Skip to content

Commit 06fb6a4

Browse files
committed
chore(ui,astro): improve error handling, build config, and code organization
UI Package Updates: - Enhanced billing error handling in CheckoutPage by properly flattening ClerkAPIResponseErrors to extract error codes - Updated InvalidPlanScreen to correctly filter and extract errors from ClerkAPIResponseErrors before checking for invalid_plan_change - Removed unused imports from OrganizationProfile components - Simplified SignUpStart appearance usage - Added type-check script to package.json - Updated tsconfig to exclude __tests__ directories - Enhanced rspack dev config with better source maps and disabled tree shaking for easier debugging - Added __BUILD_DISABLE_RHC__ constant to both rspack and tsdown configs Astro Package Updates: - Refactored createClerkInstance to extract clerk-js and clerk-ui loading into separate functions (getClerkJsEntryChunk, getClerkUiEntryChunk) - Improved code clarity with better comments explaining early returns when scripts are already loaded via middleware - Maintained parallel loading of both scripts for optimal performance Root Package Updates: - Added E2E_DEBUG=1 to billing, generic, and machine integration test scripts for better debugging visibility - Updated billing test to use withBillingJwtV2 instead of withBilling - Fixed duplicate E2E_DEBUG flag in express test script
1 parent eec60c7 commit 06fb6a4

File tree

10 files changed

+63
-36
lines changed

10 files changed

+63
-36
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@
3434
"test:integration:ap-flows": "pnpm test:integration:base --grep @ap-flows",
3535
"test:integration:astro": "E2E_APP_ID=astro.* pnpm test:integration:base --grep @astro",
3636
"test:integration:base": "pnpm playwright test --config integration/playwright.config.ts",
37-
"test:integration:billing": "E2E_APP_ID=withBilling.* pnpm test:integration:base --grep @billing",
37+
"test:integration:billing": "E2E_DEBUG=1 E2E_APP_ID=withBillingJwtV2.* pnpm test:integration:base --grep @billing",
3838
"test:integration:cleanup": "pnpm playwright test --config integration/playwright.cleanup.config.ts",
3939
"test:integration:custom": "pnpm test:integration:base --grep @custom",
4040
"test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts",
4141
"test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web",
42-
"test:integration:express": "E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express",
43-
"test:integration:generic": "E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic",
42+
"test:integration:express": "E2E_DEBUG=1 E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express",
43+
"test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic",
4444
"test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake",
4545
"test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake",
4646
"test:integration:localhost": "pnpm test:integration:base --grep @localhost",
47-
"test:integration:machine": "E2E_APP_ID=withMachine.* pnpm test:integration:base --grep @machine",
47+
"test:integration:machine": "E2E_DEBUG=1 pnpm test:integration:base --grep @machine",
4848
"test:integration:nextjs": "E2E_APP_ID=next.appRouter.* pnpm test:integration:base --grep @nextjs",
4949
"test:integration:nuxt": "E2E_DEBUG=1 E2E_APP_ID=nuxt.node npm run test:integration:base -- --grep @nuxt",
5050
"test:integration:quickstart": "E2E_APP_ID=quickstart.* pnpm test:integration:base --grep @quickstart",

packages/astro/src/internal/create-clerk-instance.ts

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,30 +36,20 @@ function createNavigationHandler(
3636
const createClerkInstance = runOnce(createClerkInstanceInternal);
3737

3838
async function createClerkInstanceInternal<TUi extends Ui = Ui>(options?: AstroClerkCreateInstanceParams<TUi>) {
39-
let clerkJSInstance = window.Clerk;
40-
let clerkUiCtor: Promise<ClerkUiConstructor> | undefined;
41-
42-
if (!clerkJSInstance) {
43-
// Load both clerk-js and clerk-ui in parallel
44-
const clerkPromise = loadClerkJsScript(options);
45-
clerkUiCtor = options?.clerkUiCtor
46-
? Promise.resolve(options.clerkUiCtor)
47-
: loadClerkUiScript(options).then(() => {
48-
if (!window.__internal_ClerkUiCtor) {
49-
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
50-
}
51-
// After the check, TypeScript knows it's defined
52-
return window.__internal_ClerkUiCtor;
53-
});
54-
55-
await clerkPromise;
56-
57-
if (!window.Clerk) {
58-
throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.');
59-
}
60-
clerkJSInstance = window.Clerk;
39+
// Load clerk-js and clerk-ui in parallel.
40+
// Both functions return early if the scripts are already loaded
41+
// (e.g., via middleware-injected script tags in the HTML head).
42+
const clerkJsChunk = getClerkJsEntryChunk(options);
43+
const clerkUiCtor = getClerkUiEntryChunk(options);
44+
45+
await clerkJsChunk;
46+
47+
if (!window.Clerk) {
48+
throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.');
6149
}
6250

51+
const clerkJSInstance = window.Clerk;
52+
6353
if (!$clerk.get()) {
6454
$clerk.set(clerkJSInstance);
6555
}
@@ -110,4 +100,32 @@ function updateClerkOptions<TUi extends Ui = Ui>(options: AstroClerkUpdateOption
110100
void (clerk as any).__internal_updateProps(updateOptions);
111101
}
112102

103+
/**
104+
* Loads clerk-js script if not already loaded.
105+
* Returns early if window.Clerk already exists.
106+
*/
107+
async function getClerkJsEntryChunk<TUi extends Ui = Ui>(options?: AstroClerkCreateInstanceParams<TUi>): Promise<void> {
108+
await loadClerkJsScript(options);
109+
}
110+
111+
/**
112+
* Gets the ClerkUI constructor, either from options or by loading the script.
113+
* Returns early if window.__internal_ClerkUiCtor already exists.
114+
*/
115+
async function getClerkUiEntryChunk<TUi extends Ui = Ui>(
116+
options?: AstroClerkCreateInstanceParams<TUi>,
117+
): Promise<ClerkUiConstructor> {
118+
if (options?.clerkUiCtor) {
119+
return options.clerkUiCtor;
120+
}
121+
122+
await loadClerkUiScript(options);
123+
124+
if (!window.__internal_ClerkUiCtor) {
125+
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
126+
}
127+
128+
return window.__internal_ClerkUiCtor;
129+
}
130+
113131
export { createClerkInstance, updateClerkOptions };

packages/ui/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
"showerrors": "tsc",
6363
"test:ci": "vitest --maxWorkers=70%",
6464
"test:coverage": "vitest --collectCoverage && open coverage/lcov-report/index.html",
65-
"test:disabled": "vitest"
65+
"test:disabled": "vitest",
66+
"type-check": "tsc --noEmit"
6667
},
6768
"dependencies": {
6869
"@clerk/localizations": "workspace:^",

packages/ui/rspack.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const common = ({ mode, variant }) => {
4444
PACKAGE_VERSION: JSON.stringify(packageJSON.version),
4545
__PKG_VERSION__: JSON.stringify(packageJSON.version),
4646
PACKAGE_NAME: JSON.stringify(packageJSON.name),
47+
__BUILD_DISABLE_RHC__: JSON.stringify(false),
4748
}),
4849
new rspack.EnvironmentPlugin({
4950
NODE_ENV: mode,
@@ -166,7 +167,7 @@ const devConfig = (mode, env) => {
166167
rules: [svgLoader(), ...typescriptLoaderDev()],
167168
},
168169
plugins: [new ReactRefreshPlugin({ overlay: { sockHost: devUrl.host } })],
169-
devtool: 'eval-cheap-source-map',
170+
devtool: 'eval-source-map',
170171
output: {
171172
publicPath: `${devUrl.origin}/npm/`,
172173
crossOriginLoading: 'anonymous',
@@ -175,6 +176,8 @@ const devConfig = (mode, env) => {
175176
},
176177
optimization: {
177178
minimize: false,
179+
usedExports: false,
180+
providedExports: false,
178181
},
179182
devServer: {
180183
allowedHosts: ['all'],

packages/ui/src/components/Checkout/CheckoutPage.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ const FetchStatus = ({
6161

6262
const internalFetchStatus = useMemo(() => {
6363
if (errors.global) {
64-
const errorCodes = errors.global.map(e => e.code);
64+
const errorCodes = errors.global.flatMap(e => {
65+
if (e.isClerkApiResponseError()) {
66+
return e.errors.map(e => e.code);
67+
}
68+
});
6569

6670
if (errorCodes.includes('missing_payer_email')) {
6771
return 'missing_payer_email';

packages/ui/src/components/Checkout/parts.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,15 @@ export const InvalidPlanScreen = () => {
4141
const { planPeriod } = useCheckoutContext();
4242
const { errors } = useCheckout();
4343

44-
const InvalidPlanError = errors?.global?.find(e => e.code === 'invalid_plan_change');
44+
const InvalidPlanError = errors?.global
45+
?.filter(e => e.isClerkApiResponseError())
46+
.flatMap(e => e.errors)
47+
.find(e => e.code === 'invalid_plan_change');
48+
4549
if (!InvalidPlanError) {
4650
return null;
4751
}
4852

49-
// @ts-expect-error - meta is not a property of FieldError
5053
const { plan: planFromError, isPlanUpgradePossible } = InvalidPlanError?.meta || {};
5154

5255
return (

packages/ui/src/components/OrganizationProfile/InviteMembersScreen.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import { useOrganization } from '@clerk/shared/react';
2-
import { runIfFunctionOrReturn } from '@clerk/shared/utils';
32

43
import { useCardState, withCardStateProvider } from '@/ui/elements/contexts';
54
import { FormContainer } from '@/ui/elements/FormContainer';
65
import { IconCircle } from '@/ui/elements/IconCircle';
76
import { SuccessPage } from '@/ui/elements/SuccessPage';
87

98
import { useWizard, Wizard } from '../../common';
10-
import { useOrganizationProfileContext } from '../../contexts';
119
import { descriptors, Flex, localizationKeys, Text } from '../../customizables';
1210
import { useActionContext } from '../../elements/Action/ActionRoot';
1311
import { Email } from '../../icons';
1412
import { InviteMembersForm } from './InviteMembersForm';
15-
1613
type InviteMembersScreenProps = {
1714
onReset?: () => void;
1815
};

packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Header } from '@/ui/elements/Header';
88
import { Tab, TabPanel, TabPanels, Tabs, TabsList } from '@/ui/elements/Tabs';
99

1010
import { NotificationCountBadge, useProtect } from '../../common';
11-
import { useEnvironment, useOrganizationProfileContext } from '../../contexts';
11+
import { useEnvironment } from '../../contexts';
1212
import { Col, descriptors, Flex, localizationKeys } from '../../customizables';
1313
import { Action } from '../../elements/Action';
1414
import { mqu } from '../../styledSystem';

packages/ui/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
"@/ui*": ["./src/*"]
3030
}
3131
},
32-
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"],
32+
"exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx", "**/__tests__/**"],
3333
"include": ["src", "src/global.d.ts"]
3434
}

packages/ui/tsdown.config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default defineConfig(({ watch }) => {
2020
PACKAGE_VERSION: `"${uiPackage.version}"`,
2121
__PKG_VERSION__: `"${uiPackage.version}"`,
2222
__DEV__: `${watch}`,
23+
__BUILD_DISABLE_RHC__: JSON.stringify(false),
2324
},
2425
} satisfies Options;
2526

0 commit comments

Comments
 (0)