Skip to content

Commit 34b89fa

Browse files
feat(tanstack): Pass Cloudflare Workers env context to getEnvVariable
On Cloudflare Workers, process.env and import.meta.env are not available. This adds cloudflare:workers module env resolution to the TanStack Start package, following the pattern used in @clerk/react-router where loader context is passed to getEnvVariable(). - Add cloudflareEnv.ts with initCloudflareWorkerEnv() + getCloudflareWorkerEnv() - Initialize CF env in clerkMiddleware (no-op on non-CF runtimes) - Pass CF env context through commonEnvs() → getEnvVariable(name, context) - Update getPublicEnvVariables to accept optional context Related: clerk#8197 Alternative approach to PR clerk#8196 (shared-level fix)
1 parent abbc6c4 commit 34b89fa

File tree

5 files changed

+66
-11
lines changed

5 files changed

+66
-11
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@clerk/tanstack-react-start': patch
3+
---
4+
5+
feat(tanstack): Pass Cloudflare Workers env context to getEnvVariable
6+
7+
Adds `cloudflare:workers` module env resolution to the TanStack Start package, following the pattern used in `@clerk/react-router` where loader context is passed to `getEnvVariable()`. On Cloudflare Workers, `process.env` and `import.meta.env` are not available at runtime. This fix initializes the CF Workers env in `clerkMiddleware` and passes it through `commonEnvs()``getEnvVariable(name, context)` so `CLERK_SECRET_KEY` and other env vars are resolved correctly.

packages/tanstack-react-start/src/server/clerkMiddleware.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { createMiddleware } from '@tanstack/react-start';
77

88
import { canUseKeyless } from '../utils/feature-flags';
99
import { clerkClient } from './clerkClient';
10+
import { initCloudflareWorkerEnv } from './cloudflareEnv';
1011
import { resolveKeysWithKeylessFallback } from './keyless/utils';
1112
import { loadOptions } from './loadOptions';
1213
import type { ClerkMiddlewareOptions, ClerkMiddlewareOptionsCallback } from './types';
@@ -16,6 +17,9 @@ export const clerkMiddleware = (
1617
options?: ClerkMiddlewareOptions | ClerkMiddlewareOptionsCallback,
1718
): AnyRequestMiddleware => {
1819
return createMiddleware().server(async ({ request, next }) => {
20+
// Initialize Cloudflare Workers env if available (no-op on non-CF runtimes)
21+
await initCloudflareWorkerEnv();
22+
1923
const clerkRequest = createClerkRequest(patchRequest(request));
2024

2125
// Resolve options: if function, call it with context object; otherwise use as-is
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Attempts to resolve Cloudflare Worker environment variables.
3+
*
4+
* On Cloudflare Workers (e.g., TanStack Start with @cloudflare/vite-plugin),
5+
* env vars are not available on `process.env` or `import.meta.env`. They are
6+
* accessible via the `cloudflare:workers` module.
7+
*
8+
* Returns the env object if available, or undefined in non-CF environments.
9+
* The result is cached after the first call.
10+
*
11+
* This follows the same pattern used in `@clerk/astro` (see PRs #7889, #8136),
12+
* adapted for synchronous access after async initialization.
13+
*/
14+
15+
let cachedEnv: Record<string, string> | null | undefined;
16+
17+
/**
18+
* Initialize the Cloudflare Workers env cache.
19+
* Call this once at startup (e.g., in middleware) before reading env vars.
20+
*/
21+
export async function initCloudflareWorkerEnv(): Promise<void> {
22+
if (cachedEnv !== undefined) {
23+
return;
24+
}
25+
try {
26+
const moduleName = 'cloudflare:workers';
27+
const mod = await import(/* @vite-ignore */ moduleName);
28+
cachedEnv = mod.env ?? null;
29+
} catch {
30+
cachedEnv = null;
31+
}
32+
}
33+
34+
/**
35+
* Returns the cached Cloudflare Workers env, or undefined if not available.
36+
* Must call `initCloudflareWorkerEnv()` first.
37+
*/
38+
export function getCloudflareWorkerEnv(): Record<string, string> | undefined {
39+
return cachedEnv ?? undefined;
40+
}

packages/tanstack-react-start/src/server/constants.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey
22
import { getEnvVariable } from '@clerk/shared/getEnvVariable';
33

44
import { getPublicEnvVariables } from '../utils/env';
5+
import { getCloudflareWorkerEnv } from './cloudflareEnv';
56

6-
export const commonEnvs = () => {
7-
const publicEnvs = getPublicEnvVariables();
7+
export const commonEnvs = (context?: Record<string, any>) => {
8+
// On Cloudflare Workers, resolve env from the runtime.
9+
// Falls back to undefined on non-CF environments.
10+
const cfEnv = context ?? getCloudflareWorkerEnv();
11+
const publicEnvs = getPublicEnvVariables(cfEnv);
812

913
return {
1014
// Public environment variables
@@ -23,17 +27,17 @@ export const commonEnvs = () => {
2327
TELEMETRY_DEBUG: publicEnvs.telemetryDebug,
2428

2529
// Server-only environment variables
26-
API_VERSION: getEnvVariable('CLERK_API_VERSION') || 'v1',
27-
SECRET_KEY: getEnvVariable('CLERK_SECRET_KEY'),
28-
MACHINE_SECRET_KEY: getEnvVariable('CLERK_MACHINE_SECRET_KEY'),
29-
ENCRYPTION_KEY: getEnvVariable('CLERK_ENCRYPTION_KEY'),
30-
CLERK_JWT_KEY: getEnvVariable('CLERK_JWT_KEY'),
31-
API_URL: getEnvVariable('CLERK_API_URL') || apiUrlFromPublishableKey(publicEnvs.publishableKey),
30+
API_VERSION: getEnvVariable('CLERK_API_VERSION', cfEnv) || 'v1',
31+
SECRET_KEY: getEnvVariable('CLERK_SECRET_KEY', cfEnv),
32+
MACHINE_SECRET_KEY: getEnvVariable('CLERK_MACHINE_SECRET_KEY', cfEnv),
33+
ENCRYPTION_KEY: getEnvVariable('CLERK_ENCRYPTION_KEY', cfEnv),
34+
CLERK_JWT_KEY: getEnvVariable('CLERK_JWT_KEY', cfEnv),
35+
API_URL: getEnvVariable('CLERK_API_URL', cfEnv) || apiUrlFromPublishableKey(publicEnvs.publishableKey),
3236

3337
SDK_METADATA: {
3438
name: PACKAGE_NAME,
3539
version: PACKAGE_VERSION,
36-
environment: getEnvVariable('NODE_ENV'),
40+
environment: getEnvVariable('NODE_ENV', cfEnv),
3741
},
3842
} as const;
3943
};

packages/tanstack-react-start/src/utils/env.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { getEnvVariable } from '@clerk/shared/getEnvVariable';
22
import { isTruthy } from '@clerk/shared/underscore';
33

4-
export const getPublicEnvVariables = () => {
4+
export const getPublicEnvVariables = (context?: Record<string, any>) => {
55
const getValue = (name: string): string => {
6-
return getEnvVariable(`VITE_${name}`) || getEnvVariable(name);
6+
return getEnvVariable(`VITE_${name}`, context) || getEnvVariable(name, context);
77
};
88

99
return {

0 commit comments

Comments
 (0)