@vercel/prepare-flags-definitions 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @vercel/prepare-flags-definitions
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - b755ffe: Fix SDK key detection to avoid false positives with third-party identifiers.
8
+
9
+ The SDK key validation now uses a regex to require the format `vf_server_*` or `vf_client_*` instead of accepting any string starting with `vf_`. This prevents false positives with third-party service identifiers that happen to start with `vf_` (e.g., Stripe identity flow IDs like `vf_1PyHgVLpWuMxVFx...`).
10
+
11
+ ## 0.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 05a5ebf: accept userAgentSuffix instead of version
16
+ - 10c10b6: Return meaningful result from `prepareFlagsDefinitions` indicating whether definitions were created or skipped
17
+
3
18
  ## 0.1.0
4
19
 
5
20
  ### Minor Changes
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # `@vercel/prepare-flags-definitions`
2
+
3
+ A build-time utility for [Vercel Flags](https://vercel.com/docs/flags/vercel-flags) that fetches flag definitions and bundles them into a synthetic `@vercel/flags-definitions` package inside `node_modules`. This allows `@vercel/flags-core` to access flag definitions instantly at runtime, even when the network is unavailable.
4
+
5
+ This package is used by the Vercel CLI and other build tools. You typically do not need to install it directly.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm i @vercel/prepare-flags-definitions
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import { prepareFlagsDefinitions } from '@vercel/prepare-flags-definitions';
17
+
18
+ const result = await prepareFlagsDefinitions({
19
+ cwd: process.cwd(),
20
+ env: process.env,
21
+ userAgentSuffix: 'my-build-tool/1.0.0',
22
+ });
23
+
24
+ if (result.created) {
25
+ console.log(`Bundled definitions for ${result.sdkKeysCount} SDK keys`);
26
+ } else {
27
+ console.log(`No definitions created: ${result.reason}`);
28
+ }
29
+ ```
30
+
31
+ ## How It Works
32
+
33
+ 1. Scans environment variables for SDK keys (matching `vf_server_*` or `vf_client_*`)
34
+ 2. Fetches flag definitions from `flags.vercel.com` for each key
35
+ 3. Generates an optimized JavaScript module with deduplication and lazy parsing
36
+ 4. Writes the module to `node_modules/@vercel/flags-definitions/`
37
+
38
+ At runtime, `@vercel/flags-core` imports this module as a fallback when streaming or polling is unavailable.
39
+
40
+ ## Documentation
41
+
42
+ - [Embedded Definitions](https://vercel.com/docs/flags/vercel-flags/sdks/core#embedded-definitions)
43
+ - [Vercel Flags](https://vercel.com/docs/flags/vercel-flags)
package/dist/index.cjs CHANGED
@@ -2,6 +2,11 @@
2
2
  var _crypto = require('crypto');
3
3
  var _promises = require('fs/promises');
4
4
  var _path = require('path');
5
+
6
+ // package.json
7
+ var version = "0.2.1";
8
+
9
+ // src/index.ts
5
10
  var FLAGS_HOST = "https://flags.vercel.com";
6
11
  var FLAGS_DEFINITIONS_VERSION = "1.0.1";
7
12
  function obfuscate(sdkKey, prefixLength = 18) {
@@ -11,6 +16,7 @@ function obfuscate(sdkKey, prefixLength = 18) {
11
16
  function hashSdkKey(sdkKey) {
12
17
  return _crypto.createHash.call(void 0, "sha256").update(sdkKey).digest("hex");
13
18
  }
19
+ var SDK_KEY_REGEX = /^vf_(?:server|client)_/;
14
20
  function generateDefinitionsModule(sdkKeys, values) {
15
21
  const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));
16
22
  const uniqueStrings = [];
@@ -54,7 +60,7 @@ async function prepareFlagsDefinitions(options) {
54
60
  const {
55
61
  cwd,
56
62
  env,
57
- version = "unknown",
63
+ userAgentSuffix,
58
64
  fetch: fetchFn = globalThis.fetch,
59
65
  output
60
66
  } = options;
@@ -62,12 +68,12 @@ async function prepareFlagsDefinitions(options) {
62
68
  const sdkKeys = Array.from(
63
69
  Object.values(env).reduce((acc, value) => {
64
70
  if (typeof value === "string") {
65
- if (value.startsWith("vf_")) {
71
+ if (SDK_KEY_REGEX.test(value)) {
66
72
  acc.add(value);
67
73
  } else if (value.startsWith("flags:")) {
68
74
  const params = new URLSearchParams(value.slice("flags:".length));
69
75
  const sdkKey = params.get("sdkKey");
70
- if (sdkKey == null ? void 0 : sdkKey.startsWith("vf_")) {
76
+ if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) {
71
77
  acc.add(sdkKey);
72
78
  }
73
79
  }
@@ -77,13 +83,16 @@ async function prepareFlagsDefinitions(options) {
77
83
  );
78
84
  output == null ? void 0 : output.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);
79
85
  if (sdkKeys.length === 0) {
80
- return;
86
+ return { created: false, reason: "no-sdk-keys" };
81
87
  }
82
88
  const fetchPromise = Promise.all(
83
89
  sdkKeys.map(async (sdkKey) => {
84
90
  const headers = {
85
91
  authorization: `Bearer ${sdkKey}`,
86
- "user-agent": `prepare-flags-definitions/${version}`
92
+ "user-agent": [
93
+ `@vercel/prepare-flags-definitions/${version}`,
94
+ userAgentSuffix
95
+ ].filter(Boolean).join(" ")
87
96
  };
88
97
  if (env.VERCEL_PROJECT_ID) {
89
98
  headers["x-vercel-project-id"] = env.VERCEL_PROJECT_ID;
@@ -143,6 +152,7 @@ async function prepareFlagsDefinitions(options) {
143
152
  output == null ? void 0 : output.debug(
144
153
  ` \u2192 included definitions for keys "${sdkKeys.map((key) => obfuscate(key)).join(", ")}"`
145
154
  );
155
+ return { created: true, sdkKeysCount: sdkKeys.length };
146
156
  }
147
157
 
148
158
 
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/flags/flags/packages/prepare-flags-definitions/dist/index.cjs","../src/index.ts"],"names":[],"mappings":"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","file":"/home/runner/work/flags/flags/packages/prepare-flags-definitions/dist/index.cjs","sourcesContent":[null,"import { createHash } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst FLAGS_HOST = 'https://flags.vercel.com';\nconst FLAGS_DEFINITIONS_VERSION = '1.0.1';\n\ntype BundledDefinitions = Record<string, unknown>;\n\nexport interface Output {\n debug(message: string): void;\n time<T>(label: string, promise: Promise<T>): Promise<T>;\n}\n\n/**\n * Obfuscates SDK key for logging (shows first 18 chars)\n */\nfunction obfuscate(sdkKey: string, prefixLength = 18): string {\n if (prefixLength >= sdkKey.length) return sdkKey;\n return (\n sdkKey.slice(0, prefixLength) + '*'.repeat(sdkKey.length - prefixLength)\n );\n}\n\n/**\n * Computes a SHA-256 hex digest of the given SDK key.\n */\nexport function hashSdkKey(sdkKey: string): string {\n return createHash('sha256').update(sdkKey).digest('hex');\n}\n\n/**\n * Generates a JS module with deduplicated, lazily-parsed definitions.\n *\n * The map keys are SHA-256 hashes of the SDK keys so that raw keys\n * are not embedded in the output.\n *\n * Output format:\n * ```js\n * const memo = (fn) => { let cached; return () => (cached ??= fn()); };\n * const _d0 = memo(() => JSON.parse('...'));\n * const map = { \"<sha256_hash>\": _d0 };\n * export function get(hashedSdkKey) { return map[hashedSdkKey]?.() ?? null; }\n * ```\n */\nexport function generateDefinitionsModule(\n sdkKeys: string[],\n values: BundledDefinitions[],\n): string {\n // Stringify each definition\n const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));\n\n // Deduplicate: map unique strings to indices\n const uniqueStrings: string[] = [];\n const stringToIndex = new Map<string, number>();\n for (const s of stringified) {\n if (!stringToIndex.has(s)) {\n stringToIndex.set(s, uniqueStrings.length);\n uniqueStrings.push(s);\n }\n }\n\n // Map SDK keys to their definition index\n const keyToIndex = sdkKeys.map(\n (_, i) => stringToIndex.get(stringified[i]!) ?? 0,\n );\n\n // Hash each SDK key\n const hashedKeys = sdkKeys.map(hashSdkKey);\n\n // Generate JS\n const lines: string[] = [\n 'const memo = (fn) => { let cached; return () => (cached ??= fn()); };',\n '',\n ];\n\n // Add definition constants\n for (let i = 0; i < uniqueStrings.length; i++) {\n lines.push(\n `const _d${i} = memo(() => JSON.parse(${JSON.stringify(uniqueStrings[i])}));`,\n );\n }\n\n lines.push('');\n lines.push('const map = {');\n for (let i = 0; i < sdkKeys.length; i++) {\n lines.push(` ${JSON.stringify(hashedKeys[i])}: _d${keyToIndex[i]},`);\n }\n lines.push('};');\n lines.push('');\n lines.push('export function get(hashedSdkKey) {');\n lines.push(' return map[hashedSdkKey]?.() ?? null;');\n lines.push('}');\n lines.push('');\n lines.push(\n `export const version = ${JSON.stringify(FLAGS_DEFINITIONS_VERSION)};`,\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Prepares flag definitions by reading SDK keys from environment variables,\n * fetching definitions from flags.vercel.com, and writing them into a\n * synthetic `@vercel/flags-definitions` package inside `node_modules/`.\n */\nexport async function prepareFlagsDefinitions(options: {\n cwd: string;\n env: Record<string, string | undefined>;\n version?: string;\n fetch?: typeof globalThis.fetch;\n output?: Output;\n}): Promise<void> {\n const {\n cwd,\n env,\n version = 'unknown',\n fetch: fetchFn = globalThis.fetch,\n output,\n } = options;\n\n output?.debug('vercel-flags: checking env vars for SDK Keys');\n\n // Collect unique SDK keys from environment variables\n // Supports both direct SDK keys (vf_ prefix) and flags: format\n const sdkKeys = Array.from(\n Object.values(env).reduce<Set<string>>((acc, value) => {\n if (typeof value === 'string') {\n if (value.startsWith('vf_')) {\n acc.add(value);\n } else if (value.startsWith('flags:')) {\n const params = new URLSearchParams(value.slice('flags:'.length));\n const sdkKey = params.get('sdkKey');\n if (sdkKey?.startsWith('vf_')) {\n acc.add(sdkKey);\n }\n }\n }\n return acc;\n }, new Set<string>()),\n );\n\n output?.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);\n\n if (sdkKeys.length === 0) {\n return;\n }\n\n // Fetch definitions for each SDK key\n const fetchPromise = Promise.all(\n sdkKeys.map(async (sdkKey) => {\n const headers: Record<string, string> = {\n authorization: `Bearer ${sdkKey}`,\n 'user-agent': `prepare-flags-definitions/${version}`,\n };\n\n // Add Vercel metadata headers if available\n if (env.VERCEL_PROJECT_ID) {\n headers['x-vercel-project-id'] = env.VERCEL_PROJECT_ID;\n }\n if (env.VERCEL_ENV) {\n headers['x-vercel-env'] = env.VERCEL_ENV;\n }\n if (env.VERCEL_DEPLOYMENT_ID) {\n headers['x-vercel-deployment-id'] = env.VERCEL_DEPLOYMENT_ID;\n }\n if (env.VERCEL_REGION) {\n headers['x-vercel-region'] = env.VERCEL_REGION;\n }\n\n const res = await fetchFn(`${FLAGS_HOST}/v1/datafile`, { headers });\n\n if (!res.ok) {\n throw new Error(\n `Failed to fetch flag definitions for ${obfuscate(sdkKey)}: ${res.status} ${res.statusText}`,\n );\n }\n\n return res.json() as Promise<BundledDefinitions>;\n }),\n );\n\n const values = output\n ? await output.time('vercel-flags: load datafiles', fetchPromise)\n : await fetchPromise;\n\n // Generate the JS module\n const definitionsJs = generateDefinitionsModule(sdkKeys, values);\n\n // Write to node_modules/@vercel/flags-definitions/\n const storageDir = join(cwd, 'node_modules', '@vercel', 'flags-definitions');\n const indexPath = join(storageDir, 'index.js');\n const dtsPath = join(storageDir, 'index.d.ts');\n const packageJsonPath = join(storageDir, 'package.json');\n\n const dts = [\n 'export function get(hashedSdkKey: string): Record<string, unknown> | null;',\n 'export const version: string;',\n '',\n ].join('\\n');\n\n const packageJson = {\n name: '@vercel/flags-definitions',\n version: FLAGS_DEFINITIONS_VERSION,\n type: 'module',\n main: './index.js',\n types: './index.d.ts',\n exports: {\n '.': {\n types: './index.d.ts',\n import: './index.js',\n },\n },\n };\n\n await mkdir(storageDir, { recursive: true });\n await Promise.all([\n writeFile(indexPath, definitionsJs),\n writeFile(dtsPath, dts),\n writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)),\n ]);\n\n output?.debug('vercel-flags: created module');\n output?.debug(` → ${indexPath}`);\n output?.debug(` → ${dtsPath}`);\n output?.debug(` → ${packageJsonPath}`);\n output?.debug(\n ` → included definitions for keys \"${sdkKeys.map((key) => obfuscate(key)).join(', ')}\"`,\n );\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/flags/flags/packages/prepare-flags-definitions/dist/index.cjs","../src/index.ts","../package.json"],"names":[],"mappings":"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","file":"/home/runner/work/flags/flags/packages/prepare-flags-definitions/dist/index.cjs","sourcesContent":[null,"import { createHash } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { version as PACKAGE_VERSION } from '../package.json';\n\nconst FLAGS_HOST = 'https://flags.vercel.com';\nconst FLAGS_DEFINITIONS_VERSION = '1.0.1';\n\ntype BundledDefinitions = Record<string, unknown>;\n\nexport interface Output {\n debug(message: string): void;\n time<T>(label: string, promise: Promise<T>): Promise<T>;\n}\n\nexport type PrepareFlagsDefinitionsResult =\n | { created: false; reason: 'no-sdk-keys' }\n | { created: true; sdkKeysCount: number };\n\n/**\n * Obfuscates SDK key for logging (shows first 18 chars)\n */\nfunction obfuscate(sdkKey: string, prefixLength = 18): string {\n if (prefixLength >= sdkKey.length) return sdkKey;\n return (\n sdkKey.slice(0, prefixLength) + '*'.repeat(sdkKey.length - prefixLength)\n );\n}\n\n/**\n * Computes a SHA-256 hex digest of the given SDK key.\n */\nexport function hashSdkKey(sdkKey: string): string {\n return createHash('sha256').update(sdkKey).digest('hex');\n}\n\n/**\n * Regex to match valid Vercel Flags SDK keys.\n * SDK keys must follow the format: vf_server_* or vf_client_*\n * This avoids false positives with third-party identifiers that happen\n * to start with 'vf_' (e.g., Stripe identity flow IDs like 'vf_1PyH...').\n */\nconst SDK_KEY_REGEX = /^vf_(?:server|client)_/;\n\n/**\n * Generates a JS module with deduplicated, lazily-parsed definitions.\n *\n * The map keys are SHA-256 hashes of the SDK keys so that raw keys\n * are not embedded in the output.\n *\n * Output format:\n * ```js\n * const memo = (fn) => { let cached; return () => (cached ??= fn()); };\n * const _d0 = memo(() => JSON.parse('...'));\n * const map = { \"<sha256_hash>\": _d0 };\n * export function get(hashedSdkKey) { return map[hashedSdkKey]?.() ?? null; }\n * ```\n */\nexport function generateDefinitionsModule(\n sdkKeys: string[],\n values: BundledDefinitions[],\n): string {\n // Stringify each definition\n const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));\n\n // Deduplicate: map unique strings to indices\n const uniqueStrings: string[] = [];\n const stringToIndex = new Map<string, number>();\n for (const s of stringified) {\n if (!stringToIndex.has(s)) {\n stringToIndex.set(s, uniqueStrings.length);\n uniqueStrings.push(s);\n }\n }\n\n // Map SDK keys to their definition index\n const keyToIndex = sdkKeys.map(\n (_, i) => stringToIndex.get(stringified[i]!) ?? 0,\n );\n\n // Hash each SDK key\n const hashedKeys = sdkKeys.map(hashSdkKey);\n\n // Generate JS\n const lines: string[] = [\n 'const memo = (fn) => { let cached; return () => (cached ??= fn()); };',\n '',\n ];\n\n // Add definition constants\n for (let i = 0; i < uniqueStrings.length; i++) {\n lines.push(\n `const _d${i} = memo(() => JSON.parse(${JSON.stringify(uniqueStrings[i])}));`,\n );\n }\n\n lines.push('');\n lines.push('const map = {');\n for (let i = 0; i < sdkKeys.length; i++) {\n lines.push(` ${JSON.stringify(hashedKeys[i])}: _d${keyToIndex[i]},`);\n }\n lines.push('};');\n lines.push('');\n lines.push('export function get(hashedSdkKey) {');\n lines.push(' return map[hashedSdkKey]?.() ?? null;');\n lines.push('}');\n lines.push('');\n lines.push(\n `export const version = ${JSON.stringify(FLAGS_DEFINITIONS_VERSION)};`,\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Prepares flag definitions by reading SDK keys from environment variables,\n * fetching definitions from flags.vercel.com, and writing them into a\n * synthetic `@vercel/flags-definitions` package inside `node_modules/`.\n */\nexport async function prepareFlagsDefinitions(options: {\n cwd: string;\n env: Record<string, string | undefined>;\n /**\n * Appended to the user-agent header to identify the caller.\n * Example: `\"vercel-cli/35.0.0\"`\n */\n userAgentSuffix?: string;\n fetch?: typeof globalThis.fetch;\n output?: Output;\n}): Promise<PrepareFlagsDefinitionsResult> {\n const {\n cwd,\n env,\n userAgentSuffix,\n fetch: fetchFn = globalThis.fetch,\n output,\n } = options;\n\n output?.debug('vercel-flags: checking env vars for SDK Keys');\n\n // Collect unique SDK keys from environment variables\n // Supports both direct SDK keys (vf_server_*/vf_client_*) and flags: format\n const sdkKeys = Array.from(\n Object.values(env).reduce<Set<string>>((acc, value) => {\n if (typeof value === 'string') {\n if (SDK_KEY_REGEX.test(value)) {\n acc.add(value);\n } else if (value.startsWith('flags:')) {\n const params = new URLSearchParams(value.slice('flags:'.length));\n const sdkKey = params.get('sdkKey');\n if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) {\n acc.add(sdkKey);\n }\n }\n }\n return acc;\n }, new Set<string>()),\n );\n\n output?.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);\n\n if (sdkKeys.length === 0) {\n return { created: false, reason: 'no-sdk-keys' };\n }\n\n // Fetch definitions for each SDK key\n const fetchPromise = Promise.all(\n sdkKeys.map(async (sdkKey) => {\n const headers: Record<string, string> = {\n authorization: `Bearer ${sdkKey}`,\n 'user-agent': [\n `@vercel/prepare-flags-definitions/${PACKAGE_VERSION}`,\n userAgentSuffix,\n ]\n .filter(Boolean)\n .join(' '),\n };\n\n // Add Vercel metadata headers if available\n if (env.VERCEL_PROJECT_ID) {\n headers['x-vercel-project-id'] = env.VERCEL_PROJECT_ID;\n }\n if (env.VERCEL_ENV) {\n headers['x-vercel-env'] = env.VERCEL_ENV;\n }\n if (env.VERCEL_DEPLOYMENT_ID) {\n headers['x-vercel-deployment-id'] = env.VERCEL_DEPLOYMENT_ID;\n }\n if (env.VERCEL_REGION) {\n headers['x-vercel-region'] = env.VERCEL_REGION;\n }\n\n const res = await fetchFn(`${FLAGS_HOST}/v1/datafile`, { headers });\n\n if (!res.ok) {\n throw new Error(\n `Failed to fetch flag definitions for ${obfuscate(sdkKey)}: ${res.status} ${res.statusText}`,\n );\n }\n\n return res.json() as Promise<BundledDefinitions>;\n }),\n );\n\n const values = output\n ? await output.time('vercel-flags: load datafiles', fetchPromise)\n : await fetchPromise;\n\n // Generate the JS module\n const definitionsJs = generateDefinitionsModule(sdkKeys, values);\n\n // Write to node_modules/@vercel/flags-definitions/\n const storageDir = join(cwd, 'node_modules', '@vercel', 'flags-definitions');\n const indexPath = join(storageDir, 'index.js');\n const dtsPath = join(storageDir, 'index.d.ts');\n const packageJsonPath = join(storageDir, 'package.json');\n\n const dts = [\n 'export function get(hashedSdkKey: string): Record<string, unknown> | null;',\n 'export const version: string;',\n '',\n ].join('\\n');\n\n const packageJson = {\n name: '@vercel/flags-definitions',\n version: FLAGS_DEFINITIONS_VERSION,\n type: 'module',\n main: './index.js',\n types: './index.d.ts',\n exports: {\n '.': {\n types: './index.d.ts',\n import: './index.js',\n },\n },\n };\n\n await mkdir(storageDir, { recursive: true });\n await Promise.all([\n writeFile(indexPath, definitionsJs),\n writeFile(dtsPath, dts),\n writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)),\n ]);\n\n output?.debug('vercel-flags: created module');\n output?.debug(` → ${indexPath}`);\n output?.debug(` → ${dtsPath}`);\n output?.debug(` → ${packageJsonPath}`);\n output?.debug(\n ` → included definitions for keys \"${sdkKeys.map((key) => obfuscate(key)).join(', ')}\"`,\n );\n\n return { created: true, sdkKeysCount: sdkKeys.length };\n}\n","{\n \"name\": \"@vercel/prepare-flags-definitions\",\n \"version\": \"0.2.1\",\n \"description\": \"\",\n \"keywords\": [],\n \"license\": \"MIT\",\n \"author\": \"\",\n \"sideEffects\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"typesVersions\": {\n \"*\": {\n \".\": [\n \"dist/*.d.ts\",\n \"dist/*.d.cts\"\n ]\n }\n },\n \"files\": [\n \"dist\",\n \"CHANGELOG.md\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"check\": \"biome check\",\n \"test\": \"vitest --run\",\n \"test:watch\": \"vitest\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"devDependencies\": {\n \"@types/node\": \"20.11.17\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"5.6.3\",\n \"vite\": \"6.4.1\",\n \"vitest\": \"2.1.9\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -3,6 +3,13 @@ interface Output {
3
3
  debug(message: string): void;
4
4
  time<T>(label: string, promise: Promise<T>): Promise<T>;
5
5
  }
6
+ type PrepareFlagsDefinitionsResult = {
7
+ created: false;
8
+ reason: 'no-sdk-keys';
9
+ } | {
10
+ created: true;
11
+ sdkKeysCount: number;
12
+ };
6
13
  /**
7
14
  * Computes a SHA-256 hex digest of the given SDK key.
8
15
  */
@@ -30,9 +37,13 @@ declare function generateDefinitionsModule(sdkKeys: string[], values: BundledDef
30
37
  declare function prepareFlagsDefinitions(options: {
31
38
  cwd: string;
32
39
  env: Record<string, string | undefined>;
33
- version?: string;
40
+ /**
41
+ * Appended to the user-agent header to identify the caller.
42
+ * Example: `"vercel-cli/35.0.0"`
43
+ */
44
+ userAgentSuffix?: string;
34
45
  fetch?: typeof globalThis.fetch;
35
46
  output?: Output;
36
- }): Promise<void>;
47
+ }): Promise<PrepareFlagsDefinitionsResult>;
37
48
 
38
- export { type Output, generateDefinitionsModule, hashSdkKey, prepareFlagsDefinitions };
49
+ export { type Output, type PrepareFlagsDefinitionsResult, generateDefinitionsModule, hashSdkKey, prepareFlagsDefinitions };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,13 @@ interface Output {
3
3
  debug(message: string): void;
4
4
  time<T>(label: string, promise: Promise<T>): Promise<T>;
5
5
  }
6
+ type PrepareFlagsDefinitionsResult = {
7
+ created: false;
8
+ reason: 'no-sdk-keys';
9
+ } | {
10
+ created: true;
11
+ sdkKeysCount: number;
12
+ };
6
13
  /**
7
14
  * Computes a SHA-256 hex digest of the given SDK key.
8
15
  */
@@ -30,9 +37,13 @@ declare function generateDefinitionsModule(sdkKeys: string[], values: BundledDef
30
37
  declare function prepareFlagsDefinitions(options: {
31
38
  cwd: string;
32
39
  env: Record<string, string | undefined>;
33
- version?: string;
40
+ /**
41
+ * Appended to the user-agent header to identify the caller.
42
+ * Example: `"vercel-cli/35.0.0"`
43
+ */
44
+ userAgentSuffix?: string;
34
45
  fetch?: typeof globalThis.fetch;
35
46
  output?: Output;
36
- }): Promise<void>;
47
+ }): Promise<PrepareFlagsDefinitionsResult>;
37
48
 
38
- export { type Output, generateDefinitionsModule, hashSdkKey, prepareFlagsDefinitions };
49
+ export { type Output, type PrepareFlagsDefinitionsResult, generateDefinitionsModule, hashSdkKey, prepareFlagsDefinitions };
package/dist/index.js CHANGED
@@ -2,6 +2,11 @@
2
2
  import { createHash } from "crypto";
3
3
  import { mkdir, writeFile } from "fs/promises";
4
4
  import { join } from "path";
5
+
6
+ // package.json
7
+ var version = "0.2.1";
8
+
9
+ // src/index.ts
5
10
  var FLAGS_HOST = "https://flags.vercel.com";
6
11
  var FLAGS_DEFINITIONS_VERSION = "1.0.1";
7
12
  function obfuscate(sdkKey, prefixLength = 18) {
@@ -11,6 +16,7 @@ function obfuscate(sdkKey, prefixLength = 18) {
11
16
  function hashSdkKey(sdkKey) {
12
17
  return createHash("sha256").update(sdkKey).digest("hex");
13
18
  }
19
+ var SDK_KEY_REGEX = /^vf_(?:server|client)_/;
14
20
  function generateDefinitionsModule(sdkKeys, values) {
15
21
  const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));
16
22
  const uniqueStrings = [];
@@ -54,7 +60,7 @@ async function prepareFlagsDefinitions(options) {
54
60
  const {
55
61
  cwd,
56
62
  env,
57
- version = "unknown",
63
+ userAgentSuffix,
58
64
  fetch: fetchFn = globalThis.fetch,
59
65
  output
60
66
  } = options;
@@ -62,12 +68,12 @@ async function prepareFlagsDefinitions(options) {
62
68
  const sdkKeys = Array.from(
63
69
  Object.values(env).reduce((acc, value) => {
64
70
  if (typeof value === "string") {
65
- if (value.startsWith("vf_")) {
71
+ if (SDK_KEY_REGEX.test(value)) {
66
72
  acc.add(value);
67
73
  } else if (value.startsWith("flags:")) {
68
74
  const params = new URLSearchParams(value.slice("flags:".length));
69
75
  const sdkKey = params.get("sdkKey");
70
- if (sdkKey == null ? void 0 : sdkKey.startsWith("vf_")) {
76
+ if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) {
71
77
  acc.add(sdkKey);
72
78
  }
73
79
  }
@@ -77,13 +83,16 @@ async function prepareFlagsDefinitions(options) {
77
83
  );
78
84
  output == null ? void 0 : output.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);
79
85
  if (sdkKeys.length === 0) {
80
- return;
86
+ return { created: false, reason: "no-sdk-keys" };
81
87
  }
82
88
  const fetchPromise = Promise.all(
83
89
  sdkKeys.map(async (sdkKey) => {
84
90
  const headers = {
85
91
  authorization: `Bearer ${sdkKey}`,
86
- "user-agent": `prepare-flags-definitions/${version}`
92
+ "user-agent": [
93
+ `@vercel/prepare-flags-definitions/${version}`,
94
+ userAgentSuffix
95
+ ].filter(Boolean).join(" ")
87
96
  };
88
97
  if (env.VERCEL_PROJECT_ID) {
89
98
  headers["x-vercel-project-id"] = env.VERCEL_PROJECT_ID;
@@ -143,6 +152,7 @@ async function prepareFlagsDefinitions(options) {
143
152
  output == null ? void 0 : output.debug(
144
153
  ` \u2192 included definitions for keys "${sdkKeys.map((key) => obfuscate(key)).join(", ")}"`
145
154
  );
155
+ return { created: true, sdkKeysCount: sdkKeys.length };
146
156
  }
147
157
  export {
148
158
  generateDefinitionsModule,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst FLAGS_HOST = 'https://flags.vercel.com';\nconst FLAGS_DEFINITIONS_VERSION = '1.0.1';\n\ntype BundledDefinitions = Record<string, unknown>;\n\nexport interface Output {\n debug(message: string): void;\n time<T>(label: string, promise: Promise<T>): Promise<T>;\n}\n\n/**\n * Obfuscates SDK key for logging (shows first 18 chars)\n */\nfunction obfuscate(sdkKey: string, prefixLength = 18): string {\n if (prefixLength >= sdkKey.length) return sdkKey;\n return (\n sdkKey.slice(0, prefixLength) + '*'.repeat(sdkKey.length - prefixLength)\n );\n}\n\n/**\n * Computes a SHA-256 hex digest of the given SDK key.\n */\nexport function hashSdkKey(sdkKey: string): string {\n return createHash('sha256').update(sdkKey).digest('hex');\n}\n\n/**\n * Generates a JS module with deduplicated, lazily-parsed definitions.\n *\n * The map keys are SHA-256 hashes of the SDK keys so that raw keys\n * are not embedded in the output.\n *\n * Output format:\n * ```js\n * const memo = (fn) => { let cached; return () => (cached ??= fn()); };\n * const _d0 = memo(() => JSON.parse('...'));\n * const map = { \"<sha256_hash>\": _d0 };\n * export function get(hashedSdkKey) { return map[hashedSdkKey]?.() ?? null; }\n * ```\n */\nexport function generateDefinitionsModule(\n sdkKeys: string[],\n values: BundledDefinitions[],\n): string {\n // Stringify each definition\n const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));\n\n // Deduplicate: map unique strings to indices\n const uniqueStrings: string[] = [];\n const stringToIndex = new Map<string, number>();\n for (const s of stringified) {\n if (!stringToIndex.has(s)) {\n stringToIndex.set(s, uniqueStrings.length);\n uniqueStrings.push(s);\n }\n }\n\n // Map SDK keys to their definition index\n const keyToIndex = sdkKeys.map(\n (_, i) => stringToIndex.get(stringified[i]!) ?? 0,\n );\n\n // Hash each SDK key\n const hashedKeys = sdkKeys.map(hashSdkKey);\n\n // Generate JS\n const lines: string[] = [\n 'const memo = (fn) => { let cached; return () => (cached ??= fn()); };',\n '',\n ];\n\n // Add definition constants\n for (let i = 0; i < uniqueStrings.length; i++) {\n lines.push(\n `const _d${i} = memo(() => JSON.parse(${JSON.stringify(uniqueStrings[i])}));`,\n );\n }\n\n lines.push('');\n lines.push('const map = {');\n for (let i = 0; i < sdkKeys.length; i++) {\n lines.push(` ${JSON.stringify(hashedKeys[i])}: _d${keyToIndex[i]},`);\n }\n lines.push('};');\n lines.push('');\n lines.push('export function get(hashedSdkKey) {');\n lines.push(' return map[hashedSdkKey]?.() ?? null;');\n lines.push('}');\n lines.push('');\n lines.push(\n `export const version = ${JSON.stringify(FLAGS_DEFINITIONS_VERSION)};`,\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Prepares flag definitions by reading SDK keys from environment variables,\n * fetching definitions from flags.vercel.com, and writing them into a\n * synthetic `@vercel/flags-definitions` package inside `node_modules/`.\n */\nexport async function prepareFlagsDefinitions(options: {\n cwd: string;\n env: Record<string, string | undefined>;\n version?: string;\n fetch?: typeof globalThis.fetch;\n output?: Output;\n}): Promise<void> {\n const {\n cwd,\n env,\n version = 'unknown',\n fetch: fetchFn = globalThis.fetch,\n output,\n } = options;\n\n output?.debug('vercel-flags: checking env vars for SDK Keys');\n\n // Collect unique SDK keys from environment variables\n // Supports both direct SDK keys (vf_ prefix) and flags: format\n const sdkKeys = Array.from(\n Object.values(env).reduce<Set<string>>((acc, value) => {\n if (typeof value === 'string') {\n if (value.startsWith('vf_')) {\n acc.add(value);\n } else if (value.startsWith('flags:')) {\n const params = new URLSearchParams(value.slice('flags:'.length));\n const sdkKey = params.get('sdkKey');\n if (sdkKey?.startsWith('vf_')) {\n acc.add(sdkKey);\n }\n }\n }\n return acc;\n }, new Set<string>()),\n );\n\n output?.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);\n\n if (sdkKeys.length === 0) {\n return;\n }\n\n // Fetch definitions for each SDK key\n const fetchPromise = Promise.all(\n sdkKeys.map(async (sdkKey) => {\n const headers: Record<string, string> = {\n authorization: `Bearer ${sdkKey}`,\n 'user-agent': `prepare-flags-definitions/${version}`,\n };\n\n // Add Vercel metadata headers if available\n if (env.VERCEL_PROJECT_ID) {\n headers['x-vercel-project-id'] = env.VERCEL_PROJECT_ID;\n }\n if (env.VERCEL_ENV) {\n headers['x-vercel-env'] = env.VERCEL_ENV;\n }\n if (env.VERCEL_DEPLOYMENT_ID) {\n headers['x-vercel-deployment-id'] = env.VERCEL_DEPLOYMENT_ID;\n }\n if (env.VERCEL_REGION) {\n headers['x-vercel-region'] = env.VERCEL_REGION;\n }\n\n const res = await fetchFn(`${FLAGS_HOST}/v1/datafile`, { headers });\n\n if (!res.ok) {\n throw new Error(\n `Failed to fetch flag definitions for ${obfuscate(sdkKey)}: ${res.status} ${res.statusText}`,\n );\n }\n\n return res.json() as Promise<BundledDefinitions>;\n }),\n );\n\n const values = output\n ? await output.time('vercel-flags: load datafiles', fetchPromise)\n : await fetchPromise;\n\n // Generate the JS module\n const definitionsJs = generateDefinitionsModule(sdkKeys, values);\n\n // Write to node_modules/@vercel/flags-definitions/\n const storageDir = join(cwd, 'node_modules', '@vercel', 'flags-definitions');\n const indexPath = join(storageDir, 'index.js');\n const dtsPath = join(storageDir, 'index.d.ts');\n const packageJsonPath = join(storageDir, 'package.json');\n\n const dts = [\n 'export function get(hashedSdkKey: string): Record<string, unknown> | null;',\n 'export const version: string;',\n '',\n ].join('\\n');\n\n const packageJson = {\n name: '@vercel/flags-definitions',\n version: FLAGS_DEFINITIONS_VERSION,\n type: 'module',\n main: './index.js',\n types: './index.d.ts',\n exports: {\n '.': {\n types: './index.d.ts',\n import: './index.js',\n },\n },\n };\n\n await mkdir(storageDir, { recursive: true });\n await Promise.all([\n writeFile(indexPath, definitionsJs),\n writeFile(dtsPath, dts),\n writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)),\n ]);\n\n output?.debug('vercel-flags: created module');\n output?.debug(` → ${indexPath}`);\n output?.debug(` → ${dtsPath}`);\n output?.debug(` → ${packageJsonPath}`);\n output?.debug(\n ` → included definitions for keys \"${sdkKeys.map((key) => obfuscate(key)).join(', ')}\"`,\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../package.json"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { version as PACKAGE_VERSION } from '../package.json';\n\nconst FLAGS_HOST = 'https://flags.vercel.com';\nconst FLAGS_DEFINITIONS_VERSION = '1.0.1';\n\ntype BundledDefinitions = Record<string, unknown>;\n\nexport interface Output {\n debug(message: string): void;\n time<T>(label: string, promise: Promise<T>): Promise<T>;\n}\n\nexport type PrepareFlagsDefinitionsResult =\n | { created: false; reason: 'no-sdk-keys' }\n | { created: true; sdkKeysCount: number };\n\n/**\n * Obfuscates SDK key for logging (shows first 18 chars)\n */\nfunction obfuscate(sdkKey: string, prefixLength = 18): string {\n if (prefixLength >= sdkKey.length) return sdkKey;\n return (\n sdkKey.slice(0, prefixLength) + '*'.repeat(sdkKey.length - prefixLength)\n );\n}\n\n/**\n * Computes a SHA-256 hex digest of the given SDK key.\n */\nexport function hashSdkKey(sdkKey: string): string {\n return createHash('sha256').update(sdkKey).digest('hex');\n}\n\n/**\n * Regex to match valid Vercel Flags SDK keys.\n * SDK keys must follow the format: vf_server_* or vf_client_*\n * This avoids false positives with third-party identifiers that happen\n * to start with 'vf_' (e.g., Stripe identity flow IDs like 'vf_1PyH...').\n */\nconst SDK_KEY_REGEX = /^vf_(?:server|client)_/;\n\n/**\n * Generates a JS module with deduplicated, lazily-parsed definitions.\n *\n * The map keys are SHA-256 hashes of the SDK keys so that raw keys\n * are not embedded in the output.\n *\n * Output format:\n * ```js\n * const memo = (fn) => { let cached; return () => (cached ??= fn()); };\n * const _d0 = memo(() => JSON.parse('...'));\n * const map = { \"<sha256_hash>\": _d0 };\n * export function get(hashedSdkKey) { return map[hashedSdkKey]?.() ?? null; }\n * ```\n */\nexport function generateDefinitionsModule(\n sdkKeys: string[],\n values: BundledDefinitions[],\n): string {\n // Stringify each definition\n const stringified = sdkKeys.map((_, i) => JSON.stringify(values[i]));\n\n // Deduplicate: map unique strings to indices\n const uniqueStrings: string[] = [];\n const stringToIndex = new Map<string, number>();\n for (const s of stringified) {\n if (!stringToIndex.has(s)) {\n stringToIndex.set(s, uniqueStrings.length);\n uniqueStrings.push(s);\n }\n }\n\n // Map SDK keys to their definition index\n const keyToIndex = sdkKeys.map(\n (_, i) => stringToIndex.get(stringified[i]!) ?? 0,\n );\n\n // Hash each SDK key\n const hashedKeys = sdkKeys.map(hashSdkKey);\n\n // Generate JS\n const lines: string[] = [\n 'const memo = (fn) => { let cached; return () => (cached ??= fn()); };',\n '',\n ];\n\n // Add definition constants\n for (let i = 0; i < uniqueStrings.length; i++) {\n lines.push(\n `const _d${i} = memo(() => JSON.parse(${JSON.stringify(uniqueStrings[i])}));`,\n );\n }\n\n lines.push('');\n lines.push('const map = {');\n for (let i = 0; i < sdkKeys.length; i++) {\n lines.push(` ${JSON.stringify(hashedKeys[i])}: _d${keyToIndex[i]},`);\n }\n lines.push('};');\n lines.push('');\n lines.push('export function get(hashedSdkKey) {');\n lines.push(' return map[hashedSdkKey]?.() ?? null;');\n lines.push('}');\n lines.push('');\n lines.push(\n `export const version = ${JSON.stringify(FLAGS_DEFINITIONS_VERSION)};`,\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Prepares flag definitions by reading SDK keys from environment variables,\n * fetching definitions from flags.vercel.com, and writing them into a\n * synthetic `@vercel/flags-definitions` package inside `node_modules/`.\n */\nexport async function prepareFlagsDefinitions(options: {\n cwd: string;\n env: Record<string, string | undefined>;\n /**\n * Appended to the user-agent header to identify the caller.\n * Example: `\"vercel-cli/35.0.0\"`\n */\n userAgentSuffix?: string;\n fetch?: typeof globalThis.fetch;\n output?: Output;\n}): Promise<PrepareFlagsDefinitionsResult> {\n const {\n cwd,\n env,\n userAgentSuffix,\n fetch: fetchFn = globalThis.fetch,\n output,\n } = options;\n\n output?.debug('vercel-flags: checking env vars for SDK Keys');\n\n // Collect unique SDK keys from environment variables\n // Supports both direct SDK keys (vf_server_*/vf_client_*) and flags: format\n const sdkKeys = Array.from(\n Object.values(env).reduce<Set<string>>((acc, value) => {\n if (typeof value === 'string') {\n if (SDK_KEY_REGEX.test(value)) {\n acc.add(value);\n } else if (value.startsWith('flags:')) {\n const params = new URLSearchParams(value.slice('flags:'.length));\n const sdkKey = params.get('sdkKey');\n if (sdkKey && SDK_KEY_REGEX.test(sdkKey)) {\n acc.add(sdkKey);\n }\n }\n }\n return acc;\n }, new Set<string>()),\n );\n\n output?.debug(`vercel-flags: found ${sdkKeys.length} SDK keys`);\n\n if (sdkKeys.length === 0) {\n return { created: false, reason: 'no-sdk-keys' };\n }\n\n // Fetch definitions for each SDK key\n const fetchPromise = Promise.all(\n sdkKeys.map(async (sdkKey) => {\n const headers: Record<string, string> = {\n authorization: `Bearer ${sdkKey}`,\n 'user-agent': [\n `@vercel/prepare-flags-definitions/${PACKAGE_VERSION}`,\n userAgentSuffix,\n ]\n .filter(Boolean)\n .join(' '),\n };\n\n // Add Vercel metadata headers if available\n if (env.VERCEL_PROJECT_ID) {\n headers['x-vercel-project-id'] = env.VERCEL_PROJECT_ID;\n }\n if (env.VERCEL_ENV) {\n headers['x-vercel-env'] = env.VERCEL_ENV;\n }\n if (env.VERCEL_DEPLOYMENT_ID) {\n headers['x-vercel-deployment-id'] = env.VERCEL_DEPLOYMENT_ID;\n }\n if (env.VERCEL_REGION) {\n headers['x-vercel-region'] = env.VERCEL_REGION;\n }\n\n const res = await fetchFn(`${FLAGS_HOST}/v1/datafile`, { headers });\n\n if (!res.ok) {\n throw new Error(\n `Failed to fetch flag definitions for ${obfuscate(sdkKey)}: ${res.status} ${res.statusText}`,\n );\n }\n\n return res.json() as Promise<BundledDefinitions>;\n }),\n );\n\n const values = output\n ? await output.time('vercel-flags: load datafiles', fetchPromise)\n : await fetchPromise;\n\n // Generate the JS module\n const definitionsJs = generateDefinitionsModule(sdkKeys, values);\n\n // Write to node_modules/@vercel/flags-definitions/\n const storageDir = join(cwd, 'node_modules', '@vercel', 'flags-definitions');\n const indexPath = join(storageDir, 'index.js');\n const dtsPath = join(storageDir, 'index.d.ts');\n const packageJsonPath = join(storageDir, 'package.json');\n\n const dts = [\n 'export function get(hashedSdkKey: string): Record<string, unknown> | null;',\n 'export const version: string;',\n '',\n ].join('\\n');\n\n const packageJson = {\n name: '@vercel/flags-definitions',\n version: FLAGS_DEFINITIONS_VERSION,\n type: 'module',\n main: './index.js',\n types: './index.d.ts',\n exports: {\n '.': {\n types: './index.d.ts',\n import: './index.js',\n },\n },\n };\n\n await mkdir(storageDir, { recursive: true });\n await Promise.all([\n writeFile(indexPath, definitionsJs),\n writeFile(dtsPath, dts),\n writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)),\n ]);\n\n output?.debug('vercel-flags: created module');\n output?.debug(` → ${indexPath}`);\n output?.debug(` → ${dtsPath}`);\n output?.debug(` → ${packageJsonPath}`);\n output?.debug(\n ` → included definitions for keys \"${sdkKeys.map((key) => obfuscate(key)).join(', ')}\"`,\n );\n\n return { created: true, sdkKeysCount: sdkKeys.length };\n}\n","{\n \"name\": \"@vercel/prepare-flags-definitions\",\n \"version\": \"0.2.1\",\n \"description\": \"\",\n \"keywords\": [],\n \"license\": \"MIT\",\n \"author\": \"\",\n \"sideEffects\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"typesVersions\": {\n \"*\": {\n \".\": [\n \"dist/*.d.ts\",\n \"dist/*.d.cts\"\n ]\n }\n },\n \"files\": [\n \"dist\",\n \"CHANGELOG.md\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"check\": \"biome check\",\n \"test\": \"vitest --run\",\n \"test:watch\": \"vitest\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"devDependencies\": {\n \"@types/node\": \"20.11.17\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"5.6.3\",\n \"vite\": \"6.4.1\",\n \"vitest\": \"2.1.9\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/prepare-flags-definitions",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "license": "MIT",