From 68d1181c46578c43f707245a1bffda8a94d0a34c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 10 Jul 2024 14:18:22 -0700 Subject: [PATCH 01/85] chore(astro): Use shared data attribute builder for hotloading --- .../src/server/build-clerk-hotload-script.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/server/build-clerk-hotload-script.ts b/packages/astro/src/server/build-clerk-hotload-script.ts index d135dd3bcb2..09bc8307cc2 100644 --- a/packages/astro/src/server/build-clerk-hotload-script.ts +++ b/packages/astro/src/server/build-clerk-hotload-script.ts @@ -1,4 +1,4 @@ -import { clerkJsScriptUrl } from '@clerk/shared/loadClerkJsScript'; +import { buildClerkJsScriptAttributes, clerkJsScriptUrl } from '@clerk/shared/loadClerkJsScript'; import type { APIContext } from 'astro'; import { getSafeEnv } from './get-safe-env'; @@ -7,6 +7,7 @@ function buildClerkHotloadScript(locals: APIContext['locals']) { const publishableKey = getSafeEnv(locals).pk!; const proxyUrl = getSafeEnv(locals).proxyUrl!; const domain = getSafeEnv(locals).domain!; + const scriptSrc = clerkJsScriptUrl({ clerkJSUrl: getSafeEnv(locals).clerkJsUrl, clerkJSVariant: getSafeEnv(locals).clerkJsVariant, @@ -15,14 +16,22 @@ function buildClerkHotloadScript(locals: APIContext['locals']) { proxyUrl, publishableKey, }); + + const attributes = buildClerkJsScriptAttributes({ + publishableKey, + proxyUrl, + domain, + }); + const attributesString = Object.entries(attributes) + .map(([key, value]) => `${key}="${value}"`) + .join(' '); + return ` \n`; } From 832d2dd940c55006faf065c24eac7b39ff82096a Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 10 Jul 2024 15:40:30 -0700 Subject: [PATCH 02/85] chore(astro): Use shared clerk-js hotload script --- packages/astro/src/server/clerk-middleware.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/astro/src/server/clerk-middleware.ts b/packages/astro/src/server/clerk-middleware.ts index 0dc2b8ea5f5..30ab5142505 100644 --- a/packages/astro/src/server/clerk-middleware.ts +++ b/packages/astro/src/server/clerk-middleware.ts @@ -8,7 +8,6 @@ import type { APIContext } from 'astro'; // @ts-ignore import { authAsyncStorage } from '#async-local-storage'; -import { buildClerkHotloadScript } from './build-clerk-hotload-script'; import { clerkClient } from './clerk-client'; import { createCurrentUser } from './current-user'; import { getAuth } from './get-auth'; @@ -287,7 +286,6 @@ async function decorateRequest( const clerkSafeEnvVariables = encoder.encode( `\n`, ); - const hotloadScript = encoder.encode(buildClerkHotloadScript(locals)); const stream = res.body!.pipeThrough( new TransformStream({ From 982d455ef231efecef65965d9e34446c416e20bd Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 10 Jul 2024 16:09:17 -0700 Subject: [PATCH 03/85] chore(astro): Clean up type ignores --- packages/astro/src/client/bundled.ts | 52 +++++++++++++++++++ .../internal/merge-env-vars-with-params.ts | 2 + 2 files changed, 54 insertions(+) create mode 100644 packages/astro/src/client/bundled.ts diff --git a/packages/astro/src/client/bundled.ts b/packages/astro/src/client/bundled.ts new file mode 100644 index 00000000000..151505bac0f --- /dev/null +++ b/packages/astro/src/client/bundled.ts @@ -0,0 +1,52 @@ +import { Clerk } from '@clerk/clerk-js'; + +import { $clerk, $csrState } from '../stores/internal'; +import type { AstroClerkCreateInstanceParams, AstroClerkUpdateOptions } from '../types'; +import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; +import { runOnce } from './run-once'; +import type { CreateClerkInstanceInternalFn } from './types'; + +let initOptions: AstroClerkCreateInstanceParams | undefined; + +/** + * Prevents firing clerk.load multiple times + */ +export const createClerkInstance: CreateClerkInstanceInternalFn = runOnce(createClerkInstanceInternal); + +export function createClerkInstanceInternal(options?: AstroClerkCreateInstanceParams) { + let clerkJSInstance = window.Clerk as unknown as Clerk; + if (!clerkJSInstance) { + clerkJSInstance = new Clerk(options!.publishableKey); + $clerk.set(clerkJSInstance); + window.Clerk = clerkJSInstance; + } + + initOptions = options; + return clerkJSInstance + .load(options) + .then(() => { + $csrState.setKey('isLoaded', true); + + mountAllClerkAstroJSComponents(); + + clerkJSInstance.addListener(payload => { + $csrState.setKey('client', payload.client); + $csrState.setKey('user', payload.user); + $csrState.setKey('session', payload.session); + $csrState.setKey('organization', payload.organization); + }); + }) + .catch(() => {}); +} + +export function updateClerkOptions(options: AstroClerkUpdateOptions) { + const clerk = $clerk.get(); + if (!clerk) { + throw new Error('Missing clerk instance'); + } + //@ts-ignore + clerk.__unstable__updateProps({ + options: { ...initOptions, ...options }, + appearance: { ...initOptions?.appearance, ...options.appearance }, + }); +} diff --git a/packages/astro/src/internal/merge-env-vars-with-params.ts b/packages/astro/src/internal/merge-env-vars-with-params.ts index c5498c1e0da..2160191b82b 100644 --- a/packages/astro/src/internal/merge-env-vars-with-params.ts +++ b/packages/astro/src/internal/merge-env-vars-with-params.ts @@ -17,6 +17,8 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish ...rest } = params || {}; + // We have an eslint config that requires us to declare env variables in the turbo.json file. + // We're skipping/disabling it below as we use it only for the Astro integration. return { signInUrl: paramSignIn || import.meta.env.PUBLIC_CLERK_SIGN_IN_URL, signUpUrl: paramSignUp || import.meta.env.PUBLIC_CLERK_SIGN_UP_URL, From 22e7ceb53d42320caed4e871b7d31cf17bac31a3 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 30 Jul 2024 10:30:31 -0700 Subject: [PATCH 04/85] chore(astro): Fix merge conflicts chore: Remove bundled file chore(astro): Add back missing declarations --- packages/astro/src/client/bundled.ts | 52 ------------------- .../internal/merge-env-vars-with-params.ts | 2 - .../src/internal/utils/loadClerkJsScript.ts | 17 ++++++ .../src/internal/utils/versionSelector.ts | 9 ++++ .../src/server/build-clerk-hotload-script.ts | 1 - packages/astro/src/server/clerk-middleware.ts | 2 + 6 files changed, 28 insertions(+), 55 deletions(-) delete mode 100644 packages/astro/src/client/bundled.ts create mode 100644 packages/astro/src/internal/utils/loadClerkJsScript.ts create mode 100644 packages/astro/src/internal/utils/versionSelector.ts diff --git a/packages/astro/src/client/bundled.ts b/packages/astro/src/client/bundled.ts deleted file mode 100644 index 151505bac0f..00000000000 --- a/packages/astro/src/client/bundled.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Clerk } from '@clerk/clerk-js'; - -import { $clerk, $csrState } from '../stores/internal'; -import type { AstroClerkCreateInstanceParams, AstroClerkUpdateOptions } from '../types'; -import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; -import { runOnce } from './run-once'; -import type { CreateClerkInstanceInternalFn } from './types'; - -let initOptions: AstroClerkCreateInstanceParams | undefined; - -/** - * Prevents firing clerk.load multiple times - */ -export const createClerkInstance: CreateClerkInstanceInternalFn = runOnce(createClerkInstanceInternal); - -export function createClerkInstanceInternal(options?: AstroClerkCreateInstanceParams) { - let clerkJSInstance = window.Clerk as unknown as Clerk; - if (!clerkJSInstance) { - clerkJSInstance = new Clerk(options!.publishableKey); - $clerk.set(clerkJSInstance); - window.Clerk = clerkJSInstance; - } - - initOptions = options; - return clerkJSInstance - .load(options) - .then(() => { - $csrState.setKey('isLoaded', true); - - mountAllClerkAstroJSComponents(); - - clerkJSInstance.addListener(payload => { - $csrState.setKey('client', payload.client); - $csrState.setKey('user', payload.user); - $csrState.setKey('session', payload.session); - $csrState.setKey('organization', payload.organization); - }); - }) - .catch(() => {}); -} - -export function updateClerkOptions(options: AstroClerkUpdateOptions) { - const clerk = $clerk.get(); - if (!clerk) { - throw new Error('Missing clerk instance'); - } - //@ts-ignore - clerk.__unstable__updateProps({ - options: { ...initOptions, ...options }, - appearance: { ...initOptions?.appearance, ...options.appearance }, - }); -} diff --git a/packages/astro/src/internal/merge-env-vars-with-params.ts b/packages/astro/src/internal/merge-env-vars-with-params.ts index 2160191b82b..c5498c1e0da 100644 --- a/packages/astro/src/internal/merge-env-vars-with-params.ts +++ b/packages/astro/src/internal/merge-env-vars-with-params.ts @@ -17,8 +17,6 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish ...rest } = params || {}; - // We have an eslint config that requires us to declare env variables in the turbo.json file. - // We're skipping/disabling it below as we use it only for the Astro integration. return { signInUrl: paramSignIn || import.meta.env.PUBLIC_CLERK_SIGN_IN_URL, signUpUrl: paramSignUp || import.meta.env.PUBLIC_CLERK_SIGN_UP_URL, diff --git a/packages/astro/src/internal/utils/loadClerkJsScript.ts b/packages/astro/src/internal/utils/loadClerkJsScript.ts new file mode 100644 index 00000000000..6d250441339 --- /dev/null +++ b/packages/astro/src/internal/utils/loadClerkJsScript.ts @@ -0,0 +1,17 @@ +const FAILED_TO_FIND_CLERK_SCRIPT = 'Clerk: Failed find clerk-js script'; + +// TODO-SHARED: Something similar exists inside clerk-react +export const waitForClerkScript = () => { + return new Promise((resolve, reject) => { + const script = document.querySelector('script[data-clerk-script]'); + + if (!script) { + return reject(FAILED_TO_FIND_CLERK_SCRIPT); + } + + script.addEventListener('load', () => { + script.remove(); + resolve(script); + }); + }); +}; diff --git a/packages/astro/src/internal/utils/versionSelector.ts b/packages/astro/src/internal/utils/versionSelector.ts new file mode 100644 index 00000000000..12b8d4c2fdd --- /dev/null +++ b/packages/astro/src/internal/utils/versionSelector.ts @@ -0,0 +1,9 @@ +const HARDCODED_LATEST_CLERK_JS_VERSION = '5'; + +export const versionSelector = (clerkJSVersion: string | undefined): string => { + if (clerkJSVersion) { + return clerkJSVersion; + } + + return HARDCODED_LATEST_CLERK_JS_VERSION; +}; diff --git a/packages/astro/src/server/build-clerk-hotload-script.ts b/packages/astro/src/server/build-clerk-hotload-script.ts index 09bc8307cc2..12ee38c0625 100644 --- a/packages/astro/src/server/build-clerk-hotload-script.ts +++ b/packages/astro/src/server/build-clerk-hotload-script.ts @@ -7,7 +7,6 @@ function buildClerkHotloadScript(locals: APIContext['locals']) { const publishableKey = getSafeEnv(locals).pk!; const proxyUrl = getSafeEnv(locals).proxyUrl!; const domain = getSafeEnv(locals).domain!; - const scriptSrc = clerkJsScriptUrl({ clerkJSUrl: getSafeEnv(locals).clerkJsUrl, clerkJSVariant: getSafeEnv(locals).clerkJsVariant, diff --git a/packages/astro/src/server/clerk-middleware.ts b/packages/astro/src/server/clerk-middleware.ts index 30ab5142505..0dc2b8ea5f5 100644 --- a/packages/astro/src/server/clerk-middleware.ts +++ b/packages/astro/src/server/clerk-middleware.ts @@ -8,6 +8,7 @@ import type { APIContext } from 'astro'; // @ts-ignore import { authAsyncStorage } from '#async-local-storage'; +import { buildClerkHotloadScript } from './build-clerk-hotload-script'; import { clerkClient } from './clerk-client'; import { createCurrentUser } from './current-user'; import { getAuth } from './get-auth'; @@ -286,6 +287,7 @@ async function decorateRequest( const clerkSafeEnvVariables = encoder.encode( `\n`, ); + const hotloadScript = encoder.encode(buildClerkHotloadScript(locals)); const stream = res.body!.pipeThrough( new TransformStream({ From 98456b939ddd358c0a97e68e8ba91710b910deba Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 30 Jul 2024 10:50:01 -0700 Subject: [PATCH 05/85] chore(astro): Fix incorrect file name --- .../internal/utils/{loadClerkJsScript.ts => loadClerkJSScript.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/astro/src/internal/utils/{loadClerkJsScript.ts => loadClerkJSScript.ts} (100%) diff --git a/packages/astro/src/internal/utils/loadClerkJsScript.ts b/packages/astro/src/internal/utils/loadClerkJSScript.ts similarity index 100% rename from packages/astro/src/internal/utils/loadClerkJsScript.ts rename to packages/astro/src/internal/utils/loadClerkJSScript.ts From 062cb9bb65ada44a2ffb33c45a9f0f227771fce9 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 30 Jul 2024 15:33:02 -0700 Subject: [PATCH 06/85] chore(shared): Allow custom package version --- packages/shared/src/loadClerkJsScript.ts | 2 +- packages/shared/src/versionSelector.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/loadClerkJsScript.ts b/packages/shared/src/loadClerkJsScript.ts index 97647e3f0bd..d8dd57db332 100644 --- a/packages/shared/src/loadClerkJsScript.ts +++ b/packages/shared/src/loadClerkJsScript.ts @@ -102,7 +102,7 @@ const clerkJsScriptUrl = (opts: LoadClerkJsScriptOptions) => { } const variant = clerkJSVariant ? `${clerkJSVariant.replace(/\.+$/, '')}.` : ''; - const version = versionSelector(clerkJSVersion); + const version = versionSelector(clerkJSVersion, packageVersion); return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.${variant}browser.js`; }; diff --git a/packages/shared/src/versionSelector.ts b/packages/shared/src/versionSelector.ts index 7eac9d9c097..080ddcb1c55 100644 --- a/packages/shared/src/versionSelector.ts +++ b/packages/shared/src/versionSelector.ts @@ -8,7 +8,7 @@ * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided * @returns The npm tag, version or major version to use */ -export const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => { +export const versionSelector = (clerkJSVersion: string | undefined, packageVersion: string) => { if (clerkJSVersion) { return clerkJSVersion; } From ddbd13aba28fb9b89acbdff6e8b8095dfc4be823 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 30 Jul 2024 17:19:41 -0700 Subject: [PATCH 07/85] test(shared): Handle custom package versions for versionSelector --- packages/shared/src/versionSelector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/versionSelector.ts b/packages/shared/src/versionSelector.ts index 080ddcb1c55..7eac9d9c097 100644 --- a/packages/shared/src/versionSelector.ts +++ b/packages/shared/src/versionSelector.ts @@ -8,7 +8,7 @@ * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided * @returns The npm tag, version or major version to use */ -export const versionSelector = (clerkJSVersion: string | undefined, packageVersion: string) => { +export const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => { if (clerkJSVersion) { return clerkJSVersion; } From 470e945cc94b4d984b3b8b40c022d6c90bbf9bdc Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 31 Jul 2024 16:53:37 -0700 Subject: [PATCH 08/85] chore(astro): Use shared clerk-js hotload script --- packages/astro/src/internal/types.ts | 2 +- packages/shared/src/loadClerkJsScript.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/internal/types.ts b/packages/astro/src/internal/types.ts index 9128cff0501..34cf8add0f5 100644 --- a/packages/astro/src/internal/types.ts +++ b/packages/astro/src/internal/types.ts @@ -1,5 +1,5 @@ import type { AstroClerkCreateInstanceParams } from '../types'; -type CreateClerkInstanceInternalFn = (options?: AstroClerkCreateInstanceParams) => Promise; +type CreateClerkInstanceInternalFn = (options: AstroClerkCreateInstanceParams) => Promise; export type { CreateClerkInstanceInternalFn }; diff --git a/packages/shared/src/loadClerkJsScript.ts b/packages/shared/src/loadClerkJsScript.ts index d8dd57db332..9155f7889ac 100644 --- a/packages/shared/src/loadClerkJsScript.ts +++ b/packages/shared/src/loadClerkJsScript.ts @@ -102,7 +102,7 @@ const clerkJsScriptUrl = (opts: LoadClerkJsScriptOptions) => { } const variant = clerkJSVariant ? `${clerkJSVariant.replace(/\.+$/, '')}.` : ''; - const version = versionSelector(clerkJSVersion, packageVersion); + const version = versionSelector(clerkJSVersion, _packageVersion); return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.${variant}browser.js`; }; From dd0c8f43fe1cc4e469baf4a66b47f2e0a678f926 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 31 Jul 2024 16:59:23 -0700 Subject: [PATCH 09/85] chore(shared): Update internal package version property name --- packages/shared/src/loadClerkJsScript.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/loadClerkJsScript.ts b/packages/shared/src/loadClerkJsScript.ts index 9155f7889ac..97647e3f0bd 100644 --- a/packages/shared/src/loadClerkJsScript.ts +++ b/packages/shared/src/loadClerkJsScript.ts @@ -102,7 +102,7 @@ const clerkJsScriptUrl = (opts: LoadClerkJsScriptOptions) => { } const variant = clerkJSVariant ? `${clerkJSVariant.replace(/\.+$/, '')}.` : ''; - const version = versionSelector(clerkJSVersion, _packageVersion); + const version = versionSelector(clerkJSVersion); return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.${variant}browser.js`; }; From af076d391dcd20001cd066daf4538a395577b42c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 31 Jul 2024 17:07:09 -0700 Subject: [PATCH 10/85] chore(astro): Remove unused file --- packages/astro/src/internal/utils/versionSelector.ts | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 packages/astro/src/internal/utils/versionSelector.ts diff --git a/packages/astro/src/internal/utils/versionSelector.ts b/packages/astro/src/internal/utils/versionSelector.ts deleted file mode 100644 index 12b8d4c2fdd..00000000000 --- a/packages/astro/src/internal/utils/versionSelector.ts +++ /dev/null @@ -1,9 +0,0 @@ -const HARDCODED_LATEST_CLERK_JS_VERSION = '5'; - -export const versionSelector = (clerkJSVersion: string | undefined): string => { - if (clerkJSVersion) { - return clerkJSVersion; - } - - return HARDCODED_LATEST_CLERK_JS_VERSION; -}; From c78912fb1794bd34989f753f30d44db47eee3848 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 10:07:00 -0700 Subject: [PATCH 11/85] chore(shared): Make options optional in loadClerkJsScript and throw if clerk-js script attribute is undefined --- packages/astro/src/internal/types.ts | 2 +- .../src/internal/utils/loadClerkJSScript.ts | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 packages/astro/src/internal/utils/loadClerkJSScript.ts diff --git a/packages/astro/src/internal/types.ts b/packages/astro/src/internal/types.ts index 34cf8add0f5..9128cff0501 100644 --- a/packages/astro/src/internal/types.ts +++ b/packages/astro/src/internal/types.ts @@ -1,5 +1,5 @@ import type { AstroClerkCreateInstanceParams } from '../types'; -type CreateClerkInstanceInternalFn = (options: AstroClerkCreateInstanceParams) => Promise; +type CreateClerkInstanceInternalFn = (options?: AstroClerkCreateInstanceParams) => Promise; export type { CreateClerkInstanceInternalFn }; diff --git a/packages/astro/src/internal/utils/loadClerkJSScript.ts b/packages/astro/src/internal/utils/loadClerkJSScript.ts deleted file mode 100644 index 6d250441339..00000000000 --- a/packages/astro/src/internal/utils/loadClerkJSScript.ts +++ /dev/null @@ -1,17 +0,0 @@ -const FAILED_TO_FIND_CLERK_SCRIPT = 'Clerk: Failed find clerk-js script'; - -// TODO-SHARED: Something similar exists inside clerk-react -export const waitForClerkScript = () => { - return new Promise((resolve, reject) => { - const script = document.querySelector('script[data-clerk-script]'); - - if (!script) { - return reject(FAILED_TO_FIND_CLERK_SCRIPT); - } - - script.addEventListener('load', () => { - script.remove(); - resolve(script); - }); - }); -}; From e0d683b1b1b798e32b7adb7b5308c0052401a9c0 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 08:59:20 -0700 Subject: [PATCH 12/85] chore(shared,astro,react,nextjs): Use built-in error thrower when ClerkJS script loading fails --- packages/shared/src/__tests__/loadClerkJsScript.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/shared/src/__tests__/loadClerkJsScript.test.ts b/packages/shared/src/__tests__/loadClerkJsScript.test.ts index 186298a2a9f..f8bb1707fb4 100644 --- a/packages/shared/src/__tests__/loadClerkJsScript.test.ts +++ b/packages/shared/src/__tests__/loadClerkJsScript.test.ts @@ -10,7 +10,10 @@ import { getMajorVersion } from '../versionSelector'; jest.mock('../loadScript'); setClerkJsLoadingErrorPackageName('@clerk/clerk-react'); +<<<<<<< HEAD const jsPackageMajorVersion = getMajorVersion(JS_PACKAGE_VERSION); +======= +>>>>>>> 230433523 (chore(shared,astro,react,nextjs): Use built-in error thrower when ClerkJS script loading fails) describe('loadClerkJsScript(options)', () => { const mockPublishableKey = 'pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk'; From 7a4911b7d9904c0167a1c50c5a3c384f3dbd53fa Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 09:54:19 -0700 Subject: [PATCH 13/85] test(shared): Use clerk-js major version from package.json when testing script loader --- packages/shared/src/__tests__/loadClerkJsScript.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/shared/src/__tests__/loadClerkJsScript.test.ts b/packages/shared/src/__tests__/loadClerkJsScript.test.ts index f8bb1707fb4..7405215c839 100644 --- a/packages/shared/src/__tests__/loadClerkJsScript.test.ts +++ b/packages/shared/src/__tests__/loadClerkJsScript.test.ts @@ -10,10 +10,7 @@ import { getMajorVersion } from '../versionSelector'; jest.mock('../loadScript'); setClerkJsLoadingErrorPackageName('@clerk/clerk-react'); -<<<<<<< HEAD const jsPackageMajorVersion = getMajorVersion(JS_PACKAGE_VERSION); -======= ->>>>>>> 230433523 (chore(shared,astro,react,nextjs): Use built-in error thrower when ClerkJS script loading fails) describe('loadClerkJsScript(options)', () => { const mockPublishableKey = 'pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk'; @@ -143,4 +140,4 @@ describe('buildClerkJsScriptAttributes()', () => { // @ts-ignore input loses correct type because of empty object expect(buildClerkJsScriptAttributes(input)).toEqual(expected); }); -}); +}); \ No newline at end of file From d8b1ac6de6e42601b8808fb01388c07bd70bcc53 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 06:28:40 -0700 Subject: [PATCH 14/85] chore(shared): Add nonce prop to to load script --- integration/templates/astro-static/env.d.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 integration/templates/astro-static/env.d.ts diff --git a/integration/templates/astro-static/env.d.ts b/integration/templates/astro-static/env.d.ts new file mode 100644 index 00000000000..f964fe0cffd --- /dev/null +++ b/integration/templates/astro-static/env.d.ts @@ -0,0 +1 @@ +/// From 097035c8306f47a3761ea85bdf8cca365e33b3c4 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 06:29:22 -0700 Subject: [PATCH 15/85] chore(shared): Remove extra folder --- integration/templates/astro-static/env.d.ts | 1 - 1 file changed, 1 deletion(-) delete mode 100644 integration/templates/astro-static/env.d.ts diff --git a/integration/templates/astro-static/env.d.ts b/integration/templates/astro-static/env.d.ts deleted file mode 100644 index f964fe0cffd..00000000000 --- a/integration/templates/astro-static/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// From a3a29d9497f86aab2de3b941effeb4692ccd450f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 16:07:05 -0700 Subject: [PATCH 16/85] feat(astro): Add CSR support to control components --- .../astro-components/control/Protect.astro | 21 +++-- .../astro-components/control/ProtectCSR.astro | 80 +++++++++++++++++++ .../astro-components/control/ProtectSSR.astro | 38 +++++++++ .../astro-components/control/SignedIn.astro | 12 ++- .../control/SignedInCSR.astro | 26 ++++++ .../control/SignedInSSR.astro | 5 ++ .../astro-components/control/SignedOut.astro | 12 ++- .../control/SignedOutCSR.astro | 26 ++++++ .../control/SignedOutSSR.astro | 5 ++ 9 files changed, 211 insertions(+), 14 deletions(-) create mode 100644 packages/astro/src/astro-components/control/ProtectCSR.astro create mode 100644 packages/astro/src/astro-components/control/ProtectSSR.astro create mode 100644 packages/astro/src/astro-components/control/SignedInCSR.astro create mode 100644 packages/astro/src/astro-components/control/SignedInSSR.astro create mode 100644 packages/astro/src/astro-components/control/SignedOutCSR.astro create mode 100644 packages/astro/src/astro-components/control/SignedOutSSR.astro diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index 74ba18846d1..99a72eb5afa 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -1,11 +1,14 @@ --- +import ProtectCSR from './ProtectCSR.astro'; +import ProtectSSR from './ProtectSSR.astro'; + import type { CheckAuthorizationWithCustomPermissions, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, } from '@clerk/types'; -type Props = +type ProtectProps = | { condition?: never; role: OrganizationCustomRoleKey; @@ -27,12 +30,14 @@ type Props = permission?: never; }; -const { has, userId } = Astro.locals.auth(); -const isUnauthorized = - !userId || - (typeof Astro.props.condition === "function" && - !Astro.props.condition(has)) || - ((Astro.props.role || Astro.props.permission) && !has(Astro.props)); +type Props = ProtectProps & { + client?: boolean +} + +const { role, permission, condition, client = false } = Astro.props --- -{isUnauthorized ? : } +{client + ? + : +} diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro new file mode 100644 index 00000000000..a37ca77dd37 --- /dev/null +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -0,0 +1,80 @@ +--- +import type { + OrganizationCustomPermissionKey, + OrganizationCustomRoleKey, +} from '@clerk/types'; + +type Props = + | { + role: OrganizationCustomRoleKey; + permission?: never; + } + | { + role?: never; + permission: OrganizationCustomPermissionKey; + } + | { + role?: never; + permission?: never; + } + | { + role?: never; + permission?: never; + }; + +const { role, permission } = Astro.props +--- + + + + + + diff --git a/packages/astro/src/astro-components/control/ProtectSSR.astro b/packages/astro/src/astro-components/control/ProtectSSR.astro new file mode 100644 index 00000000000..74ba18846d1 --- /dev/null +++ b/packages/astro/src/astro-components/control/ProtectSSR.astro @@ -0,0 +1,38 @@ +--- +import type { + CheckAuthorizationWithCustomPermissions, + OrganizationCustomPermissionKey, + OrganizationCustomRoleKey, +} from '@clerk/types'; + +type Props = + | { + condition?: never; + role: OrganizationCustomRoleKey; + permission?: never; + } + | { + condition?: never; + role?: never; + permission: OrganizationCustomPermissionKey; + } + | { + condition: (has: CheckAuthorizationWithCustomPermissions) => boolean; + role?: never; + permission?: never; + } + | { + condition?: never; + role?: never; + permission?: never; + }; + +const { has, userId } = Astro.locals.auth(); +const isUnauthorized = + !userId || + (typeof Astro.props.condition === "function" && + !Astro.props.condition(has)) || + ((Astro.props.role || Astro.props.permission) && !has(Astro.props)); +--- + +{isUnauthorized ? : } diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index c1657391909..4b8659ade72 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,6 +1,12 @@ --- -const { userId } = Astro.locals.auth() ---- +import SignedInSSR from './SignedInSSR.astro'; +import SignedInCSR from './SignedInCSR.astro'; + +type Props = { + client?: boolean; +} +const { client = false } = Astro.props; +--- -{ userId ? : null } \ No newline at end of file +{client ? : } diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro new file mode 100644 index 00000000000..fbd3c97d7f1 --- /dev/null +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -0,0 +1,26 @@ + + + + + diff --git a/packages/astro/src/astro-components/control/SignedInSSR.astro b/packages/astro/src/astro-components/control/SignedInSSR.astro new file mode 100644 index 00000000000..4253bcfe875 --- /dev/null +++ b/packages/astro/src/astro-components/control/SignedInSSR.astro @@ -0,0 +1,5 @@ +--- +const { userId } = Astro.locals.auth() +--- + +{ userId ? : null } diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index bbcf2c8cc5c..1faa00edac7 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -1,6 +1,12 @@ --- -const { userId } = Astro.locals.auth() ---- +import SignedOutSSR from './SignedOutSSR.astro'; +import SignedOutCSR from './SignedOutCSR.astro'; + +type Props = { + client?: boolean; +} +const { client = false } = Astro.props; +--- -{ !userId ? : null } \ No newline at end of file +{client ? : } diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro new file mode 100644 index 00000000000..f7b4fca5eef --- /dev/null +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -0,0 +1,26 @@ + + + + + diff --git a/packages/astro/src/astro-components/control/SignedOutSSR.astro b/packages/astro/src/astro-components/control/SignedOutSSR.astro new file mode 100644 index 00000000000..8b1b8154ad9 --- /dev/null +++ b/packages/astro/src/astro-components/control/SignedOutSSR.astro @@ -0,0 +1,5 @@ +--- +const { userId } = Astro.locals.auth() +--- + +{ !userId ? : null } From b489b410d3eb167679934f0ae2ec125a43646e9b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 16:40:57 -0700 Subject: [PATCH 17/85] chore(astro): Use dynamic components --- .../astro-components/control/Protect.astro | 24 +++++++++++-------- .../astro-components/control/ProtectCSR.astro | 2 +- .../astro-components/control/SignedIn.astro | 12 ++++++---- .../astro-components/control/SignedOut.astro | 6 +++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index 99a72eb5afa..d52aeada9f4 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -1,12 +1,12 @@ --- -import ProtectCSR from './ProtectCSR.astro'; -import ProtectSSR from './ProtectSSR.astro'; +import ProtectCSR from "./ProtectCSR.astro"; +import ProtectSSR from "./ProtectSSR.astro"; import type { CheckAuthorizationWithCustomPermissions, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, -} from '@clerk/types'; +} from "@clerk/types"; type ProtectProps = | { @@ -31,13 +31,17 @@ type ProtectProps = }; type Props = ProtectProps & { - client?: boolean -} + client?: boolean; +}; -const { role, permission, condition, client = false } = Astro.props +const { role, permission, condition, client = false } = Astro.props; + +const ProtectComponent = client ? ProtectCSR : ProtectSSR; --- -{client - ? - : -} + + + + + + diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index a37ca77dd37..4e65e353d08 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -25,7 +25,7 @@ type Props = const { role, permission } = Astro.props --- - + diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index 4b8659ade72..222c0dc266a 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,12 +1,14 @@ --- -import SignedInSSR from './SignedInSSR.astro'; -import SignedInCSR from './SignedInCSR.astro'; +import SignedInSSR from "./SignedInSSR.astro"; +import SignedInCSR from "./SignedInCSR.astro"; type Props = { client?: boolean; -} +}; -const { client = false } = Astro.props; +const SignedInComponent = Astro.props.client ? SignedInCSR : SignedInSSR; --- -{client ? : } + + + diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index 1faa00edac7..2b497168abc 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -6,7 +6,9 @@ type Props = { client?: boolean; } -const { client = false } = Astro.props; +const SignedOutComponent = Astro.props.client ? SignedOutCSR : SignedOutSSR; --- -{client ? : } + + + From 5cdebf7b6a5a4ec6e01251a9a49567bd284011e5 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 16:41:44 -0700 Subject: [PATCH 18/85] chore(astro): Type fix --- packages/astro/src/astro-components/control/Protect.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index d52aeada9f4..ded40dcf343 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -34,12 +34,12 @@ type Props = ProtectProps & { client?: boolean; }; -const { role, permission, condition, client = false } = Astro.props; +const { client = false, ...rest } = Astro.props; const ProtectComponent = client ? ProtectCSR : ProtectSSR; --- - + From bc64acd34c2a154b65f911a681fa6c54f97aab57 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 16:44:51 -0700 Subject: [PATCH 19/85] chore(astro): formatting update --- .../astro-components/control/ProtectCSR.astro | 42 +++++++++++-------- .../astro-components/control/ProtectSSR.astro | 2 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 4e65e353d08..1672130d048 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -2,7 +2,7 @@ import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey, -} from '@clerk/types'; +} from "@clerk/types"; type Props = | { @@ -13,25 +13,25 @@ type Props = role?: never; permission: OrganizationCustomPermissionKey; } - | { - role?: never; - permission?: never; - } | { role?: never; permission?: never; }; -const { role, permission } = Astro.props +const { role, permission } = Astro.props; --- - + diff --git a/packages/astro/src/astro-components/control/ProtectSSR.astro b/packages/astro/src/astro-components/control/ProtectSSR.astro index 74ba18846d1..d4b0ebb0c46 100644 --- a/packages/astro/src/astro-components/control/ProtectSSR.astro +++ b/packages/astro/src/astro-components/control/ProtectSSR.astro @@ -3,7 +3,7 @@ import type { CheckAuthorizationWithCustomPermissions, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, -} from '@clerk/types'; +} from "@clerk/types"; type Props = | { From 6890da28537d09cb7d3909576476d971009d334f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Aug 2024 16:54:24 -0700 Subject: [PATCH 20/85] chore(astro): Simplify Protect slots --- packages/astro/src/astro-components/control/Protect.astro | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index ded40dcf343..fad72a493cd 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -40,8 +40,6 @@ const ProtectComponent = client ? ProtectCSR : ProtectSSR; --- - - - - + + From ad714b7bf131abe1196aae4cdc8a89b565ad5e3d Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Tue, 6 Aug 2024 12:25:51 -0700 Subject: [PATCH 21/85] chore(astro): Add initial changeset --- .changeset/proud-horses-smell.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/proud-horses-smell.md diff --git a/.changeset/proud-horses-smell.md b/.changeset/proud-horses-smell.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/proud-horses-smell.md @@ -0,0 +1,2 @@ +--- +--- From 19af4a7c7a3e0f82886e03055ff571779ea10283 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 6 Aug 2024 13:47:21 -0700 Subject: [PATCH 22/85] test(astro): Add initial CSR e2e test --- integration/presets/astro.ts | 11 +++++ integration/presets/longRunningApps.ts | 1 + .../templates/astro-static/astro.config.mjs | 11 +++++ .../templates/astro-static/package.json | 22 +++++++++ .../templates/astro-static/public/favicon.svg | 9 ++++ .../astro-static/src/layouts/Layout.astro | 24 ++++++++++ .../astro-static/src/pages/index.astro | 15 ++++++ .../astro-static/src/pages/protected.astro | 10 ++++ integration/tests/astro/static.test.ts | 47 +++++++++++++++++++ .../control/SignedInCSR.astro | 4 ++ .../control/SignedOutCSR.astro | 4 ++ 11 files changed, 158 insertions(+) create mode 100644 integration/templates/astro-static/astro.config.mjs create mode 100644 integration/templates/astro-static/package.json create mode 100644 integration/templates/astro-static/public/favicon.svg create mode 100644 integration/templates/astro-static/src/layouts/Layout.astro create mode 100644 integration/templates/astro-static/src/pages/index.astro create mode 100644 integration/templates/astro-static/src/pages/protected.astro create mode 100644 integration/tests/astro/static.test.ts diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index f9a437e864c..95f3dfa115d 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -17,6 +17,17 @@ const astroNode = applicationConfig() .addDependency('@clerk/types', clerkTypesLocal) .addDependency('@clerk/localizations', clerkLocalizationLocal); +const astroStatic = applicationConfig() + .setName('astro-static') + .useTemplate(templates['astro-static']) + .setEnvFormatter('public', key => `PUBLIC_${key}`) + .addScript('setup', 'npm i') + .addScript('dev', 'npm run dev') + .addScript('build', 'npm run build') + .addScript('serve', 'npm run preview') + .addDependency('@clerk/astro', clerkAstroLocal); + export const astro = { node: astroNode, + static: astroStatic, }; diff --git a/integration/presets/longRunningApps.ts b/integration/presets/longRunningApps.ts index 77f8a27b428..4b08e8e6317 100644 --- a/integration/presets/longRunningApps.ts +++ b/integration/presets/longRunningApps.ts @@ -25,6 +25,7 @@ export const createLongRunningApps = () => { { id: 'quickstart.next.appRouter', config: next.appRouterQuickstart, env: envs.withEmailCodesQuickstart }, { id: 'elements.next.appRouter', config: elements.nextAppRouter, env: envs.withEmailCodes }, { id: 'astro.node.withCustomRoles', config: astro.node, env: envs.withCustomRoles }, + { id: 'astro.static.withCustomRoles', config: astro.static, env: envs.withCustomRoles }, { id: 'expo.expo-web', config: expo.expoWeb, env: envs.withEmailCodes }, ] as const; diff --git a/integration/templates/astro-static/astro.config.mjs b/integration/templates/astro-static/astro.config.mjs new file mode 100644 index 00000000000..edb485f482e --- /dev/null +++ b/integration/templates/astro-static/astro.config.mjs @@ -0,0 +1,11 @@ +import { defineConfig } from 'astro/config'; +import clerk from '@clerk/astro'; +import react from '@astrojs/react'; + +export default defineConfig({ + output: 'static', + integrations: [clerk(), react()], + server: { + port: Number(process.env.PORT), + }, +}); diff --git a/integration/templates/astro-static/package.json b/integration/templates/astro-static/package.json new file mode 100644 index 00000000000..2a82d5ff254 --- /dev/null +++ b/integration/templates/astro-static/package.json @@ -0,0 +1,22 @@ +{ + "name": "astro-clerk-static-playground", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev --port $PORT", + "build": "astro check && astro build", + "preview": "astro preview --port $PORT", + "astro": "astro" + }, + "dependencies": { + "@astrojs/check": "^0.7.0", + "@astrojs/react": "^3.6.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "astro": "^4.11.5", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "typescript": "^5.5.3" + } +} diff --git a/integration/templates/astro-static/public/favicon.svg b/integration/templates/astro-static/public/favicon.svg new file mode 100644 index 00000000000..f157bd1c5e2 --- /dev/null +++ b/integration/templates/astro-static/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/integration/templates/astro-static/src/layouts/Layout.astro b/integration/templates/astro-static/src/layouts/Layout.astro new file mode 100644 index 00000000000..b5c6c9717ba --- /dev/null +++ b/integration/templates/astro-static/src/layouts/Layout.astro @@ -0,0 +1,24 @@ +--- +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + + + {title} + + +
+ +
+ + diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-static/src/pages/index.astro new file mode 100644 index 00000000000..41a41c66b6a --- /dev/null +++ b/integration/templates/astro-static/src/pages/index.astro @@ -0,0 +1,15 @@ +--- +import { UserButton, SignInButton, SignedIn, SignedOut } from "@clerk/astro/components"; +import Layout from "../layouts/Layout.astro"; +--- + + +
+ + + + + + +
+
diff --git a/integration/templates/astro-static/src/pages/protected.astro b/integration/templates/astro-static/src/pages/protected.astro new file mode 100644 index 00000000000..e73683e590e --- /dev/null +++ b/integration/templates/astro-static/src/pages/protected.astro @@ -0,0 +1,10 @@ +--- +import { Protect } from "@clerk/astro/components"; +import Layout from "../layouts/Layout.astro"; +--- + + +
+ Protected +
+
diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts new file mode 100644 index 00000000000..716fbaa2fc7 --- /dev/null +++ b/integration/tests/astro/static.test.ts @@ -0,0 +1,47 @@ +import { expect, test } from '@playwright/test'; + +import type { FakeOrganization, FakeUser } from '../../testUtils'; +import { createTestUtils, testAgainstRunningApps } from '../../testUtils'; + +testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( + 'basic flows for @astro static output', + ({ app }) => { + test.describe.configure({ mode: 'serial' }); + + let fakeAdmin: FakeUser; + let fakeOrganization: FakeOrganization; + let fakeAdmin2: FakeUser; + let fakeOrganization2: FakeOrganization; + + test.beforeAll(async () => { + const m = createTestUtils({ app }); + fakeAdmin = m.services.users.createFakeUser(); + const admin = await m.services.users.createBapiUser(fakeAdmin); + fakeOrganization = await m.services.users.createFakeOrganization(admin.id); + + fakeAdmin2 = m.services.users.createFakeUser(); + const admin2 = await m.services.users.createBapiUser(fakeAdmin2); + fakeOrganization2 = await m.services.users.createFakeOrganization(admin2.id); + }); + + test.afterAll(async () => { + await fakeOrganization.delete(); + await fakeAdmin.deleteIfExists(); + + await fakeOrganization2.delete(); + await fakeAdmin2.deleteIfExists(); + await app.teardown(); + }); + + test('Clerk client loads on first visit and Sign In button renders', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + await u.page.goToAppHome(); + + await u.page.waitForClerkJsLoaded(); + + await u.po.expect.toBeSignedOut(); + + await expect(u.page.getByRole('link', { name: /Login/i })).toBeVisible(); + }); + }, +); diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro index fbd3c97d7f1..1a3d08666c7 100644 --- a/packages/astro/src/astro-components/control/SignedInCSR.astro +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -13,6 +13,10 @@ subscribe() { $authStore.subscribe((state) => { + if (state.userId === undefined) { + return; + } + if (state.userId) { this.style.display = 'block'; } else { diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro index f7b4fca5eef..be75709f592 100644 --- a/packages/astro/src/astro-components/control/SignedOutCSR.astro +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -13,6 +13,10 @@ subscribe() { $authStore.subscribe((state) => { + if (state.userId === undefined) { + return + } + if (state.userId) { this.style.display = 'none'; } else { From 604bec8841efd3d77e63ae53cc692f75d97e1c91 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 6 Aug 2024 13:53:09 -0700 Subject: [PATCH 23/85] test(astro): Add astro-static to template map --- integration/templates/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/integration/templates/index.ts b/integration/templates/index.ts index e4c2f4ad2fe..3a122120827 100644 --- a/integration/templates/index.ts +++ b/integration/templates/index.ts @@ -12,6 +12,7 @@ export const templates = { 'remix-node': resolve(__dirname, './remix-node'), 'elements-next': resolve(__dirname, './elements-next'), 'astro-node': resolve(__dirname, './astro-node'), + 'astro-static': resolve(__dirname, './astro-static'), 'expo-web': resolve(__dirname, './expo-web'), } as const; From e82f4a7932a1eb25fc2a6cbeb31ad17d5ab630bd Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 6 Aug 2024 14:18:44 -0700 Subject: [PATCH 24/85] chore(astrp): Use hidden attribute for CSR component toggling --- .../astro/src/astro-components/control/SignedInCSR.astro | 6 +++--- .../astro/src/astro-components/control/SignedOutCSR.astro | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro index 1a3d08666c7..89b30932665 100644 --- a/packages/astro/src/astro-components/control/SignedInCSR.astro +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -1,4 +1,4 @@ - + @@ -18,9 +18,9 @@ } if (state.userId) { - this.style.display = 'block'; + this.removeAttribute('hidden'); } else { - this.style.display = 'none'; + this.setAttribute('hidden', ''); } }); } diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro index be75709f592..85330b8a29d 100644 --- a/packages/astro/src/astro-components/control/SignedOutCSR.astro +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -1,4 +1,4 @@ - + @@ -18,9 +18,9 @@ } if (state.userId) { - this.style.display = 'none'; + this.setAttribute('hidden', ''); } else { - this.style.display = 'block'; + this.removeAttribute('hidden'); } }); } From 63e2b2453695c81c6ee51c096fd71497883368aa Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 6 Aug 2024 14:51:52 -0700 Subject: [PATCH 25/85] test(astro): Clean up --- integration/tests/astro/static.test.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 716fbaa2fc7..466a97a6570 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -10,26 +10,17 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( let fakeAdmin: FakeUser; let fakeOrganization: FakeOrganization; - let fakeAdmin2: FakeUser; - let fakeOrganization2: FakeOrganization; test.beforeAll(async () => { const m = createTestUtils({ app }); fakeAdmin = m.services.users.createFakeUser(); const admin = await m.services.users.createBapiUser(fakeAdmin); fakeOrganization = await m.services.users.createFakeOrganization(admin.id); - - fakeAdmin2 = m.services.users.createFakeUser(); - const admin2 = await m.services.users.createBapiUser(fakeAdmin2); - fakeOrganization2 = await m.services.users.createFakeOrganization(admin2.id); }); test.afterAll(async () => { await fakeOrganization.delete(); await fakeAdmin.deleteIfExists(); - - await fakeOrganization2.delete(); - await fakeAdmin2.deleteIfExists(); await app.teardown(); }); From 6f71f034a3ef8f6d51b6b50506d189907990d299 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 07:26:41 -0700 Subject: [PATCH 26/85] test(astro): More clean ups --- integration/templates/astro-static/.gitignore | 24 +++++++++++++++++++ .../astro-static/src/pages/index.astro | 14 +++++------ .../templates/astro-static/tsconfig.json | 7 ++++++ integration/tests/astro/static.test.ts | 3 ++- 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 integration/templates/astro-static/.gitignore create mode 100644 integration/templates/astro-static/tsconfig.json diff --git a/integration/templates/astro-static/.gitignore b/integration/templates/astro-static/.gitignore new file mode 100644 index 00000000000..016b59ea143 --- /dev/null +++ b/integration/templates/astro-static/.gitignore @@ -0,0 +1,24 @@ +# build output +dist/ + +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +.idea/ diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-static/src/pages/index.astro index 41a41c66b6a..20b1f81b3e3 100644 --- a/integration/templates/astro-static/src/pages/index.astro +++ b/integration/templates/astro-static/src/pages/index.astro @@ -4,12 +4,10 @@ import Layout from "../layouts/Layout.astro"; --- -
- - - - - - -
+ + + + + +
diff --git a/integration/templates/astro-static/tsconfig.json b/integration/templates/astro-static/tsconfig.json new file mode 100644 index 00000000000..b7243b92ccf --- /dev/null +++ b/integration/templates/astro-static/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react" + } +} diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 466a97a6570..cd1a1ce6fc4 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -31,8 +31,9 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await u.page.waitForClerkJsLoaded(); await u.po.expect.toBeSignedOut(); + console.log('contents', await page.content()); - await expect(u.page.getByRole('link', { name: /Login/i })).toBeVisible(); + await expect(u.page.getByRole('button', { name: /Sign in/i })).toBeVisible(); }); }, ); From 03a1e73a48ff865e97f416a2aa8713975be075ab Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 17:12:50 -0700 Subject: [PATCH 27/85] chore(astro): Add vite plugin for dynamic control components --- .../astro-components/control/Protect.astro | 17 ++++++-------- .../astro-components/control/SignedIn.astro | 8 +++---- .../astro-components/control/SignedOut.astro | 8 +++---- .../src/integration/create-integration.ts | 10 ++------ .../src/internal/vite-plugin-astro-config.ts | 23 +++++++++++++++++++ 5 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 packages/astro/src/internal/vite-plugin-astro-config.ts diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index fad72a493cd..74c6e22a49f 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -8,7 +8,10 @@ import type { OrganizationCustomRoleKey, } from "@clerk/types"; -type ProtectProps = +// @ts-expect-error: Fix types later +import config from "virtual:astro/config"; + +type Props = | { condition?: never; role: OrganizationCustomRoleKey; @@ -30,16 +33,10 @@ type ProtectProps = permission?: never; }; -type Props = ProtectProps & { - client?: boolean; -}; - -const { client = false, ...rest } = Astro.props; - -const ProtectComponent = client ? ProtectCSR : ProtectSSR; +const ProtectComponent = config.output === 'static' ? ProtectCSR : ProtectSSR; --- - - + + diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index 222c0dc266a..48bcaab66ad 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,12 +1,10 @@ --- import SignedInSSR from "./SignedInSSR.astro"; import SignedInCSR from "./SignedInCSR.astro"; +// @ts-expect-error: Fix types later +import config from "virtual:astro/config"; -type Props = { - client?: boolean; -}; - -const SignedInComponent = Astro.props.client ? SignedInCSR : SignedInSSR; +const SignedInComponent = config.output === 'static' ? SignedInCSR : SignedInSSR; --- diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index 2b497168abc..dd8b0aaeb80 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -1,12 +1,10 @@ --- import SignedOutSSR from './SignedOutSSR.astro'; import SignedOutCSR from './SignedOutCSR.astro'; +// @ts-expect-error: Fix types later +import config from "virtual:astro/config"; -type Props = { - client?: boolean; -} - -const SignedOutComponent = Astro.props.client ? SignedOutCSR : SignedOutSSR; +const SignedOutComponent = config.output === 'static' ? SignedOutCSR : SignedOutSSR; --- diff --git a/packages/astro/src/integration/create-integration.ts b/packages/astro/src/integration/create-integration.ts index 246bba537af..ac75ce6ba38 100644 --- a/packages/astro/src/integration/create-integration.ts +++ b/packages/astro/src/integration/create-integration.ts @@ -2,6 +2,7 @@ import type { ClerkOptions } from '@clerk/types'; import type { AstroIntegration } from 'astro'; import { name as packageName, version as packageVersion } from '../../package.json'; +import { vitePluginAstroConfig } from '../internal/vite-plugin-astro-config'; import type { AstroClerkIntegrationParams } from '../types'; const buildEnvVarFromOption = (valueToBeStored: unknown, envName: keyof InternalEnv) => { @@ -27,14 +28,6 @@ function createIntegration() name: '@clerk/astro/integration', hooks: { 'astro:config:setup': ({ config, injectScript, updateConfig, logger, command }) => { - if (config.output === 'static') { - logger.error(`${packageName} requires SSR to be turned on. Please update output to "server"`); - } - - if (!config.adapter) { - logger.error('Missing adapter, please update your Astro config to use one.'); - } - if (typeof clerkJSVariant !== 'undefined' && clerkJSVariant !== 'headless' && clerkJSVariant !== '') { logger.error('Invalid value for clerkJSVariant. Acceptable values are `"headless"`, `""`, and `undefined`'); } @@ -53,6 +46,7 @@ function createIntegration() // Set params as envs so backend code has access to them updateConfig({ vite: { + plugins: [vitePluginAstroConfig(config)], define: { /** * Convert the integration params to environment variable in order for it to be readable from the server diff --git a/packages/astro/src/internal/vite-plugin-astro-config.ts b/packages/astro/src/internal/vite-plugin-astro-config.ts new file mode 100644 index 00000000000..43e15b07acc --- /dev/null +++ b/packages/astro/src/internal/vite-plugin-astro-config.ts @@ -0,0 +1,23 @@ +import type { AstroConfig } from 'astro'; +import type { ViteUserConfig } from 'astro/config'; + +type ExtractPluginOption = T extends (infer U)[] ? U : never; + +export function vitePluginAstroConfig(astroConfig: AstroConfig): ExtractPluginOption> { + const virtualModuleId = 'virtual:astro/config'; + const resolvedVirtualModuleId = '\0' + virtualModuleId; + + return { + name: 'vite-plugin-astro-config', + resolveId(id) { + if (id === virtualModuleId) { + return resolvedVirtualModuleId; + } + }, + load(id) { + if (id === resolvedVirtualModuleId) { + return `export default ${JSON.stringify(astroConfig)}`; + } + } + }; +} From 8be568bc63e3a2f8aa3d9645fed016cfbabb2cc3 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 17:18:55 -0700 Subject: [PATCH 28/85] chore(astro): Use hidden attribute for toggling visibility in Protect component CSR --- .../astro/src/astro-components/control/ProtectCSR.astro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 1672130d048..8503d6fc238 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -24,7 +24,7 @@ const { role, permission } = Astro.props; @@ -76,9 +76,9 @@ const { role, permission } = Astro.props; !state.userId || ((role || permission) && !has({ role, permission })); if (isUnauthorized) { - this.style.display = "none"; + this.setAttribute('hidden', ''); } else { - this.style.display = "block"; + this.removeAttribute('hidden'); } }); } From ce1b5fb24d18156088be1c8dcbfc972d3068942c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 7 Aug 2024 21:22:39 -0700 Subject: [PATCH 29/85] test(astro): Remove client props --- integration/templates/astro-static/src/pages/index.astro | 4 ++-- integration/templates/astro-static/src/pages/protected.astro | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-static/src/pages/index.astro index 20b1f81b3e3..d795e2f802c 100644 --- a/integration/templates/astro-static/src/pages/index.astro +++ b/integration/templates/astro-static/src/pages/index.astro @@ -4,10 +4,10 @@ import Layout from "../layouts/Layout.astro"; --- - + - + diff --git a/integration/templates/astro-static/src/pages/protected.astro b/integration/templates/astro-static/src/pages/protected.astro index e73683e590e..9423a5ea696 100644 --- a/integration/templates/astro-static/src/pages/protected.astro +++ b/integration/templates/astro-static/src/pages/protected.astro @@ -5,6 +5,6 @@ import Layout from "../layouts/Layout.astro";
- Protected + Protected
From 982d0d1285172f9d38e7844c44f311efb561d123 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 09:36:53 -0700 Subject: [PATCH 30/85] chore(astro): Add type for virtual module --- packages/astro/src/env.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/astro/src/env.d.ts b/packages/astro/src/env.d.ts index 57dc7096ab1..6a4476c953d 100644 --- a/packages/astro/src/env.d.ts +++ b/packages/astro/src/env.d.ts @@ -29,3 +29,9 @@ declare namespace App { runtime: { env: InternalEnv }; } } + +declare module "virtual:astro/config" { + import type { AstroConfig } from "astro"; + const config: AstroConfig; + export default config; +} From f97124bb54fb125acaeaeabca9385f5cd97e2335 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 12:59:48 -0700 Subject: [PATCH 31/85] test(astro): Add SignedIn, SignedOut and Protect e2e tests --- .../astro-static/src/pages/index.astro | 5 +- .../astro-static/src/pages/protected.astro | 9 ++- integration/tests/astro/static.test.ts | 67 ++++++++++++++++--- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-static/src/pages/index.astro index d795e2f802c..2879de8190e 100644 --- a/integration/templates/astro-static/src/pages/index.astro +++ b/integration/templates/astro-static/src/pages/index.astro @@ -1,13 +1,14 @@ --- -import { UserButton, SignInButton, SignedIn, SignedOut } from "@clerk/astro/components"; +import { OrganizationSwitcher, UserButton, SignIn, SignedIn, SignedOut } from "@clerk/astro/components"; import Layout from "../layouts/Layout.astro"; --- - + + diff --git a/integration/templates/astro-static/src/pages/protected.astro b/integration/templates/astro-static/src/pages/protected.astro index 9423a5ea696..13665d20ca7 100644 --- a/integration/templates/astro-static/src/pages/protected.astro +++ b/integration/templates/astro-static/src/pages/protected.astro @@ -4,7 +4,10 @@ import Layout from "../layouts/Layout.astro"; --- -
- Protected -
+ + +

Not an admin

+
+

I'm an admin

+
diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index cd1a1ce6fc4..7fd4c54b246 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -10,30 +10,81 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( let fakeAdmin: FakeUser; let fakeOrganization: FakeOrganization; + let fakeAdmin2: FakeUser; + let fakeOrganization2: FakeOrganization; test.beforeAll(async () => { const m = createTestUtils({ app }); - fakeAdmin = m.services.users.createFakeUser(); - const admin = await m.services.users.createBapiUser(fakeAdmin); - fakeOrganization = await m.services.users.createFakeOrganization(admin.id); + fakeAdmin = m.services.users.createFakeUser(); + const admin = await m.services.users.createBapiUser(fakeAdmin); + fakeOrganization = await m.services.users.createFakeOrganization(admin.id); + + fakeAdmin2 = m.services.users.createFakeUser(); + const admin2 = await m.services.users.createBapiUser(fakeAdmin2); + fakeOrganization2 = await m.services.users.createFakeOrganization(admin2.id); }); test.afterAll(async () => { await fakeOrganization.delete(); - await fakeAdmin.deleteIfExists(); - await app.teardown(); + await fakeAdmin.deleteIfExists(); + + await fakeOrganization2.delete(); + await fakeAdmin2.deleteIfExists(); + await app.teardown(); }); - test('Clerk client loads on first visit and Sign In button renders', async ({ page, context }) => { + test('render SignedIn and SignedOut contents', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); await u.page.waitForClerkJsLoaded(); await u.po.expect.toBeSignedOut(); - console.log('contents', await page.content()); + await u.po.signIn.waitForMounted(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); + await u.po.expect.toBeSignedIn(); + await u.po.userButton.waitForMounted(); + }); + + test('render Protect contents for admin', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + await u.page.goToAppHome(); + + await u.page.waitForClerkJsLoaded(); + + // Sign in + await u.po.signIn.waitForMounted(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); + await u.po.expect.toBeSignedIn(); + + // Select an organization + await u.po.organizationSwitcher.waitForMounted(); + await u.po.organizationSwitcher.expectPersonalAccount(); + await u.po.organizationSwitcher.toggleTrigger(); + await u.page.locator('.cl-organizationSwitcherPreviewButton').click(); + await u.po.organizationSwitcher.waitForAnOrganizationToSelected(); + + await u.page.goToRelative('/protected'); + await u.page.waitForClerkJsLoaded(); + + await expect(u.page.getByText("I'm an admin")).toBeVisible(); + }); + + test('render Protect fallback for non-admins', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + await u.page.goToAppHome(); + + await u.page.waitForClerkJsLoaded(); + + // Sign in + await u.po.signIn.waitForMounted(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin2.email, password: fakeAdmin2.password }); + await u.po.expect.toBeSignedIn(); + + await u.page.goToRelative('/protected'); + await u.page.waitForClerkJsLoaded(); - await expect(u.page.getByRole('button', { name: /Sign in/i })).toBeVisible(); + await expect(u.page.getByText('Not an admin')).toBeVisible(); }); }, ); From ae02d48575fb267222b6d8019852c29a6f169cef Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 13:35:25 -0700 Subject: [PATCH 32/85] test(astro): Clean up static config --- integration/presets/astro.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 95f3dfa115d..6849535de66 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -17,15 +17,10 @@ const astroNode = applicationConfig() .addDependency('@clerk/types', clerkTypesLocal) .addDependency('@clerk/localizations', clerkLocalizationLocal); -const astroStatic = applicationConfig() +const astroStatic = astroNode + .clone() .setName('astro-static') - .useTemplate(templates['astro-static']) - .setEnvFormatter('public', key => `PUBLIC_${key}`) - .addScript('setup', 'npm i') - .addScript('dev', 'npm run dev') - .addScript('build', 'npm run build') - .addScript('serve', 'npm run preview') - .addDependency('@clerk/astro', clerkAstroLocal); + .useTemplate(templates['astro-static']); export const astro = { node: astroNode, From 7887e26a4511da26b80d2d44da21baad657dee35 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 14:03:34 -0700 Subject: [PATCH 33/85] chore(astro): File location clean up --- integration/presets/astro.ts | 2 +- packages/astro/src/integration/create-integration.ts | 2 +- .../src/{internal => integration}/vite-plugin-astro-config.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/astro/src/{internal => integration}/vite-plugin-astro-config.ts (100%) diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 6849535de66..92d370b1ccd 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -25,4 +25,4 @@ const astroStatic = astroNode export const astro = { node: astroNode, static: astroStatic, -}; +} as const; diff --git a/packages/astro/src/integration/create-integration.ts b/packages/astro/src/integration/create-integration.ts index ac75ce6ba38..34b3e6e3c7c 100644 --- a/packages/astro/src/integration/create-integration.ts +++ b/packages/astro/src/integration/create-integration.ts @@ -2,8 +2,8 @@ import type { ClerkOptions } from '@clerk/types'; import type { AstroIntegration } from 'astro'; import { name as packageName, version as packageVersion } from '../../package.json'; -import { vitePluginAstroConfig } from '../internal/vite-plugin-astro-config'; import type { AstroClerkIntegrationParams } from '../types'; +import { vitePluginAstroConfig } from './vite-plugin-astro-config'; const buildEnvVarFromOption = (valueToBeStored: unknown, envName: keyof InternalEnv) => { return valueToBeStored ? { [`import.meta.env.${envName}`]: JSON.stringify(valueToBeStored) } : {}; diff --git a/packages/astro/src/internal/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts similarity index 100% rename from packages/astro/src/internal/vite-plugin-astro-config.ts rename to packages/astro/src/integration/vite-plugin-astro-config.ts From 095c199e6002f60a68a7d0b47b99e67ce964b851 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 14:24:37 -0700 Subject: [PATCH 34/85] chore(astro): Remove unused bundled folder --- packages/astro/bundled/package.json | 3 --- packages/astro/package.json | 1 - 2 files changed, 4 deletions(-) delete mode 100644 packages/astro/bundled/package.json diff --git a/packages/astro/bundled/package.json b/packages/astro/bundled/package.json deleted file mode 100644 index a59118805b6..00000000000 --- a/packages/astro/bundled/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "main": "../dist/bundled.js" -} diff --git a/packages/astro/package.json b/packages/astro/package.json index 55b28d7de6a..d7911d3ec48 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -38,7 +38,6 @@ }, "files": [ "dist", - "bundled", "client", "server", "internal", From 5a41ab11569a5f41defe3f5373e8f36086f246b9 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 15:05:16 -0700 Subject: [PATCH 35/85] chore(astro): Update virtual module to include hybrid mode --- .../astro-components/control/Protect.astro | 19 ++++++++++++++----- .../astro-components/control/SignedIn.astro | 10 +++++++--- .../astro-components/control/SignedOut.astro | 10 +++++++--- .../integration/vite-plugin-astro-config.ts | 18 ++++++++++++++++-- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index 74c6e22a49f..b8a9e0c69a6 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -2,16 +2,19 @@ import ProtectCSR from "./ProtectCSR.astro"; import ProtectSSR from "./ProtectSSR.astro"; +// @ts-expect-error: Virtual module +import { isStaticOutput } from "virtual:@clerk/astro/config"; + import type { CheckAuthorizationWithCustomPermissions, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, } from "@clerk/types"; -// @ts-expect-error: Fix types later -import config from "virtual:astro/config"; +// @ts-expect-error: Virtual module +import { isStaticOutput } from "virtual:@clerk/astro/config"; -type Props = +type ProtectProps = | { condition?: never; role: OrganizationCustomRoleKey; @@ -33,10 +36,16 @@ type Props = permission?: never; }; -const ProtectComponent = config.output === 'static' ? ProtectCSR : ProtectSSR; +type Props = ProtectProps & { + isStatic?: boolean +} + +const { isStatic, ...props } = Astro.props; + +const ProtectComponent = isStaticOutput(isStatic) ? ProtectCSR : ProtectSSR; --- - + diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index 48bcaab66ad..fc71fe3c3e5 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,10 +1,14 @@ --- import SignedInSSR from "./SignedInSSR.astro"; import SignedInCSR from "./SignedInCSR.astro"; -// @ts-expect-error: Fix types later -import config from "virtual:astro/config"; +// @ts-expect-error: Virtual module +import { isStaticOutput } from "virtual:@clerk/astro/config"; -const SignedInComponent = config.output === 'static' ? SignedInCSR : SignedInSSR; +type Props = { + isStatic?: boolean +} + +const SignedInComponent = isStaticOutput(Astro.props.isStatic) ? SignedInCSR : SignedInSSR; --- diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index dd8b0aaeb80..770d1e0a098 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -1,10 +1,14 @@ --- import SignedOutSSR from './SignedOutSSR.astro'; import SignedOutCSR from './SignedOutCSR.astro'; -// @ts-expect-error: Fix types later -import config from "virtual:astro/config"; +// @ts-expect-error: Virtual module +import { isStaticOutput } from "virtual:@clerk/astro/config"; -const SignedOutComponent = config.output === 'static' ? SignedOutCSR : SignedOutSSR; +type Props = { + isStatic?: boolean +} + +const SignedOutComponent = isStaticOutput(Astro.props.isStatic) ? SignedOutCSR : SignedOutSSR; --- diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 43e15b07acc..fcaed148ad4 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -4,7 +4,7 @@ import type { ViteUserConfig } from 'astro/config'; type ExtractPluginOption = T extends (infer U)[] ? U : never; export function vitePluginAstroConfig(astroConfig: AstroConfig): ExtractPluginOption> { - const virtualModuleId = 'virtual:astro/config'; + const virtualModuleId = 'virtual:@clerk/astro/config'; const resolvedVirtualModuleId = '\0' + virtualModuleId; return { @@ -16,7 +16,21 @@ export function vitePluginAstroConfig(astroConfig: AstroConfig): ExtractPluginOp }, load(id) { if (id === resolvedVirtualModuleId) { - return `export default ${JSON.stringify(astroConfig)}`; + return ` + export const astroConfig = ${JSON.stringify(astroConfig)}; + + export function isStaticOutput(forceStatic) { + if (astroConfig.output === 'hybrid' && forceStatic === undefined) { + throw new Error('Please specify if component should be in static or server mode.'); + } + + if (forceStatic !== undefined) { + return forceClient; + } + + return astroConfig.output === 'static'; + } + `; } } }; From 783f4db78d3cb8aba005b9b259f7c22531ddc703 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 15:06:28 -0700 Subject: [PATCH 36/85] chore(astro): Run formatter --- integration/presets/astro.ts | 5 +---- integration/tests/astro/static.test.ts | 20 +++++++++---------- packages/astro/src/env.d.ts | 6 ------ .../integration/vite-plugin-astro-config.ts | 6 ++++-- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 92d370b1ccd..7ac64acf87c 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -17,10 +17,7 @@ const astroNode = applicationConfig() .addDependency('@clerk/types', clerkTypesLocal) .addDependency('@clerk/localizations', clerkLocalizationLocal); -const astroStatic = astroNode - .clone() - .setName('astro-static') - .useTemplate(templates['astro-static']); +const astroStatic = astroNode.clone().setName('astro-static').useTemplate(templates['astro-static']); export const astro = { node: astroNode, diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 7fd4c54b246..933ef9c4d02 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -15,22 +15,22 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( test.beforeAll(async () => { const m = createTestUtils({ app }); - fakeAdmin = m.services.users.createFakeUser(); - const admin = await m.services.users.createBapiUser(fakeAdmin); - fakeOrganization = await m.services.users.createFakeOrganization(admin.id); + fakeAdmin = m.services.users.createFakeUser(); + const admin = await m.services.users.createBapiUser(fakeAdmin); + fakeOrganization = await m.services.users.createFakeOrganization(admin.id); - fakeAdmin2 = m.services.users.createFakeUser(); - const admin2 = await m.services.users.createBapiUser(fakeAdmin2); - fakeOrganization2 = await m.services.users.createFakeOrganization(admin2.id); + fakeAdmin2 = m.services.users.createFakeUser(); + const admin2 = await m.services.users.createBapiUser(fakeAdmin2); + fakeOrganization2 = await m.services.users.createFakeOrganization(admin2.id); }); test.afterAll(async () => { await fakeOrganization.delete(); - await fakeAdmin.deleteIfExists(); + await fakeAdmin.deleteIfExists(); - await fakeOrganization2.delete(); - await fakeAdmin2.deleteIfExists(); - await app.teardown(); + await fakeOrganization2.delete(); + await fakeAdmin2.deleteIfExists(); + await app.teardown(); }); test('render SignedIn and SignedOut contents', async ({ page, context }) => { diff --git a/packages/astro/src/env.d.ts b/packages/astro/src/env.d.ts index 6a4476c953d..57dc7096ab1 100644 --- a/packages/astro/src/env.d.ts +++ b/packages/astro/src/env.d.ts @@ -29,9 +29,3 @@ declare namespace App { runtime: { env: InternalEnv }; } } - -declare module "virtual:astro/config" { - import type { AstroConfig } from "astro"; - const config: AstroConfig; - export default config; -} diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index fcaed148ad4..19fe8405b2d 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -3,7 +3,9 @@ import type { ViteUserConfig } from 'astro/config'; type ExtractPluginOption = T extends (infer U)[] ? U : never; -export function vitePluginAstroConfig(astroConfig: AstroConfig): ExtractPluginOption> { +export function vitePluginAstroConfig( + astroConfig: AstroConfig, +): ExtractPluginOption> { const virtualModuleId = 'virtual:@clerk/astro/config'; const resolvedVirtualModuleId = '\0' + virtualModuleId; @@ -32,6 +34,6 @@ export function vitePluginAstroConfig(astroConfig: AstroConfig): ExtractPluginOp } `; } - } + }, }; } From 3d5943f47dc7ae32499949b6fec05ffcf4d8386f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 15:47:09 -0700 Subject: [PATCH 37/85] test(astro): Improve visibility tests --- integration/templates/astro-static/src/pages/index.astro | 2 ++ integration/tests/astro/static.test.ts | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-static/src/pages/index.astro index 2879de8190e..36415f59dfb 100644 --- a/integration/templates/astro-static/src/pages/index.astro +++ b/integration/templates/astro-static/src/pages/index.astro @@ -5,9 +5,11 @@ import Layout from "../layouts/Layout.astro"; +

Signed out

+

Signed in

diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 933ef9c4d02..67ee7e0afda 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -40,10 +40,15 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await u.page.waitForClerkJsLoaded(); await u.po.expect.toBeSignedOut(); + await expect(u.page.getByText("Signed out")).toBeVisible(); + await expect(u.page.getByText("Signed in")).toBeHidden(); + await u.po.signIn.waitForMounted(); await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); await u.po.expect.toBeSignedIn(); - await u.po.userButton.waitForMounted(); + + await expect(u.page.getByText("Signed out")).toBeHidden(); + await expect(u.page.getByText("Signed in")).toBeVisible(); }); test('render Protect contents for admin', async ({ page, context }) => { From 5d91dd0c4515d8698d55b73db95eb23bd86af254 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 8 Aug 2024 15:50:17 -0700 Subject: [PATCH 38/85] chore(astro): Add back adapter missing error message --- packages/astro/src/integration/create-integration.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/astro/src/integration/create-integration.ts b/packages/astro/src/integration/create-integration.ts index 34b3e6e3c7c..54242761ea1 100644 --- a/packages/astro/src/integration/create-integration.ts +++ b/packages/astro/src/integration/create-integration.ts @@ -28,6 +28,10 @@ function createIntegration() name: '@clerk/astro/integration', hooks: { 'astro:config:setup': ({ config, injectScript, updateConfig, logger, command }) => { + if (['server', 'hybrid'].includes(config.output) && !config.adapter) { + logger.error('Missing adapter, please update your Astro config to use one.'); + } + if (typeof clerkJSVariant !== 'undefined' && clerkJSVariant !== 'headless' && clerkJSVariant !== '') { logger.error('Invalid value for clerkJSVariant. Acceptable values are `"headless"`, `""`, and `undefined`'); } From 5e363d2d4e083ccead9e751f599d2b5a33ffa999 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 9 Aug 2024 07:30:27 -0700 Subject: [PATCH 39/85] chore(astro): Run prettier format --- integration/tests/astro/static.test.ts | 8 ++++---- packages/shared/src/__tests__/loadClerkJsScript.test.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 67ee7e0afda..513a873776c 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -40,15 +40,15 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await u.page.waitForClerkJsLoaded(); await u.po.expect.toBeSignedOut(); - await expect(u.page.getByText("Signed out")).toBeVisible(); - await expect(u.page.getByText("Signed in")).toBeHidden(); + await expect(u.page.getByText('Signed out')).toBeVisible(); + await expect(u.page.getByText('Signed in')).toBeHidden(); await u.po.signIn.waitForMounted(); await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); await u.po.expect.toBeSignedIn(); - await expect(u.page.getByText("Signed out")).toBeHidden(); - await expect(u.page.getByText("Signed in")).toBeVisible(); + await expect(u.page.getByText('Signed out')).toBeHidden(); + await expect(u.page.getByText('Signed in')).toBeVisible(); }); test('render Protect contents for admin', async ({ page, context }) => { diff --git a/packages/shared/src/__tests__/loadClerkJsScript.test.ts b/packages/shared/src/__tests__/loadClerkJsScript.test.ts index 7405215c839..186298a2a9f 100644 --- a/packages/shared/src/__tests__/loadClerkJsScript.test.ts +++ b/packages/shared/src/__tests__/loadClerkJsScript.test.ts @@ -140,4 +140,4 @@ describe('buildClerkJsScriptAttributes()', () => { // @ts-ignore input loses correct type because of empty object expect(buildClerkJsScriptAttributes(input)).toEqual(expected); }); -}); \ No newline at end of file +}); From 2928bf6bc49e9b5f507e335ff457f5b327da436e Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 9 Aug 2024 07:32:53 -0700 Subject: [PATCH 40/85] chore(astro): Revert hotload script build logic --- .../src/server/build-clerk-hotload-script.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/astro/src/server/build-clerk-hotload-script.ts b/packages/astro/src/server/build-clerk-hotload-script.ts index 12ee38c0625..d135dd3bcb2 100644 --- a/packages/astro/src/server/build-clerk-hotload-script.ts +++ b/packages/astro/src/server/build-clerk-hotload-script.ts @@ -1,4 +1,4 @@ -import { buildClerkJsScriptAttributes, clerkJsScriptUrl } from '@clerk/shared/loadClerkJsScript'; +import { clerkJsScriptUrl } from '@clerk/shared/loadClerkJsScript'; import type { APIContext } from 'astro'; import { getSafeEnv } from './get-safe-env'; @@ -15,22 +15,14 @@ function buildClerkHotloadScript(locals: APIContext['locals']) { proxyUrl, publishableKey, }); - - const attributes = buildClerkJsScriptAttributes({ - publishableKey, - proxyUrl, - domain, - }); - const attributesString = Object.entries(attributes) - .map(([key, value]) => `${key}="${value}"`) - .join(' '); - return ` \n`; } From 05f848f3f71d5026564164e5a5ae37d067170db9 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 9 Aug 2024 15:46:32 -0700 Subject: [PATCH 41/85] chore(astro): Remove duplicate import --- packages/astro/src/astro-components/control/Protect.astro | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index b8a9e0c69a6..fd6aa6c8dbb 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -11,9 +11,6 @@ import type { OrganizationCustomRoleKey, } from "@clerk/types"; -// @ts-expect-error: Virtual module -import { isStaticOutput } from "virtual:@clerk/astro/config"; - type ProtectProps = | { condition?: never; From 026b7e4689551ccdd2ea89d0116fef3ed16bd574 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 9 Aug 2024 16:04:49 -0700 Subject: [PATCH 42/85] chore(astro): Reuse ProtectProps and publish types file --- packages/astro/.gitignore | 1 + packages/astro/package.json | 5 +-- .../astro-components/control/Protect.astro | 29 +--------------- .../astro-components/control/ProtectCSR.astro | 19 ++--------- .../astro-components/control/ProtectSSR.astro | 28 ++-------------- .../astro/src/react/controlComponents.tsx | 30 ++--------------- packages/astro/src/types.ts | 33 +++++++++++++++++-- 7 files changed, 42 insertions(+), 103 deletions(-) diff --git a/packages/astro/.gitignore b/packages/astro/.gitignore index 29d852eaa1c..17fa296850d 100644 --- a/packages/astro/.gitignore +++ b/packages/astro/.gitignore @@ -5,6 +5,7 @@ astro-components/ components/ !src/components/ .output/ +/types.ts .vscode/ .idea/ diff --git a/packages/astro/package.json b/packages/astro/package.json index d7911d3ec48..178f2f10ecb 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -30,7 +30,7 @@ "dev": "tsup --watch --onSuccess \"npm run build:dts\"", "build": "tsup --onSuccess \"npm run build:dts\" && npm run copy:components", "build:dts": "tsc --emitDeclarationOnly --declaration", - "copy:components": "rm -rf ./components && mkdir -p ./components/ && cp -r ./src/astro-components/* ./components/", + "copy:components": "rm -rf ./components && mkdir -p ./components/ && cp -r ./src/astro-components/* ./components/ && cp ./src/types.ts ./", "lint": "eslint src/", "lint:attw": "attw --pack .", "lint:publint": "publint", @@ -42,7 +42,8 @@ "server", "internal", "components", - "env.d.ts" + "env.d.ts", + "types.ts" ], "exports": { ".": { diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index fd6aa6c8dbb..7d42e7b78a5 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -4,34 +4,7 @@ import ProtectSSR from "./ProtectSSR.astro"; // @ts-expect-error: Virtual module import { isStaticOutput } from "virtual:@clerk/astro/config"; - -import type { - CheckAuthorizationWithCustomPermissions, - OrganizationCustomPermissionKey, - OrganizationCustomRoleKey, -} from "@clerk/types"; - -type ProtectProps = - | { - condition?: never; - role: OrganizationCustomRoleKey; - permission?: never; - } - | { - condition?: never; - role?: never; - permission: OrganizationCustomPermissionKey; - } - | { - condition: (has: CheckAuthorizationWithCustomPermissions) => boolean; - role?: never; - permission?: never; - } - | { - condition?: never; - role?: never; - permission?: never; - }; +import type { ProtectProps } from '../../types'; type Props = ProtectProps & { isStatic?: boolean diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 8503d6fc238..d1ed5833a91 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -1,22 +1,7 @@ --- -import type { - OrganizationCustomPermissionKey, - OrganizationCustomRoleKey, -} from "@clerk/types"; +import type { ProtectProps } from '../../types'; -type Props = - | { - role: OrganizationCustomRoleKey; - permission?: never; - } - | { - role?: never; - permission: OrganizationCustomPermissionKey; - } - | { - role?: never; - permission?: never; - }; +type Props = Omit; const { role, permission } = Astro.props; --- diff --git a/packages/astro/src/astro-components/control/ProtectSSR.astro b/packages/astro/src/astro-components/control/ProtectSSR.astro index d4b0ebb0c46..4f0d58a98ea 100644 --- a/packages/astro/src/astro-components/control/ProtectSSR.astro +++ b/packages/astro/src/astro-components/control/ProtectSSR.astro @@ -1,31 +1,7 @@ --- -import type { - CheckAuthorizationWithCustomPermissions, - OrganizationCustomPermissionKey, - OrganizationCustomRoleKey, -} from "@clerk/types"; +import type { ProtectProps } from '../../types'; -type Props = - | { - condition?: never; - role: OrganizationCustomRoleKey; - permission?: never; - } - | { - condition?: never; - role?: never; - permission: OrganizationCustomPermissionKey; - } - | { - condition: (has: CheckAuthorizationWithCustomPermissions) => boolean; - role?: never; - permission?: never; - } - | { - condition?: never; - role?: never; - permission?: never; - }; +type Props = ProtectProps; const { has, userId } = Astro.locals.auth(); const isUnauthorized = diff --git a/packages/astro/src/react/controlComponents.tsx b/packages/astro/src/react/controlComponents.tsx index 22c1bd65ccf..24d509219ed 100644 --- a/packages/astro/src/react/controlComponents.tsx +++ b/packages/astro/src/react/controlComponents.tsx @@ -1,14 +1,13 @@ import type { CheckAuthorizationWithCustomPermissions, HandleOAuthCallbackParams, - OrganizationCustomPermissionKey, - OrganizationCustomRoleKey, } from '@clerk/types'; import { computed } from 'nanostores'; import type { PropsWithChildren } from 'react'; import React, { useEffect, useState } from 'react'; import { $csrState } from '../stores/internal'; +import type { ProtectProps as _ProtectProps } from '../types'; import { useAuth } from './hooks'; import type { WithClerkProp } from './utils'; import { withClerk } from './utils'; @@ -73,32 +72,7 @@ export const ClerkLoading = ({ children }: React.PropsWithChildren): JSX.Element return <>{children}; }; -export type ProtectProps = React.PropsWithChildren< - ( - | { - condition?: never; - role: OrganizationCustomRoleKey; - permission?: never; - } - | { - condition?: never; - role?: never; - permission: OrganizationCustomPermissionKey; - } - | { - condition: (has: CheckAuthorizationWithCustomPermissions) => boolean; - role?: never; - permission?: never; - } - | { - condition?: never; - role?: never; - permission?: never; - } - ) & { - fallback?: React.ReactNode; - } ->; +export type ProtectProps = React.PropsWithChildren<_ProtectProps & { fallback?: React.ReactNode }>; /** * Use `` in order to prevent unauthenticated or unauthorized users from accessing the children passed to the component. diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts index c9e9897e128..802dd06d053 100644 --- a/packages/astro/src/types.ts +++ b/packages/astro/src/types.ts @@ -1,4 +1,11 @@ -import type { ClerkOptions, MultiDomainAndOrProxyPrimitives, Without } from '@clerk/types'; +import type { + CheckAuthorizationWithCustomPermissions, + ClerkOptions, + MultiDomainAndOrProxyPrimitives, + OrganizationCustomPermissionKey, + OrganizationCustomRoleKey, + Without, +} from '@clerk/types'; type AstroClerkUpdateOptions = Pick; @@ -25,4 +32,26 @@ declare global { } } -export type { AstroClerkUpdateOptions, AstroClerkIntegrationParams, AstroClerkCreateInstanceParams }; +type ProtectProps = + | { + condition?: never; + role: OrganizationCustomRoleKey; + permission?: never; + } + | { + condition?: never; + role?: never; + permission: OrganizationCustomPermissionKey; + } + | { + condition: (has: CheckAuthorizationWithCustomPermissions) => boolean; + role?: never; + permission?: never; + } + | { + condition?: never; + role?: never; + permission?: never; + } + +export type { AstroClerkUpdateOptions, AstroClerkIntegrationParams, AstroClerkCreateInstanceParams, ProtectProps }; From ce97965dafcfa9a6975eecedd36ea651df5def7c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 12 Aug 2024 11:49:08 -0700 Subject: [PATCH 43/85] chore(astro): Fix incorrect variable name --- packages/astro/src/integration/vite-plugin-astro-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 19fe8405b2d..94c8aef4ed0 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -27,7 +27,7 @@ export function vitePluginAstroConfig( } if (forceStatic !== undefined) { - return forceClient; + return forceStatic; } return astroConfig.output === 'static'; From ac7d4602c15d5ea8edc8ec216bf9ad8032560d1c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 12 Aug 2024 20:24:09 -0700 Subject: [PATCH 44/85] chore(astro): pre-bundle client stores export --- packages/astro/src/integration/vite-plugin-astro-config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 94c8aef4ed0..61060124991 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -16,6 +16,10 @@ export function vitePluginAstroConfig( return resolvedVirtualModuleId; } }, + config(config) { + // This is necessary because it does not work in dev mode without pre-bundling. + config.optimizeDeps?.include?.push('@clerk/astro/client'); + }, load(id) { if (id === resolvedVirtualModuleId) { return ` From c99bc75a345b56b6602a909fa08cbd531fefa0d8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 12 Aug 2024 20:29:38 -0700 Subject: [PATCH 45/85] chore(astro): Update vite plugin to set hybrid component initial to server --- packages/astro/src/integration/vite-plugin-astro-config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 61060124991..f90b11025c7 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -18,6 +18,7 @@ export function vitePluginAstroConfig( }, config(config) { // This is necessary because it does not work in dev mode without pre-bundling. + // We use it in our CSR control components. config.optimizeDeps?.include?.push('@clerk/astro/client'); }, load(id) { From 466ba972958b8c8e824ad66b2b0a555c482831b4 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 12 Aug 2024 20:30:27 -0700 Subject: [PATCH 46/85] chore(astro): Update vite plugin to set hybrid component initial to server --- packages/astro/src/integration/vite-plugin-astro-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index f90b11025c7..f289ca15d4d 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -28,7 +28,7 @@ export function vitePluginAstroConfig( export function isStaticOutput(forceStatic) { if (astroConfig.output === 'hybrid' && forceStatic === undefined) { - throw new Error('Please specify if component should be in static or server mode.'); + return 'server'; } if (forceStatic !== undefined) { From 29957bb88436e0bc9d4dba2414949aafd55b1934 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 12 Aug 2024 20:31:27 -0700 Subject: [PATCH 47/85] chore(astro): Remove duplicate env vars in vite --- packages/astro/src/integration/create-integration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/astro/src/integration/create-integration.ts b/packages/astro/src/integration/create-integration.ts index 54242761ea1..b640dedbbf4 100644 --- a/packages/astro/src/integration/create-integration.ts +++ b/packages/astro/src/integration/create-integration.ts @@ -60,8 +60,6 @@ function createIntegration() ...buildEnvVarFromOption(isSatellite, 'PUBLIC_CLERK_IS_SATELLITE'), ...buildEnvVarFromOption(proxyUrl, 'PUBLIC_CLERK_PROXY_URL'), ...buildEnvVarFromOption(domain, 'PUBLIC_CLERK_DOMAIN'), - ...buildEnvVarFromOption(domain, 'PUBLIC_CLERK_DOMAIN'), - ...buildEnvVarFromOption(domain, 'PUBLIC_CLERK_DOMAIN'), ...buildEnvVarFromOption(clerkJSUrl, 'PUBLIC_CLERK_JS_URL'), ...buildEnvVarFromOption(clerkJSVariant, 'PUBLIC_CLERK_JS_VARIANT'), ...buildEnvVarFromOption(clerkJSVersion, 'PUBLIC_CLERK_JS_VERSION'), From 3dae9b25d493048382c53ab764998222f2896898 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 13 Aug 2024 08:20:47 -0700 Subject: [PATCH 48/85] chore(astro): Update changeset --- .changeset/proud-horses-smell.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.changeset/proud-horses-smell.md b/.changeset/proud-horses-smell.md index a845151cc84..3162375ffff 100644 --- a/.changeset/proud-horses-smell.md +++ b/.changeset/proud-horses-smell.md @@ -1,2 +1,5 @@ --- +"@clerk/astro": patch --- + +Add support for Astro `static` and `hybrid` outputs. From 0c8d0f361f9e964cb49ddd596b735acf73819872 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 14 Aug 2024 11:51:37 -0700 Subject: [PATCH 49/85] chore(astro): Dynamically export control components --- integration/tests/astro/static.test.ts | 4 ++-- .../src/astro-components/control/Protect.astro | 6 ++---- .../src/astro-components/control/ProtectCSR.astro | 13 ++++++++++--- .../src/astro-components/control/SignedIn.astro | 5 ++--- .../astro-components/control/SignedInCSR.astro | 15 +++++++++------ .../src/astro-components/control/SignedOut.astro | 5 ++--- .../astro-components/control/SignedOutCSR.astro | 15 +++++++++------ packages/astro/src/stores/external.ts | 9 +++++++++ 8 files changed, 45 insertions(+), 27 deletions(-) diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 513a873776c..1d272844889 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -51,7 +51,7 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await expect(u.page.getByText('Signed in')).toBeVisible(); }); - test('render Protect contents for admin', async ({ page, context }) => { + test.skip('render Protect contents for admin', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); @@ -75,7 +75,7 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await expect(u.page.getByText("I'm an admin")).toBeVisible(); }); - test('render Protect fallback for non-admins', async ({ page, context }) => { + test.skip('render Protect fallback for non-admins', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index 7d42e7b78a5..8ee22c756e1 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -1,7 +1,4 @@ --- -import ProtectCSR from "./ProtectCSR.astro"; -import ProtectSSR from "./ProtectSSR.astro"; - // @ts-expect-error: Virtual module import { isStaticOutput } from "virtual:@clerk/astro/config"; import type { ProtectProps } from '../../types'; @@ -12,7 +9,8 @@ type Props = ProtectProps & { const { isStatic, ...props } = Astro.props; -const ProtectComponent = isStaticOutput(isStatic) ? ProtectCSR : ProtectSSR; +const module = isStaticOutput(isStatic) ? await import('./ProtectCSR.astro') : await import('./ProtectSSR.astro'); +const ProtectComponent = module.default; --- diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index d1ed5833a91..dc596a0a19a 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -15,16 +15,23 @@ const { role, permission } = Astro.props;
+ +
+ +
+
+ +
+ diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index bd9a4f7b5f9..aa99356a5ec 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,13 +1,14 @@ --- +import SignedInCSR from './SignedInCSR.astro'; +import SignedInSSR from './SignedInSSR.astro'; // @ts-expect-error: Virtual module -import { isStaticOutput } from "virtual:@clerk/astro/config"; +import { isStaticOutput } from 'virtual:@clerk/astro/config'; type Props = { isStatic?: boolean } -const module = isStaticOutput(Astro.props.isStatic) ? await import('./SignedInCSR.astro') : await import('./SignedInSSR.astro'); -const SignedInComponent = module.default; +const SignedInComponent = isStaticOutput(Astro.props.isStatic) ? SignedInCSR : SignedInSSR; --- diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro index a6588873576..2aa71220340 100644 --- a/packages/astro/src/astro-components/control/SignedInCSR.astro +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -1,33 +1,3 @@ - - - + diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index d8c9d87dfb7..4684f5698ce 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -1,13 +1,14 @@ --- +import SignedOutCSR from './SignedOutCSR.astro'; +import SignedOutSSR from './SignedOutSSR.astro'; // @ts-expect-error: Virtual module -import { isStaticOutput } from "virtual:@clerk/astro/config"; +import { isStaticOutput } from 'virtual:@clerk/astro/config'; type Props = { isStatic?: boolean } -const module = isStaticOutput(Astro.props.isStatic) ? await import('./SignedOutCSR.astro') : await import('./SignedOutSSR.astro'); -const SignedOutComponent = module.default; +const SignedOutComponent = isStaticOutput(Astro.props.isStatic) ? SignedOutCSR : SignedOutSSR; --- diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro index cc56294f844..bfac0dec438 100644 --- a/packages/astro/src/astro-components/control/SignedOutCSR.astro +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -1,33 +1,3 @@ - - - + diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index dd72be8d929..69efb4c1552 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -3,6 +3,7 @@ import type { ClerkOptions } from '@clerk/types'; import { $clerk, $csrState } from '../stores/internal'; import type { AstroClerkCreateInstanceParams, AstroClerkUpdateOptions } from '../types'; +import { defineCustomElements } from './define-custom-elements'; import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions'; import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; import { runOnce } from './run-once'; @@ -56,6 +57,7 @@ async function createClerkInstanceInternal(options?: AstroClerkCreateInstancePar mountAllClerkAstroJSComponents(); invokeClerkAstroJSFunctions(); + void defineCustomElements(); clerkJSInstance.addListener(payload => { $csrState.setKey('client', payload.client); diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts new file mode 100644 index 00000000000..c63497edea8 --- /dev/null +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -0,0 +1,64 @@ +import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types'; + +import { $authStore } from '../../stores/external'; +import { $csrState } from '../../stores/internal'; + +export class Protect extends HTMLElement { + private defaultSlot: HTMLDivElement | null = null; + private fallbackSlot: HTMLDivElement | null = null; + + constructor() { + super(); + } + + connectedCallback() { + this.defaultSlot = this.querySelector('[data-default-slot]'); + this.fallbackSlot = this.querySelector('[data-fallback-slot]'); + + $csrState.subscribe(state => { + if (state.isLoaded) { + this.toggleContentVisibility(); + } + }); + } + + toggleContentVisibility() { + $authStore.subscribe(state => { + const has = (params: Parameters[0]) => { + if (!params?.permission && !params?.role) { + throw new Error( + 'Missing parameters. The prop permission or role is required to be passed. Example usage: `has({permission: "org:posts:edit"})`', + ); + } + + if (!state.orgId || !state.userId || !state.orgRole || !state?.orgPermissions) { + return false; + } + + if (params.permission) { + return state.orgPermissions.includes(params.permission); + } + + if (params.role) { + return state.orgRole === params.role; + } + + return false; + }; + + const role = this.dataset.role; + const permission = this.dataset.permission; + const isUnauthorized = + !state.userId || + ((role || permission) && !has({ role, permission } as Parameters[0])); + + if (this.defaultSlot) { + isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden'); + } + + if (this.fallbackSlot) { + isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', ''); + } + }); + } +} diff --git a/packages/astro/src/internal/custom-elements/signed-in.ts b/packages/astro/src/internal/custom-elements/signed-in.ts new file mode 100644 index 00000000000..d6a9688d289 --- /dev/null +++ b/packages/astro/src/internal/custom-elements/signed-in.ts @@ -0,0 +1,26 @@ +import { $authStore } from '../../stores/external'; +import { $csrState } from '../../stores/internal'; + +export class SignedIn extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + $csrState.subscribe(state => { + if (state.isLoaded) { + this.toggleContentVisibility(); + } + }); + } + + toggleContentVisibility() { + $authStore.subscribe(state => { + if (state.userId) { + this.removeAttribute('hidden'); + } else { + this.setAttribute('hidden', ''); + } + }); + } +} diff --git a/packages/astro/src/internal/custom-elements/signed-out.ts b/packages/astro/src/internal/custom-elements/signed-out.ts new file mode 100644 index 00000000000..854915fd89d --- /dev/null +++ b/packages/astro/src/internal/custom-elements/signed-out.ts @@ -0,0 +1,26 @@ +import { $authStore } from '../../stores/external'; +import { $csrState } from '../../stores/internal'; + +export class SignedOut extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + $csrState.subscribe(state => { + if (state.isLoaded) { + this.toggleContentVisibility(); + } + }); + } + + toggleContentVisibility() { + $authStore.subscribe(state => { + if (state.userId) { + this.setAttribute('hidden', ''); + } else { + this.removeAttribute('hidden'); + } + }); + } +} diff --git a/packages/astro/src/internal/define-custom-elements.ts b/packages/astro/src/internal/define-custom-elements.ts new file mode 100644 index 00000000000..863918d4013 --- /dev/null +++ b/packages/astro/src/internal/define-custom-elements.ts @@ -0,0 +1,17 @@ +/** + * Defines custom elements for Clerk CSR control components. + * + * @example + * + * Content for signed-in users + */ +export async function defineCustomElements() { + const [{ SignedIn }, { SignedOut }, { Protect }] = await Promise.all([ + import('./custom-elements/signed-in'), + import('./custom-elements/signed-out'), + import('./custom-elements/protect'), + ]); + window.customElements.define('clerk-signed-in', SignedIn); + window.customElements.define('clerk-signed-out', SignedOut); + window.customElements.define('clerk-protect', Protect); +} diff --git a/packages/astro/src/stores/external.ts b/packages/astro/src/stores/external.ts index 706700b568a..d122767c191 100644 --- a/packages/astro/src/stores/external.ts +++ b/packages/astro/src/stores/external.ts @@ -4,15 +4,6 @@ import { computed, onMount, type Store } from 'nanostores'; import { $clerk, $csrState, $initialState } from './internal'; -/** - * A client side store that is set to `true` after clerk-js has loaded. - * @example - * A simple example: - * - * $clerkLoadedStore.subscribe((loaded) => console.log(loaded)) - */ -export const $clerkLoadedStore = computed($csrState, state => state.isLoaded); - /** * A client side store that is prepopulated with the authentication context during SSR. * It is a nanostore, for instructions on how to use nanostores please review the [documentation](https://github.com/nanostores/nanostores) From edbe5ad04bc01c51e3a152e85147d427e9f72d02 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 14 Aug 2024 20:31:00 -0700 Subject: [PATCH 53/85] chore(astro): Add base element for CSR web components --- .../internal/custom-elements/base-element.ts | 19 +++++++++++++++++++ .../src/internal/custom-elements/protect.ts | 14 +++----------- .../src/internal/custom-elements/signed-in.ts | 14 +++----------- .../internal/custom-elements/signed-out.ts | 14 +++----------- 4 files changed, 28 insertions(+), 33 deletions(-) create mode 100644 packages/astro/src/internal/custom-elements/base-element.ts diff --git a/packages/astro/src/internal/custom-elements/base-element.ts b/packages/astro/src/internal/custom-elements/base-element.ts new file mode 100644 index 00000000000..2fbd2be6962 --- /dev/null +++ b/packages/astro/src/internal/custom-elements/base-element.ts @@ -0,0 +1,19 @@ +import { $csrState } from '../../stores/internal'; + +export class BaseElement extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + $csrState.subscribe(state => { + if (state.isLoaded) { + this.onLoaded(); + } + }); + } + + onLoaded() { + console.log('BaseElement.onLoaded()'); + } +} diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts index c63497edea8..55b96377e04 100644 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -1,9 +1,9 @@ import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types'; import { $authStore } from '../../stores/external'; -import { $csrState } from '../../stores/internal'; +import { BaseElement } from './base-element'; -export class Protect extends HTMLElement { +export class Protect extends BaseElement { private defaultSlot: HTMLDivElement | null = null; private fallbackSlot: HTMLDivElement | null = null; @@ -11,18 +11,10 @@ export class Protect extends HTMLElement { super(); } - connectedCallback() { + onLoaded() { this.defaultSlot = this.querySelector('[data-default-slot]'); this.fallbackSlot = this.querySelector('[data-fallback-slot]'); - $csrState.subscribe(state => { - if (state.isLoaded) { - this.toggleContentVisibility(); - } - }); - } - - toggleContentVisibility() { $authStore.subscribe(state => { const has = (params: Parameters[0]) => { if (!params?.permission && !params?.role) { diff --git a/packages/astro/src/internal/custom-elements/signed-in.ts b/packages/astro/src/internal/custom-elements/signed-in.ts index d6a9688d289..3da49dd31df 100644 --- a/packages/astro/src/internal/custom-elements/signed-in.ts +++ b/packages/astro/src/internal/custom-elements/signed-in.ts @@ -1,20 +1,12 @@ import { $authStore } from '../../stores/external'; -import { $csrState } from '../../stores/internal'; +import { BaseElement } from './base-element'; -export class SignedIn extends HTMLElement { +export class SignedIn extends BaseElement { constructor() { super(); } - connectedCallback() { - $csrState.subscribe(state => { - if (state.isLoaded) { - this.toggleContentVisibility(); - } - }); - } - - toggleContentVisibility() { + onLoaded() { $authStore.subscribe(state => { if (state.userId) { this.removeAttribute('hidden'); diff --git a/packages/astro/src/internal/custom-elements/signed-out.ts b/packages/astro/src/internal/custom-elements/signed-out.ts index 854915fd89d..e311b926c60 100644 --- a/packages/astro/src/internal/custom-elements/signed-out.ts +++ b/packages/astro/src/internal/custom-elements/signed-out.ts @@ -1,20 +1,12 @@ import { $authStore } from '../../stores/external'; -import { $csrState } from '../../stores/internal'; +import { BaseElement } from './base-element'; -export class SignedOut extends HTMLElement { +export class SignedOut extends BaseElement { constructor() { super(); } - connectedCallback() { - $csrState.subscribe(state => { - if (state.isLoaded) { - this.toggleContentVisibility(); - } - }); - } - - toggleContentVisibility() { + onLoaded() { $authStore.subscribe(state => { if (state.userId) { this.setAttribute('hidden', ''); From aa3112cbbee6b0b8a3f62b4b339ebfd8051d1710 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 14 Aug 2024 21:24:01 -0700 Subject: [PATCH 54/85] chore(astro): Remove unnecessary optimized dep --- packages/astro/src/integration/vite-plugin-astro-config.ts | 5 ----- packages/astro/src/internal/custom-elements/base-element.ts | 6 +++--- packages/astro/src/internal/custom-elements/protect.ts | 2 +- packages/astro/src/internal/custom-elements/signed-in.ts | 2 +- packages/astro/src/internal/custom-elements/signed-out.ts | 2 +- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index f289ca15d4d..c6cf6c78da6 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -16,11 +16,6 @@ export function vitePluginAstroConfig( return resolvedVirtualModuleId; } }, - config(config) { - // This is necessary because it does not work in dev mode without pre-bundling. - // We use it in our CSR control components. - config.optimizeDeps?.include?.push('@clerk/astro/client'); - }, load(id) { if (id === resolvedVirtualModuleId) { return ` diff --git a/packages/astro/src/internal/custom-elements/base-element.ts b/packages/astro/src/internal/custom-elements/base-element.ts index 2fbd2be6962..ac7388ab669 100644 --- a/packages/astro/src/internal/custom-elements/base-element.ts +++ b/packages/astro/src/internal/custom-elements/base-element.ts @@ -8,12 +8,12 @@ export class BaseElement extends HTMLElement { connectedCallback() { $csrState.subscribe(state => { if (state.isLoaded) { - this.onLoaded(); + this.onClerkLoaded(); } }); } - onLoaded() { - console.log('BaseElement.onLoaded()'); + onClerkLoaded() { + // This will be overridden by child classes } } diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts index 55b96377e04..2528c01b57f 100644 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -11,7 +11,7 @@ export class Protect extends BaseElement { super(); } - onLoaded() { + onClerkLoaded() { this.defaultSlot = this.querySelector('[data-default-slot]'); this.fallbackSlot = this.querySelector('[data-fallback-slot]'); diff --git a/packages/astro/src/internal/custom-elements/signed-in.ts b/packages/astro/src/internal/custom-elements/signed-in.ts index 3da49dd31df..66517ed8405 100644 --- a/packages/astro/src/internal/custom-elements/signed-in.ts +++ b/packages/astro/src/internal/custom-elements/signed-in.ts @@ -6,7 +6,7 @@ export class SignedIn extends BaseElement { super(); } - onLoaded() { + onClerkLoaded() { $authStore.subscribe(state => { if (state.userId) { this.removeAttribute('hidden'); diff --git a/packages/astro/src/internal/custom-elements/signed-out.ts b/packages/astro/src/internal/custom-elements/signed-out.ts index e311b926c60..65154415bbd 100644 --- a/packages/astro/src/internal/custom-elements/signed-out.ts +++ b/packages/astro/src/internal/custom-elements/signed-out.ts @@ -6,7 +6,7 @@ export class SignedOut extends BaseElement { super(); } - onLoaded() { + onClerkLoaded() { $authStore.subscribe(state => { if (state.userId) { this.setAttribute('hidden', ''); From dfb9826108825b02a06e78440b6a1f871b7356f7 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 14 Aug 2024 21:35:31 -0700 Subject: [PATCH 55/85] chore(astro): Perform clean ups --- .../internal/custom-elements/base-element.ts | 19 ------------------- .../src/internal/custom-elements/protect.ts | 16 ++++++++++++---- .../src/internal/custom-elements/signed-in.ts | 17 +++++++++++++---- .../internal/custom-elements/signed-out.ts | 17 +++++++++++++---- 4 files changed, 38 insertions(+), 31 deletions(-) delete mode 100644 packages/astro/src/internal/custom-elements/base-element.ts diff --git a/packages/astro/src/internal/custom-elements/base-element.ts b/packages/astro/src/internal/custom-elements/base-element.ts deleted file mode 100644 index ac7388ab669..00000000000 --- a/packages/astro/src/internal/custom-elements/base-element.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { $csrState } from '../../stores/internal'; - -export class BaseElement extends HTMLElement { - constructor() { - super(); - } - - connectedCallback() { - $csrState.subscribe(state => { - if (state.isLoaded) { - this.onClerkLoaded(); - } - }); - } - - onClerkLoaded() { - // This will be overridden by child classes - } -} diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts index 2528c01b57f..6c3a571cd69 100644 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -1,21 +1,29 @@ import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types'; import { $authStore } from '../../stores/external'; -import { BaseElement } from './base-element'; -export class Protect extends BaseElement { +export class Protect extends HTMLElement { private defaultSlot: HTMLDivElement | null = null; private fallbackSlot: HTMLDivElement | null = null; + private authStoreListener: (() => void) | null = null; constructor() { super(); } - onClerkLoaded() { + connectedCallback() { + this.toggleContentVisibility(); + } + + disconnectedCallback() { + this.authStoreListener?.(); + } + + toggleContentVisibility() { this.defaultSlot = this.querySelector('[data-default-slot]'); this.fallbackSlot = this.querySelector('[data-fallback-slot]'); - $authStore.subscribe(state => { + this.authStoreListener = $authStore.subscribe(state => { const has = (params: Parameters[0]) => { if (!params?.permission && !params?.role) { throw new Error( diff --git a/packages/astro/src/internal/custom-elements/signed-in.ts b/packages/astro/src/internal/custom-elements/signed-in.ts index 66517ed8405..82f339f839a 100644 --- a/packages/astro/src/internal/custom-elements/signed-in.ts +++ b/packages/astro/src/internal/custom-elements/signed-in.ts @@ -1,13 +1,22 @@ import { $authStore } from '../../stores/external'; -import { BaseElement } from './base-element'; -export class SignedIn extends BaseElement { +export class SignedIn extends HTMLElement { + private authStoreListener: (() => void) | null = null; + constructor() { super(); } - onClerkLoaded() { - $authStore.subscribe(state => { + connectedCallback() { + this.toggleContentVisibility(); + } + + disconnectedCallback() { + this.authStoreListener?.(); + } + + toggleContentVisibility() { + this.authStoreListener = $authStore.subscribe(state => { if (state.userId) { this.removeAttribute('hidden'); } else { diff --git a/packages/astro/src/internal/custom-elements/signed-out.ts b/packages/astro/src/internal/custom-elements/signed-out.ts index 65154415bbd..1281ed65b90 100644 --- a/packages/astro/src/internal/custom-elements/signed-out.ts +++ b/packages/astro/src/internal/custom-elements/signed-out.ts @@ -1,13 +1,22 @@ import { $authStore } from '../../stores/external'; -import { BaseElement } from './base-element'; -export class SignedOut extends BaseElement { +export class SignedOut extends HTMLElement { + private authStoreListener: (() => void) | null = null; + constructor() { super(); } - onClerkLoaded() { - $authStore.subscribe(state => { + connectedCallback() { + this.toggleContentVisibility(); + } + + disconnectedCallback() { + this.authStoreListener?.(); + } + + toggleContentVisibility() { + this.authStoreListener = $authStore.subscribe(state => { if (state.userId) { this.setAttribute('hidden', ''); } else { From 4b2e495d130ecffcd946ae7ab3546aa40c1b4da4 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 14 Aug 2024 21:46:30 -0700 Subject: [PATCH 56/85] chore(astro): Slot clean up --- packages/astro/src/astro-components/control/Protect.astro | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index f67c01f1d03..d004470ea4f 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -16,7 +16,5 @@ const ProtectComponent = isStaticOutput(isStatic) ? ProtectCSR : ProtectSSR; - - - + From ed6f7f121f5457284cca8c93e80bdeaf9273293c Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Fri, 16 Aug 2024 08:57:30 -0700 Subject: [PATCH 57/85] chore(astro): Update changeset Co-authored-by: Lennart --- .changeset/proud-horses-smell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/proud-horses-smell.md b/.changeset/proud-horses-smell.md index 3162375ffff..974bfd4599b 100644 --- a/.changeset/proud-horses-smell.md +++ b/.changeset/proud-horses-smell.md @@ -1,5 +1,5 @@ --- -"@clerk/astro": patch +"@clerk/astro": minor --- Add support for Astro `static` and `hybrid` outputs. From ccecf05a64757df12ca9067f014c56944158ff42 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 13:51:35 -0700 Subject: [PATCH 58/85] chore(astro): Fix incorrect output --- packages/astro/src/integration/vite-plugin-astro-config.ts | 3 ++- packages/astro/src/types.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index c6cf6c78da6..00d20446312 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -23,7 +23,8 @@ export function vitePluginAstroConfig( export function isStaticOutput(forceStatic) { if (astroConfig.output === 'hybrid' && forceStatic === undefined) { - return 'server'; + // Default page is prerendered in hybrid mode + return true; } if (forceStatic !== undefined) { diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts index 9f2628faa62..f70631f5eb5 100644 --- a/packages/astro/src/types.ts +++ b/packages/astro/src/types.ts @@ -1,6 +1,6 @@ import type { - Clerk, CheckAuthorizationWithCustomPermissions, + Clerk, ClerkOptions, ClientResource, MultiDomainAndOrProxyPrimitives, From 6582e64d20324a2a23decd42edb2679fa3a06dc8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 14:07:43 -0700 Subject: [PATCH 59/85] chore(astro): Use authorization checker function from session object --- .../astro-components/control/ProtectCSR.astro | 5 ++- .../src/internal/custom-elements/protect.ts | 32 ++++--------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 30ba6d2184f..6843b001475 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -10,11 +10,10 @@ const { role, permission } = Astro.props; data-role={role} data-permission={permission} > - -
+
-
+
diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts index 6c3a571cd69..05d6b6baa0d 100644 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -1,6 +1,6 @@ -import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types'; +import type { CheckAuthorization } from '@clerk/types'; -import { $authStore } from '../../stores/external'; +import { $authStore, $sessionStore } from '../../stores/external'; export class Protect extends HTMLElement { private defaultSlot: HTMLDivElement | null = null; @@ -20,37 +20,17 @@ export class Protect extends HTMLElement { } toggleContentVisibility() { - this.defaultSlot = this.querySelector('[data-default-slot]'); - this.fallbackSlot = this.querySelector('[data-fallback-slot]'); + this.defaultSlot = this.querySelector('[data-clerk-control-slot-default]'); + this.fallbackSlot = this.querySelector('[data-clerk-control-slot-fallback]'); this.authStoreListener = $authStore.subscribe(state => { - const has = (params: Parameters[0]) => { - if (!params?.permission && !params?.role) { - throw new Error( - 'Missing parameters. The prop permission or role is required to be passed. Example usage: `has({permission: "org:posts:edit"})`', - ); - } - - if (!state.orgId || !state.userId || !state.orgRole || !state?.orgPermissions) { - return false; - } - - if (params.permission) { - return state.orgPermissions.includes(params.permission); - } - - if (params.role) { - return state.orgRole === params.role; - } - - return false; - }; + const has = $sessionStore.get()?.checkAuthorization; const role = this.dataset.role; const permission = this.dataset.permission; const isUnauthorized = !state.userId || - ((role || permission) && !has({ role, permission } as Parameters[0])); + ((role || permission) && !has?.({ role, permission } as Parameters[0])); if (this.defaultSlot) { isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden'); From 2dca843e6e8db6f292fb2369f8cc38d7c5a42063 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 14:26:39 -0700 Subject: [PATCH 60/85] fix(astro): Do not ignore astro files in tsconfig --- packages/astro/src/astro-components/control/Protect.astro | 2 +- packages/astro/src/astro-components/control/SignedIn.astro | 2 +- .../astro/src/astro-components/control/SignedOut.astro | 2 +- packages/astro/src/env.d.ts | 7 +++++++ packages/astro/tsconfig.json | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index d004470ea4f..fe4632fc575 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -1,7 +1,7 @@ --- import ProtectCSR from './ProtectCSR.astro'; import ProtectSSR from './ProtectSSR.astro'; -// @ts-expect-error: Virtual module + import { isStaticOutput } from "virtual:@clerk/astro/config"; import type { ProtectProps } from '../../types'; diff --git a/packages/astro/src/astro-components/control/SignedIn.astro b/packages/astro/src/astro-components/control/SignedIn.astro index aa99356a5ec..a5dc40087a5 100644 --- a/packages/astro/src/astro-components/control/SignedIn.astro +++ b/packages/astro/src/astro-components/control/SignedIn.astro @@ -1,7 +1,7 @@ --- import SignedInCSR from './SignedInCSR.astro'; import SignedInSSR from './SignedInSSR.astro'; -// @ts-expect-error: Virtual module + import { isStaticOutput } from 'virtual:@clerk/astro/config'; type Props = { diff --git a/packages/astro/src/astro-components/control/SignedOut.astro b/packages/astro/src/astro-components/control/SignedOut.astro index 4684f5698ce..02d2b090318 100644 --- a/packages/astro/src/astro-components/control/SignedOut.astro +++ b/packages/astro/src/astro-components/control/SignedOut.astro @@ -1,7 +1,7 @@ --- import SignedOutCSR from './SignedOutCSR.astro'; import SignedOutSSR from './SignedOutSSR.astro'; -// @ts-expect-error: Virtual module + import { isStaticOutput } from 'virtual:@clerk/astro/config'; type Props = { diff --git a/packages/astro/src/env.d.ts b/packages/astro/src/env.d.ts index 57dc7096ab1..36637dfe2fc 100644 --- a/packages/astro/src/env.d.ts +++ b/packages/astro/src/env.d.ts @@ -29,3 +29,10 @@ declare namespace App { runtime: { env: InternalEnv }; } } + +declare module 'virtual:@clerk/astro/config' { + import type { AstroConfig } from 'astro'; + + export const astroConfig: AstroConfig; + export function isStaticOutput(forceStatic?: boolean): boolean; +} diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index d1e9ae67c05..2085897de6c 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -24,5 +24,5 @@ "declarationDir": "dist/types", "noUncheckedIndexedAccess": true }, - "exclude": ["dist", "build", "node_modules", "src/astro-components"] + "exclude": ["dist", "build", "node_modules", "src/astro-components/index.ts"] } From 29e1190dee5c6abfbf41614c28c59b3701346583 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 14:27:10 -0700 Subject: [PATCH 61/85] chore(astro): Run prettier format --- packages/astro/src/env.d.ts | 4 ++-- packages/astro/src/internal/custom-elements/protect.ts | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/env.d.ts b/packages/astro/src/env.d.ts index 36637dfe2fc..0d0c534341c 100644 --- a/packages/astro/src/env.d.ts +++ b/packages/astro/src/env.d.ts @@ -33,6 +33,6 @@ declare namespace App { declare module 'virtual:@clerk/astro/config' { import type { AstroConfig } from 'astro'; - export const astroConfig: AstroConfig; - export function isStaticOutput(forceStatic?: boolean): boolean; + export const astroConfig: AstroConfig; + export function isStaticOutput(forceStatic?: boolean): boolean; } diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts index 05d6b6baa0d..430a3716636 100644 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ b/packages/astro/src/internal/custom-elements/protect.ts @@ -29,8 +29,7 @@ export class Protect extends HTMLElement { const role = this.dataset.role; const permission = this.dataset.permission; const isUnauthorized = - !state.userId || - ((role || permission) && !has?.({ role, permission } as Parameters[0])); + !state.userId || ((role || permission) && !has?.({ role, permission } as Parameters[0])); if (this.defaultSlot) { isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden'); From f182753fe90608e7ce939b5491f0cbc05de314e9 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 14:40:48 -0700 Subject: [PATCH 62/85] chore(astro): Add isStatic prop definition --- .../src/astro-components/control/Protect.astro | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index fe4632fc575..0de0d90a83d 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -6,6 +6,20 @@ import { isStaticOutput } from "virtual:@clerk/astro/config"; import type { ProtectProps } from '../../types'; type Props = ProtectProps & { + /** + * Determines whether the component should render for static or server output. + * + * - Set to `true` for static/prerendered output + * - Set to `false` for server-side rendering + * + * In Astro's hybrid mode: + * - If not specified, defaults to `true` (pages are prerendered by default) + * - Can be explicitly set to override the default behavior + * + * In static or server-only output modes: + * - If specified, it will override the default output behavior + * - If not specified, it follows the project's output mode + */ isStatic?: boolean } From 85e257a31cf4a83b28a77bc595829dd778f678dd Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 14:42:34 -0700 Subject: [PATCH 63/85] chore(astro): Revert previous commit --- .../src/astro-components/control/Protect.astro | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index 0de0d90a83d..fe4632fc575 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -6,20 +6,6 @@ import { isStaticOutput } from "virtual:@clerk/astro/config"; import type { ProtectProps } from '../../types'; type Props = ProtectProps & { - /** - * Determines whether the component should render for static or server output. - * - * - Set to `true` for static/prerendered output - * - Set to `false` for server-side rendering - * - * In Astro's hybrid mode: - * - If not specified, defaults to `true` (pages are prerendered by default) - * - Can be explicitly set to override the default behavior - * - * In static or server-only output modes: - * - If specified, it will override the default output behavior - * - If not specified, it follows the project's output mode - */ isStatic?: boolean } From 42a830b0843a3ab92faaa5b01d65a896b804fb47 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 15:23:45 -0700 Subject: [PATCH 64/85] chore(astro): type fixes --- packages/astro/src/integration/vite-plugin-astro-config.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 00d20446312..716b7db98de 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -1,11 +1,8 @@ import type { AstroConfig } from 'astro'; -import type { ViteUserConfig } from 'astro/config'; -type ExtractPluginOption = T extends (infer U)[] ? U : never; +type VitePlugin = Required['plugins'][number]; -export function vitePluginAstroConfig( - astroConfig: AstroConfig, -): ExtractPluginOption> { +export function vitePluginAstroConfig(astroConfig: AstroConfig): VitePlugin { const virtualModuleId = 'virtual:@clerk/astro/config'; const resolvedVirtualModuleId = '\0' + virtualModuleId; From 0ee00fff12f86173c32ec3edf2347c7b277e03d8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 16 Aug 2024 21:42:45 -0700 Subject: [PATCH 65/85] chore(astro): Put web component declarations inside CSR components --- integration/presets/astro.ts | 5 +- .../astro-components/control/ProtectCSR.astro | 47 +++++++++++++++++++ .../control/SignedInCSR.astro | 32 +++++++++++++ .../control/SignedOutCSR.astro | 32 +++++++++++++ .../src/internal/create-clerk-instance.ts | 2 - .../src/internal/custom-elements/protect.ts | 43 ----------------- .../src/internal/custom-elements/signed-in.ts | 27 ----------- .../internal/custom-elements/signed-out.ts | 27 ----------- .../src/internal/define-custom-elements.ts | 17 ------- 9 files changed, 115 insertions(+), 117 deletions(-) delete mode 100644 packages/astro/src/internal/custom-elements/protect.ts delete mode 100644 packages/astro/src/internal/custom-elements/signed-in.ts delete mode 100644 packages/astro/src/internal/custom-elements/signed-out.ts delete mode 100644 packages/astro/src/internal/define-custom-elements.ts diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 7ac64acf87c..0fb76fed334 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -9,7 +9,10 @@ const astroNode = applicationConfig() .setName('astro-node') .useTemplate(templates['astro-node']) .setEnvFormatter('public', key => `PUBLIC_${key}`) - .addScript('setup', 'npm i') + // Creating symlinks causes the Astro vite plugin to fail. + // Without `--install-link`, it throws this error: + // https://github.com/withastro/astro/blob/cb98b74881355de9ec9d90a613a3f1d27d154463/packages/astro/src/vite-plugin-astro/index.ts#L114 + .addScript('setup', 'npm i --install-links') .addScript('dev', 'npm run dev') .addScript('build', 'npm run build') .addScript('serve', 'npm run preview') diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 6843b001475..b0bc61bcdda 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -17,3 +17,50 @@ const { role, permission } = Astro.props;
+ + diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro index 2aa71220340..91b53182ad0 100644 --- a/packages/astro/src/astro-components/control/SignedInCSR.astro +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -1,3 +1,35 @@ + + diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro index bfac0dec438..5ea684d216e 100644 --- a/packages/astro/src/astro-components/control/SignedOutCSR.astro +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -1,3 +1,35 @@ + + diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index 2b3be0566db..6d64083b90b 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -3,7 +3,6 @@ import type { ClerkOptions } from '@clerk/types'; import { $clerk, $csrState } from '../stores/internal'; import type { AstroClerkCreateInstanceParams, AstroClerkUpdateOptions } from '../types'; -import { defineCustomElements } from './define-custom-elements'; import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions'; import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components'; import { runOnce } from './run-once'; @@ -57,7 +56,6 @@ async function createClerkInstanceInternal(options?: AstroClerkCreateInstancePar mountAllClerkAstroJSComponents(); invokeClerkAstroJSFunctions(); - void defineCustomElements(); clerkJSInstance.addListener(payload => { $csrState.setKey('client', payload.client); diff --git a/packages/astro/src/internal/custom-elements/protect.ts b/packages/astro/src/internal/custom-elements/protect.ts deleted file mode 100644 index 430a3716636..00000000000 --- a/packages/astro/src/internal/custom-elements/protect.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { CheckAuthorization } from '@clerk/types'; - -import { $authStore, $sessionStore } from '../../stores/external'; - -export class Protect extends HTMLElement { - private defaultSlot: HTMLDivElement | null = null; - private fallbackSlot: HTMLDivElement | null = null; - private authStoreListener: (() => void) | null = null; - - constructor() { - super(); - } - - connectedCallback() { - this.toggleContentVisibility(); - } - - disconnectedCallback() { - this.authStoreListener?.(); - } - - toggleContentVisibility() { - this.defaultSlot = this.querySelector('[data-clerk-control-slot-default]'); - this.fallbackSlot = this.querySelector('[data-clerk-control-slot-fallback]'); - - this.authStoreListener = $authStore.subscribe(state => { - const has = $sessionStore.get()?.checkAuthorization; - - const role = this.dataset.role; - const permission = this.dataset.permission; - const isUnauthorized = - !state.userId || ((role || permission) && !has?.({ role, permission } as Parameters[0])); - - if (this.defaultSlot) { - isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden'); - } - - if (this.fallbackSlot) { - isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', ''); - } - }); - } -} diff --git a/packages/astro/src/internal/custom-elements/signed-in.ts b/packages/astro/src/internal/custom-elements/signed-in.ts deleted file mode 100644 index 82f339f839a..00000000000 --- a/packages/astro/src/internal/custom-elements/signed-in.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { $authStore } from '../../stores/external'; - -export class SignedIn extends HTMLElement { - private authStoreListener: (() => void) | null = null; - - constructor() { - super(); - } - - connectedCallback() { - this.toggleContentVisibility(); - } - - disconnectedCallback() { - this.authStoreListener?.(); - } - - toggleContentVisibility() { - this.authStoreListener = $authStore.subscribe(state => { - if (state.userId) { - this.removeAttribute('hidden'); - } else { - this.setAttribute('hidden', ''); - } - }); - } -} diff --git a/packages/astro/src/internal/custom-elements/signed-out.ts b/packages/astro/src/internal/custom-elements/signed-out.ts deleted file mode 100644 index 1281ed65b90..00000000000 --- a/packages/astro/src/internal/custom-elements/signed-out.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { $authStore } from '../../stores/external'; - -export class SignedOut extends HTMLElement { - private authStoreListener: (() => void) | null = null; - - constructor() { - super(); - } - - connectedCallback() { - this.toggleContentVisibility(); - } - - disconnectedCallback() { - this.authStoreListener?.(); - } - - toggleContentVisibility() { - this.authStoreListener = $authStore.subscribe(state => { - if (state.userId) { - this.setAttribute('hidden', ''); - } else { - this.removeAttribute('hidden'); - } - }); - } -} diff --git a/packages/astro/src/internal/define-custom-elements.ts b/packages/astro/src/internal/define-custom-elements.ts deleted file mode 100644 index 863918d4013..00000000000 --- a/packages/astro/src/internal/define-custom-elements.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Defines custom elements for Clerk CSR control components. - * - * @example - * - * Content for signed-in users - */ -export async function defineCustomElements() { - const [{ SignedIn }, { SignedOut }, { Protect }] = await Promise.all([ - import('./custom-elements/signed-in'), - import('./custom-elements/signed-out'), - import('./custom-elements/protect'), - ]); - window.customElements.define('clerk-signed-in', SignedIn); - window.customElements.define('clerk-signed-out', SignedOut); - window.customElements.define('clerk-protect', Protect); -} From edad85356299b3068efb2f25135df6280f756ee0 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Sat, 17 Aug 2024 18:45:05 -0700 Subject: [PATCH 66/85] chore(astro): Fix flickering when rendering signed in and signed out contents --- .../control/BaseClerkControlElement.ts | 35 +++++++++++++++ .../astro-components/control/ProtectCSR.astro | 44 +++++++------------ .../control/SignedInCSR.astro | 32 ++++---------- .../control/SignedOutCSR.astro | 32 ++++---------- packages/astro/src/stores/external.ts | 10 +++++ 5 files changed, 76 insertions(+), 77 deletions(-) create mode 100644 packages/astro/src/astro-components/control/BaseClerkControlElement.ts diff --git a/packages/astro/src/astro-components/control/BaseClerkControlElement.ts b/packages/astro/src/astro-components/control/BaseClerkControlElement.ts new file mode 100644 index 00000000000..f992af25978 --- /dev/null +++ b/packages/astro/src/astro-components/control/BaseClerkControlElement.ts @@ -0,0 +1,35 @@ +import { $authStore, $isLoadedStore } from '@clerk/astro/client'; + +export type AuthState = ReturnType; + +export class BaseClerkControlElement extends HTMLElement { + protected authStoreListener: (() => void) | null = null; + protected isLoadedStoreListener: (() => void) | null = null; + + constructor() { + super(); + } + + connectedCallback() { + this.isLoadedStoreListener = $isLoadedStore.subscribe(loaded => { + if (loaded) { + this.toggleContentVisibility(); + } + }); + } + + disconnectedCallback() { + this.authStoreListener?.(); + this.isLoadedStoreListener?.(); + } + + toggleContentVisibility() { + this.authStoreListener = $authStore.subscribe(state => { + this.onAuthStateChange(state); + }); + } + + // This method will be overridden by subclasses + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected onAuthStateChange(state: AuthState): void {} +} diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index b0bc61bcdda..f2efcb00703 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -19,46 +19,32 @@ const { role, permission } = Astro.props; + + diff --git a/packages/astro/src/astro-components/control/SignedInCSR.astro b/packages/astro/src/astro-components/control/SignedInCSR.astro index f73aa0a87f1..16deb42511b 100644 --- a/packages/astro/src/astro-components/control/SignedInCSR.astro +++ b/packages/astro/src/astro-components/control/SignedInCSR.astro @@ -17,3 +17,9 @@ class ClerkSignedIn extends BaseClerkControlElement { customElements.define('clerk-signed-in', ClerkSignedIn); + + diff --git a/packages/astro/src/astro-components/control/SignedOutCSR.astro b/packages/astro/src/astro-components/control/SignedOutCSR.astro index 91e15a76bde..517bc4c2b33 100644 --- a/packages/astro/src/astro-components/control/SignedOutCSR.astro +++ b/packages/astro/src/astro-components/control/SignedOutCSR.astro @@ -17,3 +17,9 @@ class ClerkSignedOut extends BaseClerkControlElement { customElements.define('clerk-signed-out', ClerkSignedOut); + + From e2f82791c5e546f592e7251f71937cec469d0010 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 19 Aug 2024 09:04:26 -0700 Subject: [PATCH 73/85] chore(astro): Make sure hidden attributes are not overridable in protect csr --- .../astro/src/astro-components/control/ProtectCSR.astro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index b1c64a270f0..736e17a97cc 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -10,10 +10,10 @@ const { role, permission } = Astro.props; data-role={role} data-permission={permission} > -
+ -
+ @@ -52,7 +52,7 @@ customElements.define('clerk-protect', ClerkProtect); From 24df6dfe08e1eb5930409d962c106d3ea4a6452a Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 19 Aug 2024 12:48:22 -0700 Subject: [PATCH 74/85] test(astro): Fix protect CSR tests --- .../src/pages/{protected.astro => only-admins.astro} | 0 .../astro-static/src/pages/only-members.astro | 11 +++++++++++ integration/tests/astro/static.test.ts | 10 +++++----- 3 files changed, 16 insertions(+), 5 deletions(-) rename integration/templates/astro-static/src/pages/{protected.astro => only-admins.astro} (100%) create mode 100644 integration/templates/astro-static/src/pages/only-members.astro diff --git a/integration/templates/astro-static/src/pages/protected.astro b/integration/templates/astro-static/src/pages/only-admins.astro similarity index 100% rename from integration/templates/astro-static/src/pages/protected.astro rename to integration/templates/astro-static/src/pages/only-admins.astro diff --git a/integration/templates/astro-static/src/pages/only-members.astro b/integration/templates/astro-static/src/pages/only-members.astro new file mode 100644 index 00000000000..b54ed1b706d --- /dev/null +++ b/integration/templates/astro-static/src/pages/only-members.astro @@ -0,0 +1,11 @@ +--- +import { Protect } from "@clerk/astro/components"; +import Layout from "../layouts/Layout.astro"; +--- + + + +

I'm a member

+

Not a member

+
+
diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index b490b78bc9f..8e34c8db13b 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -69,12 +69,12 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await u.po.organizationSwitcher.waitForMounted(); await u.po.organizationSwitcher.waitForAnOrganizationToSelected(); - await u.page.goToRelative('/protected'); + await u.page.goToRelative('/only-admins'); await expect(u.page.getByText("I'm an admin")).toBeVisible(); }); - test('render Protect fallback for non-admins', async ({ page, context }) => { + test('render Protect fallback', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); @@ -83,12 +83,12 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( // Sign in await u.page.getByRole('button', { name: /Sign in/i }).click(); await u.po.signIn.waitForMounted(); - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin2.email, password: fakeAdmin2.password }); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); await u.po.expect.toBeSignedIn(); - await u.page.goToRelative('/protected'); + await u.page.goToRelative('/only-members'); - await expect(u.page.getByText('Not an admin')).toBeVisible(); + await expect(u.page.getByText("Not a member")).toBeVisible(); }); }, ); From 0ae12489a0d444fe4baca83a3af5c5fc65fc58db Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 19 Aug 2024 12:53:01 -0700 Subject: [PATCH 75/85] chore(astro): Formatting fix --- integration/tests/astro/static.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/static.test.ts index 8e34c8db13b..79b5379fe49 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/static.test.ts @@ -88,7 +88,7 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await u.page.goToRelative('/only-members'); - await expect(u.page.getByText("Not a member")).toBeVisible(); + await expect(u.page.getByText('Not a member')).toBeVisible(); }); }, ); From 506bce7aa6ec738a727691da4176473509adf629 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 19 Aug 2024 19:23:39 -0700 Subject: [PATCH 76/85] chore(astro): Remove unused util file --- packages/astro/src/stores/utils.ts | 78 ------------------------------ 1 file changed, 78 deletions(-) delete mode 100644 packages/astro/src/stores/utils.ts diff --git a/packages/astro/src/stores/utils.ts b/packages/astro/src/stores/utils.ts deleted file mode 100644 index efb6aadef9f..00000000000 --- a/packages/astro/src/stores/utils.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { - ActiveSessionResource, - InitialState, - OrganizationCustomPermissionKey, - OrganizationCustomRoleKey, - OrganizationResource, - Resources, - UserResource, -} from '@clerk/types'; - -export function deriveState(clerkLoaded: boolean, state: Resources, initialState: InitialState | undefined) { - if (!clerkLoaded && initialState) { - return { - ...deriveFromSsrInitialState(initialState), - clerkLoaded, - }; - } - - return { - ...deriveFromClientSideState(state), - clerkLoaded, - }; -} - -function deriveFromSsrInitialState(initialState: InitialState) { - const userId = initialState.userId; - const user = initialState.user as any as UserResource; - const sessionId = initialState.sessionId; - const session = initialState.session as any as ActiveSessionResource; - const organization = initialState.organization as any as OrganizationResource; - const orgId = initialState.orgId; - const orgRole = initialState.orgRole as OrganizationCustomRoleKey; - const orgPermissions = initialState.orgPermissions as OrganizationCustomPermissionKey[]; - const orgSlug = initialState.orgSlug; - const actor = initialState.actor; - - return { - userId, - user, - sessionId, - session, - organization, - orgId, - orgRole, - orgPermissions, - orgSlug, - actor, - }; -} - -function deriveFromClientSideState(state: Resources) { - const userId: string | null | undefined = state.user ? state.user.id : state.user; - const user = state.user; - const sessionId: string | null | undefined = state.session ? state.session.id : state.session; - const session = state.session; - const actor = session?.actor; - const organization = state.organization; - const orgId: string | null | undefined = state.organization ? state.organization.id : state.organization; - const orgSlug = organization?.slug; - const membership = organization - ? user?.organizationMemberships?.find(om => om.organization.id === orgId) - : organization; - const orgPermissions = membership ? membership.permissions : membership; - const orgRole = membership ? membership.role : membership; - - return { - userId, - user, - sessionId, - session, - organization, - orgId, - orgRole, - orgSlug, - orgPermissions, - actor, - }; -} From 17a4abb35aa1637e804db11f22d6c671c8bfaac1 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 19 Aug 2024 19:41:45 -0700 Subject: [PATCH 77/85] chore(astro): Set initial resource values to undefined --- packages/astro/src/stores/internal.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/stores/internal.ts b/packages/astro/src/stores/internal.ts index 2ac76f464f0..d9ea37d6902 100644 --- a/packages/astro/src/stores/internal.ts +++ b/packages/astro/src/stores/internal.ts @@ -16,10 +16,10 @@ export const $csrState = map<{ organization: OrganizationResource | undefined | null; }>({ isLoaded: false, - client: null, - user: null, - session: null, - organization: null, + client: undefined, + user: undefined, + session: undefined, + organization: undefined, }); export const $initialState = map(); From a188cc84e2dd7b34fa5d72beffa0ba8228f46db7 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 08:27:26 -0700 Subject: [PATCH 78/85] chore(astro): Ignore ts files in components folder --- packages/astro/package.json | 2 +- packages/astro/src/astro-components/index.ts | 5 +++++ .../src/astro-components/interactive/UserButton/index.ts | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index 249b17431bc..eab621b38eb 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -28,7 +28,7 @@ }, "scripts": { "dev": "tsup --watch --onSuccess \"npm run build:dts\"", - "build": "tsup && npm run copy:components", + "build": "tsup --onSuccess \"npm run build:dts\" && npm run copy:components", "build:dts": "tsc --emitDeclarationOnly --declaration", "copy:components": "rm -rf ./components && mkdir -p ./components/ && cp -r ./src/astro-components/* ./components/ && cp ./src/types.ts ./", "lint": "eslint src/", diff --git a/packages/astro/src/astro-components/index.ts b/packages/astro/src/astro-components/index.ts index e78da856ec3..8c808239ec6 100644 --- a/packages/astro/src/astro-components/index.ts +++ b/packages/astro/src/astro-components/index.ts @@ -1,3 +1,8 @@ +// @ts-nocheck +// We're using @ts-nocheck here because this file gets copied to the dist folder +// when published and is not bundled with tsup. This can cause TS to throw errors +// even though we're not bundling it. + /** * Control Components */ diff --git a/packages/astro/src/astro-components/interactive/UserButton/index.ts b/packages/astro/src/astro-components/interactive/UserButton/index.ts index 10f83b9f0e9..e0d118b2832 100644 --- a/packages/astro/src/astro-components/interactive/UserButton/index.ts +++ b/packages/astro/src/astro-components/interactive/UserButton/index.ts @@ -1,3 +1,8 @@ +// @ts-nocheck +// We're using @ts-nocheck here because this file gets copied to the dist folder +// when published and is not bundled with tsup. This can cause TS to throw errors +// even though we're not bundling it. + import _UserButton from './UserButton.astro'; import UserButtonLink from './UserButtonLink.astro'; import UserButtonAction from './UserButtonAction.astro'; From db66adc0b739f7d343b62e8a9c0fb864f04abfde Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 08:39:58 -0700 Subject: [PATCH 79/85] chore(astro): TS errors clean up --- packages/astro/src/astro-components/index.ts | 5 ----- .../astro-components/interactive/UserButton/index.ts | 5 ----- packages/astro/tsconfig.json | 11 ++++++++++- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/astro/src/astro-components/index.ts b/packages/astro/src/astro-components/index.ts index 8c808239ec6..e78da856ec3 100644 --- a/packages/astro/src/astro-components/index.ts +++ b/packages/astro/src/astro-components/index.ts @@ -1,8 +1,3 @@ -// @ts-nocheck -// We're using @ts-nocheck here because this file gets copied to the dist folder -// when published and is not bundled with tsup. This can cause TS to throw errors -// even though we're not bundling it. - /** * Control Components */ diff --git a/packages/astro/src/astro-components/interactive/UserButton/index.ts b/packages/astro/src/astro-components/interactive/UserButton/index.ts index e0d118b2832..10f83b9f0e9 100644 --- a/packages/astro/src/astro-components/interactive/UserButton/index.ts +++ b/packages/astro/src/astro-components/interactive/UserButton/index.ts @@ -1,8 +1,3 @@ -// @ts-nocheck -// We're using @ts-nocheck here because this file gets copied to the dist folder -// when published and is not bundled with tsup. This can cause TS to throw errors -// even though we're not bundling it. - import _UserButton from './UserButton.astro'; import UserButtonLink from './UserButtonLink.astro'; import UserButtonAction from './UserButtonAction.astro'; diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index ce451941228..5195b6cd524 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -24,5 +24,14 @@ "declarationDir": "dist/types", "noUncheckedIndexedAccess": true }, - "exclude": ["dist", "build", "node_modules"] + "exclude": [ + "dist", + "build", + "node_modules", + // We're ignoring the files below because they are published and is not processed/bundled with tsup. + // This cause TS to throw errors even though we're not bundling it. + "src/astro-components/index.ts", + "src/astro-components/interactive/UserButton/index.ts", + "src/astro-components/control/BaseClerkControlElement.ts", + ] } From 0b65ac6e1ed50fe893f9f0597131e62e51a45415 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 08:53:25 -0700 Subject: [PATCH 80/85] test(astro): Update static test to hybrid --- integration/presets/astro.ts | 2 +- .../{astro-static => astro-hybrid}/.gitignore | 0 .../astro.config.mjs | 2 +- .../package.json | 3 ++- .../public/favicon.svg | 0 .../src/layouts/Layout.astro | 0 .../templates/astro-hybrid/src/middleware.ts | 3 +++ .../src/pages/index.astro | 2 ++ .../src/pages/only-admins.astro | 2 ++ .../src/pages/only-members.astro | 4 +++- .../astro-hybrid/src/pages/ssr.astro | 19 ++++++++++++++++ .../tsconfig.json | 0 integration/templates/index.ts | 2 +- .../astro/{static.test.ts => hybrid.test.ts} | 22 ++++++++++++++++++- packages/astro/tsconfig.json | 2 +- 15 files changed, 56 insertions(+), 7 deletions(-) rename integration/templates/{astro-static => astro-hybrid}/.gitignore (100%) rename integration/templates/{astro-static => astro-hybrid}/astro.config.mjs (92%) rename integration/templates/{astro-static => astro-hybrid}/package.json (86%) rename integration/templates/{astro-static => astro-hybrid}/public/favicon.svg (100%) rename integration/templates/{astro-static => astro-hybrid}/src/layouts/Layout.astro (100%) create mode 100644 integration/templates/astro-hybrid/src/middleware.ts rename integration/templates/{astro-static => astro-hybrid}/src/pages/index.astro (93%) rename integration/templates/{astro-static => astro-hybrid}/src/pages/only-admins.astro (89%) rename integration/templates/{astro-static => astro-hybrid}/src/pages/only-members.astro (73%) create mode 100644 integration/templates/astro-hybrid/src/pages/ssr.astro rename integration/templates/{astro-static => astro-hybrid}/tsconfig.json (100%) rename integration/tests/astro/{static.test.ts => hybrid.test.ts} (78%) diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 9c936b3d9f1..5b1bb70ec84 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -20,7 +20,7 @@ const astroNode = applicationConfig() .addDependency('@clerk/types', clerkTypesLocal) .addDependency('@clerk/localizations', clerkLocalizationLocal); -const astroStatic = astroNode.clone().setName('astro-static').useTemplate(templates['astro-static']); +const astroStatic = astroNode.clone().setName('astro-hybrid').useTemplate(templates['astro-hybrid']); export const astro = { node: astroNode, diff --git a/integration/templates/astro-static/.gitignore b/integration/templates/astro-hybrid/.gitignore similarity index 100% rename from integration/templates/astro-static/.gitignore rename to integration/templates/astro-hybrid/.gitignore diff --git a/integration/templates/astro-static/astro.config.mjs b/integration/templates/astro-hybrid/astro.config.mjs similarity index 92% rename from integration/templates/astro-static/astro.config.mjs rename to integration/templates/astro-hybrid/astro.config.mjs index edb485f482e..30ff739e8a3 100644 --- a/integration/templates/astro-static/astro.config.mjs +++ b/integration/templates/astro-hybrid/astro.config.mjs @@ -3,7 +3,7 @@ import clerk from '@clerk/astro'; import react from '@astrojs/react'; export default defineConfig({ - output: 'static', + output: 'hybrid', integrations: [clerk(), react()], server: { port: Number(process.env.PORT), diff --git a/integration/templates/astro-static/package.json b/integration/templates/astro-hybrid/package.json similarity index 86% rename from integration/templates/astro-static/package.json rename to integration/templates/astro-hybrid/package.json index 2a82d5ff254..e5600f80bb0 100644 --- a/integration/templates/astro-static/package.json +++ b/integration/templates/astro-hybrid/package.json @@ -1,5 +1,5 @@ { - "name": "astro-clerk-static-playground", + "name": "astro-clerk-hybrid-playground", "type": "module", "version": "0.0.1", "scripts": { @@ -12,6 +12,7 @@ "dependencies": { "@astrojs/check": "^0.7.0", "@astrojs/react": "^3.6.0", + "@astrojs/node": "^8.3.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "astro": "^4.11.5", diff --git a/integration/templates/astro-static/public/favicon.svg b/integration/templates/astro-hybrid/public/favicon.svg similarity index 100% rename from integration/templates/astro-static/public/favicon.svg rename to integration/templates/astro-hybrid/public/favicon.svg diff --git a/integration/templates/astro-static/src/layouts/Layout.astro b/integration/templates/astro-hybrid/src/layouts/Layout.astro similarity index 100% rename from integration/templates/astro-static/src/layouts/Layout.astro rename to integration/templates/astro-hybrid/src/layouts/Layout.astro diff --git a/integration/templates/astro-hybrid/src/middleware.ts b/integration/templates/astro-hybrid/src/middleware.ts new file mode 100644 index 00000000000..cd6f0baf9d5 --- /dev/null +++ b/integration/templates/astro-hybrid/src/middleware.ts @@ -0,0 +1,3 @@ +import { clerkMiddleware } from '@clerk/astro/server'; + +export const onRequest = clerkMiddleware(); diff --git a/integration/templates/astro-static/src/pages/index.astro b/integration/templates/astro-hybrid/src/pages/index.astro similarity index 93% rename from integration/templates/astro-static/src/pages/index.astro rename to integration/templates/astro-hybrid/src/pages/index.astro index 328a68923ae..b13e67a0a46 100644 --- a/integration/templates/astro-static/src/pages/index.astro +++ b/integration/templates/astro-hybrid/src/pages/index.astro @@ -2,6 +2,8 @@ import { UserButton, SignInButton, SignedIn, SignedOut } from "@clerk/astro/components"; import { OrganizationSwitcher } from "@clerk/astro/react"; import Layout from "../layouts/Layout.astro"; + +export const prerender = true; --- diff --git a/integration/templates/astro-static/src/pages/only-admins.astro b/integration/templates/astro-hybrid/src/pages/only-admins.astro similarity index 89% rename from integration/templates/astro-static/src/pages/only-admins.astro rename to integration/templates/astro-hybrid/src/pages/only-admins.astro index 7ba88903bfd..14465c76c80 100644 --- a/integration/templates/astro-static/src/pages/only-admins.astro +++ b/integration/templates/astro-hybrid/src/pages/only-admins.astro @@ -1,6 +1,8 @@ --- import { Protect } from "@clerk/astro/components"; import Layout from "../layouts/Layout.astro"; + +export const prerender = true; --- diff --git a/integration/templates/astro-static/src/pages/only-members.astro b/integration/templates/astro-hybrid/src/pages/only-members.astro similarity index 73% rename from integration/templates/astro-static/src/pages/only-members.astro rename to integration/templates/astro-hybrid/src/pages/only-members.astro index b54ed1b706d..70eac5ff274 100644 --- a/integration/templates/astro-static/src/pages/only-members.astro +++ b/integration/templates/astro-hybrid/src/pages/only-members.astro @@ -1,10 +1,12 @@ --- import { Protect } from "@clerk/astro/components"; import Layout from "../layouts/Layout.astro"; + +export const prerender = false; --- - +

I'm a member

Not a member

diff --git a/integration/templates/astro-hybrid/src/pages/ssr.astro b/integration/templates/astro-hybrid/src/pages/ssr.astro new file mode 100644 index 00000000000..b0ad0b253ef --- /dev/null +++ b/integration/templates/astro-hybrid/src/pages/ssr.astro @@ -0,0 +1,19 @@ +--- +import { UserButton, SignInButton, SignedIn, SignedOut } from "@clerk/astro/components"; +import { OrganizationSwitcher } from "@clerk/astro/react"; +import Layout from "../layouts/Layout.astro"; + +export const prerender = false; +--- + + + +

Signed out

+ +
+ +

Signed in

+ + +
+
diff --git a/integration/templates/astro-static/tsconfig.json b/integration/templates/astro-hybrid/tsconfig.json similarity index 100% rename from integration/templates/astro-static/tsconfig.json rename to integration/templates/astro-hybrid/tsconfig.json diff --git a/integration/templates/index.ts b/integration/templates/index.ts index 3a122120827..791590c666f 100644 --- a/integration/templates/index.ts +++ b/integration/templates/index.ts @@ -12,7 +12,7 @@ export const templates = { 'remix-node': resolve(__dirname, './remix-node'), 'elements-next': resolve(__dirname, './elements-next'), 'astro-node': resolve(__dirname, './astro-node'), - 'astro-static': resolve(__dirname, './astro-static'), + 'astro-hybrid': resolve(__dirname, './astro-hybrid'), 'expo-web': resolve(__dirname, './expo-web'), } as const; diff --git a/integration/tests/astro/static.test.ts b/integration/tests/astro/hybrid.test.ts similarity index 78% rename from integration/tests/astro/static.test.ts rename to integration/tests/astro/hybrid.test.ts index 79b5379fe49..3eb48f361a4 100644 --- a/integration/tests/astro/static.test.ts +++ b/integration/tests/astro/hybrid.test.ts @@ -33,7 +33,7 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await app.teardown(); }); - test('render SignedIn and SignedOut contents', async ({ page, context }) => { + test('render SignedIn and SignedOut contents (prerendered)', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); @@ -53,6 +53,26 @@ testAgainstRunningApps({ withPattern: ['astro.static.withCustomRoles'] })( await expect(u.page.getByText('Signed in')).toBeVisible(); }); + test('render SignedIn and SignedOut contents (SSR)', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + await u.page.goToRelative('/ssr'); + + await u.page.waitForClerkJsLoaded(); + + await u.po.expect.toBeSignedOut(); + await expect(u.page.getByText('Signed out')).toBeVisible(); + await expect(u.page.getByText('Signed in')).toBeHidden(); + + await u.page.getByRole('button', { name: /Sign in/i }).click(); + + await u.po.signIn.waitForMounted(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password }); + await u.po.expect.toBeSignedIn(); + + await expect(u.page.getByText('Signed out')).toBeHidden(); + await expect(u.page.getByText('Signed in')).toBeVisible(); + }); + test('render Protect contents for admin', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); await u.page.goToAppHome(); diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index 5195b6cd524..53f93c5e747 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -32,6 +32,6 @@ // This cause TS to throw errors even though we're not bundling it. "src/astro-components/index.ts", "src/astro-components/interactive/UserButton/index.ts", - "src/astro-components/control/BaseClerkControlElement.ts", + "src/astro-components/control/BaseClerkControlElement.ts" ] } From 6e1beeb6f65772a4e49ddcc88adda6b10a6f0507 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 09:01:03 -0700 Subject: [PATCH 81/85] chore(astro): Update eslint ignores --- packages/astro/.eslintrc.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/.eslintrc.cjs b/packages/astro/.eslintrc.cjs index 7288f46d3b7..84bc665e0e0 100644 --- a/packages/astro/.eslintrc.cjs +++ b/packages/astro/.eslintrc.cjs @@ -4,7 +4,7 @@ module.exports = { rules: { 'import/no-unresolved': ['error', { ignore: ['^#'] }], }, - ignorePatterns: ['src/astro-components/index.ts', 'src/astro-components/interactive/UserButton/index.ts'], + ignorePatterns: ['src/astro-components/**/*.ts'], overrides: [ { files: ['./env.d.ts'], From eb0647c7b7584e0e55ed2773cc0642aea111a238 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 09:04:23 -0700 Subject: [PATCH 82/85] chore(astro): Simplify ignored files in tsconfig --- packages/astro/tsconfig.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index 53f93c5e747..96527b31b53 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -30,8 +30,6 @@ "node_modules", // We're ignoring the files below because they are published and is not processed/bundled with tsup. // This cause TS to throw errors even though we're not bundling it. - "src/astro-components/index.ts", - "src/astro-components/interactive/UserButton/index.ts", - "src/astro-components/control/BaseClerkControlElement.ts" + "src/astro-components/**/*.ts" ] } From fa723e4eaae823b6b50f0f15b506f27465630d8b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 09:07:29 -0700 Subject: [PATCH 83/85] chore(astro): Add JSDoc to vite plugin --- packages/astro/src/integration/vite-plugin-astro-config.ts | 7 +++++++ packages/astro/tsconfig.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/integration/vite-plugin-astro-config.ts b/packages/astro/src/integration/vite-plugin-astro-config.ts index 716b7db98de..f9505aeb580 100644 --- a/packages/astro/src/integration/vite-plugin-astro-config.ts +++ b/packages/astro/src/integration/vite-plugin-astro-config.ts @@ -2,6 +2,13 @@ import type { AstroConfig } from 'astro'; type VitePlugin = Required['plugins'][number]; +/** + * This Vite module exports a `isStaticOutput` function that is imported inside our control components + * to determine which components to use depending on the Astro config output option. + * + * @param {AstroConfig} astroConfig - The Astro configuration object + * @returns {VitePlugin} A Vite plugin + */ export function vitePluginAstroConfig(astroConfig: AstroConfig): VitePlugin { const virtualModuleId = 'virtual:@clerk/astro/config'; const resolvedVirtualModuleId = '\0' + virtualModuleId; diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index 96527b31b53..514256274a8 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -28,7 +28,7 @@ "dist", "build", "node_modules", - // We're ignoring the files below because they are published and is not processed/bundled with tsup. + // We're ignoring the files below because they are published as-is and is not processed/bundled with tsup. // This cause TS to throw errors even though we're not bundling it. "src/astro-components/**/*.ts" ] From 7f20b125f9497f6e9038bfb3f72b7ba09d6e3594 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 21 Aug 2024 11:32:44 -0700 Subject: [PATCH 84/85] chore(astro): Add classes to control components wrappers --- .../astro-components/control/Protect.astro | 15 +++++++++++++++ .../astro-components/control/ProtectCSR.astro | 19 +++++++++---------- .../astro-components/control/SignedIn.astro | 11 +++++++++-- .../control/SignedInCSR.astro | 16 +++++++++------- .../astro-components/control/SignedOut.astro | 13 ++++++++++--- .../control/SignedOutCSR.astro | 16 +++++++++------- 6 files changed, 61 insertions(+), 29 deletions(-) diff --git a/packages/astro/src/astro-components/control/Protect.astro b/packages/astro/src/astro-components/control/Protect.astro index fe4632fc575..e1ccd138c31 100644 --- a/packages/astro/src/astro-components/control/Protect.astro +++ b/packages/astro/src/astro-components/control/Protect.astro @@ -7,6 +7,21 @@ import type { ProtectProps } from '../../types'; type Props = ProtectProps & { isStatic?: boolean + /** + * The class name to apply to the outermost element of the component. + * This class is only applied to static components. + */ + class?: string; + /** + * The class name to apply to the wrapper element of the default slot. + * This class is only applied to static components. + */ + defaultSlotWrapperClass?: string; + /** + * The class name to apply to the wrapper element of the fallback slot. + * This class is only applied to static components. + */ + fallbackSlotWrapperClass?: string; } const { isStatic, ...props } = Astro.props; diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 736e17a97cc..18a02b18128 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -1,19 +1,24 @@ --- import type { ProtectProps } from '../../types'; -type Props = Omit; +type Props = Omit & { + class?: string; + defaultSlotWrapperClass?: string; + fallbackSlotWrapperClass?: string; +}; -const { role, permission } = Astro.props; +const { role, permission, class: className, defaultSlotWrapperClass, fallbackSlotWrapperClass } = Astro.props; --- -