From c92104e62a90377b8702e594db1bbbb5f6a5b544 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Tue, 16 Jul 2024 05:01:59 -0700 Subject: [PATCH] feat(astro): Introduce `` for custom oath flows (#3719) --- .changeset/short-otters-return.md | 5 +++ .../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 + 8 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 .changeset/short-otters-return.md 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/.changeset/short-otters-return.md b/.changeset/short-otters-return.md new file mode 100644 index 0000000000..3e00c93776 --- /dev/null +++ b/.changeset/short-otters-return.md @@ -0,0 +1,5 @@ +--- +"@clerk/astro": patch +--- + +Introduce `` as an Astro and as a React component 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 0000000000..713cf3117c --- /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 fa816b7b52..f9714851fb 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 a3442ac23a..ed50b90e4b 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 0000000000..92e1e95635 --- /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 11ec81768d..f36149f9c2 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 71c2ed41da..6e17605f10 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 c68c878b43..935d3d4c7b 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>>; } }