-
Notifications
You must be signed in to change notification settings - Fork 297
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(shared): Support passing env source into runtime environment hel…
…pers We can support cases like per-request env in Cloudflare workers
- Loading branch information
Showing
2 changed files
with
290 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
import { isDevelopmentEnvironment, isProductionEnvironment, isTestEnvironment } from './runtimeEnvironment'; | ||
|
||
async function withEnv(name: string, value: any, cb: () => any | Promise<any>) { | ||
const currentValue = process.env[name]; | ||
|
||
process.env[name] = value; | ||
const res = await cb(); | ||
|
||
process.env[name] = currentValue; | ||
return res; | ||
} | ||
|
||
describe('isDevelopmentEnvironment(env)', () => { | ||
test('is false for undefined process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', undefined, () => { | ||
return isDevelopmentEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is false for non-development process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isDevelopmentEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for development process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'development', () => { | ||
return isDevelopmentEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
|
||
describe('when env is passed as parameter', () => { | ||
test('is false for non-development process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isDevelopmentEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for development process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'development', () => { | ||
return isDevelopmentEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
// This case is related to per-request env on Cloudflare fetch handler | ||
describe('when env-like object is passed as parameter', () => { | ||
test('is false for non-development process.env.NODE_ENV', async () => { | ||
const isDev = isDevelopmentEnvironment({ NODE_ENV: 'whatever' }); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for development process.env.NODE_ENV', async () => { | ||
const isDev = isDevelopmentEnvironment({ NODE_ENV: 'development' }); | ||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('when publishableKey is passed as parameter', () => { | ||
test('is false for non-development process.env.NODE_ENV', async () => { | ||
const isDev = isDevelopmentEnvironment('pk_live_ZXhhbXBsZS5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for development process.env.NODE_ENV', async () => { | ||
const isDev = isDevelopmentEnvironment('pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('isProductionEnvironment(env)', () => { | ||
test('is false for undefined process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', undefined, () => { | ||
return isProductionEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is false for non-production process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isProductionEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for production process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'production', () => { | ||
return isProductionEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
|
||
describe('when env is passed as parameter', () => { | ||
test('is false for non-production process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isProductionEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for production process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'production', () => { | ||
return isProductionEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
// This case is related to per-request env on Cloudflare fetch handler | ||
describe('when env-like object is passed as parameter', () => { | ||
test('is false for non-production process.env.NODE_ENV', async () => { | ||
const isDev = isProductionEnvironment({ NODE_ENV: 'whatever' }); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for production process.env.NODE_ENV', async () => { | ||
const isDev = isProductionEnvironment({ NODE_ENV: 'production' }); | ||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('when publishableKey is passed as parameter', () => { | ||
test('is false for non-production process.env.NODE_ENV', async () => { | ||
const isDev = isProductionEnvironment('pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for production process.env.NODE_ENV', async () => { | ||
const isDev = isProductionEnvironment('pk_live_ZXhhbXBsZS5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('isTestEnvironment(env)', () => { | ||
test('is false for undefined process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', undefined, () => { | ||
return isTestEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is false for non-test process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isTestEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for test process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'test', () => { | ||
return isTestEnvironment(); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
|
||
describe('when env is passed as parameter', () => { | ||
test('is false non-test process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'whatever', () => { | ||
return isTestEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is true for test process.env.NODE_ENV', async () => { | ||
const isDev = await withEnv('NODE_ENV', 'test', () => { | ||
return isTestEnvironment(process.env); | ||
}); | ||
|
||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
// This case is related to per-request env on Cloudflare fetch handler | ||
describe('when env-like object is passed as parameter', () => { | ||
test('is false for non-test process.env.NODE_ENV', async () => { | ||
const isDev = isTestEnvironment({ NODE_ENV: 'whatever' }); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is false for test process.env.NODE_ENV', async () => { | ||
const isDev = isTestEnvironment({ NODE_ENV: 'test' }); | ||
expect(isDev).toBe(true); | ||
}); | ||
}); | ||
|
||
// There is no publishableKey for test env (only prod /dev) | ||
describe('when publishableKey is passed as parameter', () => { | ||
test('is false for non-test process.env.NODE_ENV', async () => { | ||
const isDev = isTestEnvironment('pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(false); | ||
}); | ||
|
||
test('is false for test process.env.NODE_ENV', async () => { | ||
const isDev = isTestEnvironment('pk_live_ZXhhbXBsZS5jbGVyay5hY2NvdW50cy5kZXYk'); | ||
expect(isDev).toBe(false); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,83 @@ | ||
export const isDevelopmentEnvironment = (): boolean => { | ||
try { | ||
return process.env.NODE_ENV === 'development'; | ||
// eslint-disable-next-line no-empty | ||
} catch (err) {} | ||
import { parsePublishableKey } from './keys'; | ||
|
||
// TODO: add support for import.meta.env.DEV that is being used by vite | ||
/** | ||
* Check for development runtime environment using the environment variables of the Clerk publishableKey. | ||
* | ||
* Examples: | ||
* | ||
* 1. using process.env: `isDevelopmentEnvironment()` | ||
* 2. passing custom process.env source: `isDevelopmentEnvironment(import.meta.env)` | ||
* 3. using publishableKey: `isDevelopmentEnvironment('pk_********')` | ||
* | ||
* @param envOrPublishableKey | ||
* @returns boolean | ||
*/ | ||
export const isDevelopmentEnvironment = (envOrPublishableKey?: EnvironmentOrPublishableKey): boolean => { | ||
return isEnvironment('development', envOrPublishableKey); | ||
}; | ||
|
||
return false; | ||
/** | ||
* Check for testing runtime environment using the environment variables of the Clerk publishableKey. | ||
* | ||
* Examples: | ||
* | ||
* 1. using process.env: `isTestEnvironment()` | ||
* 2. passing custom process.env source: `isTestEnvironment(import.meta.env)` | ||
* 3. using publishableKey: `isTestEnvironment('pk_test_********')` | ||
* | ||
* The `isTestEnvironment()` will always be false for any publishableKey since development and production | ||
* publishable keys are only supported. | ||
* | ||
* @param envOrPublishableKey | ||
* @returns boolean | ||
*/ | ||
export const isTestEnvironment = (envOrPublishableKey?: EnvironmentOrPublishableKey): boolean => { | ||
return isEnvironment('test', envOrPublishableKey); | ||
}; | ||
|
||
export const isTestEnvironment = (): boolean => { | ||
try { | ||
return process.env.NODE_ENV === 'test'; | ||
// eslint-disable-next-line no-empty | ||
} catch (err) {} | ||
/** | ||
* Check for production runtime environment using the environment variables of the Clerk publishableKey. | ||
* | ||
* Examples: | ||
* | ||
* 1. using process.env: `isProductionEnvironment()` | ||
* 2. passing custom process.env source: `isProductionEnvironment(import.meta.env)` | ||
* 3. using publishableKey: `isProductionEnvironment('pk_live_********')` | ||
* | ||
* @param envOrPublishableKey | ||
* @returns boolean | ||
*/ | ||
export const isProductionEnvironment = (envOrPublishableKey?: EnvironmentOrPublishableKey): boolean => { | ||
return isEnvironment('production', envOrPublishableKey); | ||
}; | ||
|
||
// TODO: add support for import.meta.env.DEV that is being used by vite | ||
return false; | ||
const getRuntimeFromProcess = (env?: typeof process.env) => { | ||
return env?.NODE_ENV; | ||
}; | ||
|
||
const getRuntimeFromPublishableKey = (publishableKey: string) => { | ||
return parsePublishableKey(publishableKey)?.instanceType; | ||
}; | ||
|
||
const isPublishableKey = (envOrPublishableKey?: string | typeof process.env): envOrPublishableKey is string => { | ||
return typeof envOrPublishableKey === 'string'; | ||
}; | ||
|
||
export const isProductionEnvironment = (): boolean => { | ||
type Environment = 'development' | 'production' | 'test'; | ||
type EnvironmentOrPublishableKey = typeof process.env | string; | ||
|
||
// Allow passing env as arg to support Cloudflare workers case | ||
function isEnvironment(environment: Environment, envOrPublishableKey?: EnvironmentOrPublishableKey) { | ||
try { | ||
return process.env.NODE_ENV === 'production'; | ||
envOrPublishableKey ||= process?.env; | ||
// eslint-disable-next-line no-empty | ||
} catch (err) {} | ||
|
||
if (isPublishableKey(envOrPublishableKey)) { | ||
return getRuntimeFromPublishableKey(envOrPublishableKey) === environment; | ||
} | ||
|
||
// TODO: add support for import.meta.env.DEV that is being used by vite | ||
return false; | ||
}; | ||
|
||
return getRuntimeFromProcess(envOrPublishableKey) === environment; | ||
} |