From a9f548db12d95f3e32e796201b882fc3e75aa8a8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 15 Jul 2024 09:45:03 -0700 Subject: [PATCH 1/3] feat(astro): Add OAuth flow component for Astro and React chore(astro): Make sure Clerk is loaded before invoking functions --- .../AuthenticateWithRedirectCallback.astro | 42 +++++++++++++++++++ packages/astro/src/astro-components/index.ts | 1 + .../src/internal/create-clerk-instance.ts | 2 + .../invoke-clerk-astro-js-functions.ts | 19 +++++++++ packages/astro/src/internal/run-once.ts | 2 + .../astro/src/react/controlComponents.tsx | 19 ++++++++- packages/astro/src/types.ts | 1 + 7 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 packages/astro/src/astro-components/control/AuthenticateWithRedirectCallback.astro create mode 100644 packages/astro/src/internal/invoke-clerk-astro-js-functions.ts diff --git a/packages/astro/src/astro-components/control/AuthenticateWithRedirectCallback.astro b/packages/astro/src/astro-components/control/AuthenticateWithRedirectCallback.astro new file mode 100644 index 00000000000..713cf3117c4 --- /dev/null +++ b/packages/astro/src/astro-components/control/AuthenticateWithRedirectCallback.astro @@ -0,0 +1,42 @@ +--- +import type { HandleOAuthCallbackParams } from '@clerk/types'; + +type Props = HandleOAuthCallbackParams + +import { generateSafeId } from '@clerk/astro/internal'; + +const safeId = generateSafeId(); + +// TODO: Move this to a prop when we implement more control components. +const functionName = 'handleRedirectCallback'; +--- + +
+ + diff --git a/packages/astro/src/astro-components/index.ts b/packages/astro/src/astro-components/index.ts index fa816b7b52c..f9714851fbd 100644 --- a/packages/astro/src/astro-components/index.ts +++ b/packages/astro/src/astro-components/index.ts @@ -4,6 +4,7 @@ export { default as SignedIn } from './control/SignedIn.astro'; export { default as SignedOut } from './control/SignedOut.astro'; export { default as Protect } from './control/Protect.astro'; +export { default as AuthenticateWithRedirectCallback } from './control/AuthenticateWithRedirectCallback.astro'; /** * Unstyled Components diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index a3442ac23a5..ed50b90e4bd 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -1,6 +1,7 @@ import { waitForClerkScript } from '../internal/utils/loadClerkJSScript'; import { $clerk, $csrState } from '../stores/internal'; import type { AstroClerkIntegrationParams, AstroClerkUpdateOptions } from '../types'; +import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions'; import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; import { runOnce } from './run-once'; @@ -35,6 +36,7 @@ async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams $csrState.setKey('isLoaded', true); mountAllClerkAstroJSComponents(); + invokeClerkAstroJSFunctions(); clerkJSInstance.addListener(payload => { $csrState.setKey('client', payload.client); diff --git a/packages/astro/src/internal/invoke-clerk-astro-js-functions.ts b/packages/astro/src/internal/invoke-clerk-astro-js-functions.ts new file mode 100644 index 00000000000..92e1e95635f --- /dev/null +++ b/packages/astro/src/internal/invoke-clerk-astro-js-functions.ts @@ -0,0 +1,19 @@ +import { $clerk } from '../stores/internal'; + +/** + * Loop through any Astro component that has requested to invoke a function and invoke it with its respective props. + */ +const invokeClerkAstroJSFunctions = () => { + const functionNames = ['handleRedirectCallback'] as const; + + functionNames.forEach(fnName => { + const elementsOfCategory = document.querySelectorAll(`[data-clerk-function-id^="clerk-${fnName}"]`); + elementsOfCategory.forEach(el => { + const id = el.getAttribute('data-clerk-function-id'); + const props = window.__astro_clerk_function_props?.get(fnName)?.get(id!) ?? {}; + void $clerk.get()?.[fnName]?.(props); + }); + }); +}; + +export { invokeClerkAstroJSFunctions }; diff --git a/packages/astro/src/internal/run-once.ts b/packages/astro/src/internal/run-once.ts index 11ec81768d3..f36149f9c2f 100644 --- a/packages/astro/src/internal/run-once.ts +++ b/packages/astro/src/internal/run-once.ts @@ -1,5 +1,6 @@ import type { Clerk } from '@clerk/clerk-js'; +import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions'; import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; import type { CreateClerkInstanceInternalFn } from './types'; @@ -19,6 +20,7 @@ const runOnce = (onFirst: CreateClerkInstanceInternalFn) => { if (clerkJSInstance.loaded) { mountAllClerkAstroJSComponents(); + invokeClerkAstroJSFunctions(); } return res(clerkJSInstance.loaded); }); diff --git a/packages/astro/src/react/controlComponents.tsx b/packages/astro/src/react/controlComponents.tsx index 71c2ed41dad..6e17605f109 100644 --- a/packages/astro/src/react/controlComponents.tsx +++ b/packages/astro/src/react/controlComponents.tsx @@ -1,8 +1,11 @@ -import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types'; +import type { CheckAuthorizationWithCustomPermissions, HandleOAuthCallbackParams } from '@clerk/types'; import type { PropsWithChildren } from 'react'; +import React from 'react'; import type { ProtectComponentDefaultProps } from '../types'; import { useAuth } from './hooks'; +import type { WithClerkProp } from './utils'; +import { withClerk } from './utils'; export function SignedOut(props: PropsWithChildren) { const { userId } = useAuth(); @@ -83,3 +86,17 @@ export const Protect = ({ children, fallback, ...restAuthorizedParams }: Protect */ return authorized; }; + +/** + * Use `` to complete a custom OAuth flow. + */ +export const AuthenticateWithRedirectCallback = withClerk( + ({ clerk, ...handleRedirectCallbackParams }: WithClerkProp) => { + React.useEffect(() => { + void clerk?.handleRedirectCallback(handleRedirectCallbackParams); + }, []); + + return null; + }, + 'AuthenticateWithRedirectCallback', +); diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts index c68c878b432..935d3d4c7b6 100644 --- a/packages/astro/src/types.ts +++ b/packages/astro/src/types.ts @@ -20,6 +20,7 @@ type AstroClerkCreateInstanceParams = AstroClerkIntegrationParams & { publishabl declare global { interface Window { __astro_clerk_component_props: Map>>; + __astro_clerk_function_props: Map>>; } } From 6dbadf75b5b72e14e2c1cd483c671e2a47b241e8 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Mon, 15 Jul 2024 11:53:19 -0700 Subject: [PATCH 2/3] chore(astro): Add changeset --- .changeset/short-otters-return.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/short-otters-return.md diff --git a/.changeset/short-otters-return.md b/.changeset/short-otters-return.md new file mode 100644 index 00000000000..7c61d766228 --- /dev/null +++ b/.changeset/short-otters-return.md @@ -0,0 +1,5 @@ +--- +"@clerk/astro": patch +--- + +Add custom OAuth flow component for Astro and React From 58ad906c829aba23fb247c690bf07b099aca50a5 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Mon, 15 Jul 2024 14:37:21 -0700 Subject: [PATCH 3/3] chore(astro): Update changeset message Co-authored-by: panteliselef --- .changeset/short-otters-return.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/short-otters-return.md b/.changeset/short-otters-return.md index 7c61d766228..3e00c937766 100644 --- a/.changeset/short-otters-return.md +++ b/.changeset/short-otters-return.md @@ -2,4 +2,4 @@ "@clerk/astro": patch --- -Add custom OAuth flow component for Astro and React +Introduce `` as an Astro and as a React component