@vercel/flags-core 1.0.0 → 1.0.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,11 @@
1
1
  # @vercel/flags-core
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7d7719a: Fixed an issue where concurrent flag evaluations (e.g. `Promise.all([client.evaluate('a'), client.evaluate('b')])`) would each trigger a separate initialization, causing a flood of network requests to the flags service. Also fixed stream disconnect during initialization from starting a duplicate polling cycle.
8
+
3
9
  ## 1.0.0
4
10
 
5
11
  ### Major Changes
@@ -354,7 +354,7 @@ function findWeightedIndex(weights, value, maxValue) {
354
354
  }
355
355
 
356
356
  // package.json
357
- var version = "1.0.0";
357
+ var version = "1.0.1";
358
358
 
359
359
  // src/lib/report-value.ts
360
360
  function internalReportValue(key, value, data) {
@@ -430,26 +430,38 @@ async function evaluate2(id, flagKey, defaultValue, entities) {
430
430
 
431
431
  // src/create-raw-client.ts
432
432
  var idCount = 0;
433
+ async function performInitialize(instance, initFn) {
434
+ try {
435
+ await initFn();
436
+ instance.initialized = true;
437
+ } catch (error) {
438
+ instance.initPromise = null;
439
+ throw error;
440
+ }
441
+ }
433
442
  function createCreateRawClient(fns) {
434
443
  return function createRawClient({
435
444
  dataSource,
436
445
  origin
437
446
  }) {
438
447
  const id = idCount++;
439
- clientMap.set(id, { dataSource, initialized: false });
448
+ clientMap.set(id, { dataSource, initialized: false, initPromise: null });
440
449
  const api = {
441
450
  origin,
442
451
  initialize: async () => {
443
452
  let instance = clientMap.get(id);
444
453
  if (!instance) {
445
- instance = { dataSource, initialized: false };
454
+ instance = { dataSource, initialized: false, initPromise: null };
446
455
  clientMap.set(id, instance);
447
456
  }
448
457
  if (instance.initialized) return;
449
- const promise = fns.initialize(id);
450
- await promise;
451
- instance.initialized = true;
452
- return promise;
458
+ if (!instance.initPromise) {
459
+ instance.initPromise = performInitialize(
460
+ instance,
461
+ () => fns.initialize(id)
462
+ );
463
+ }
464
+ return instance.initPromise;
453
465
  },
454
466
  shutdown: async () => {
455
467
  await fns.shutdown(id);
@@ -872,6 +884,9 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
872
884
  // Polling state
873
885
  pollingIntervalId;
874
886
  pollingAbortController;
887
+ // Initialization state — suppresses onDisconnect from starting polling
888
+ // while initialize() is still running its own fallback chain
889
+ isInitializing = false;
875
890
  // Usage tracking
876
891
  usageTracker;
877
892
  isFirstGetData = true;
@@ -917,16 +932,21 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
917
932
  this.startBackgroundUpdates();
918
933
  return;
919
934
  }
920
- if (this.options.stream.enabled) {
921
- const streamSuccess = await this.tryInitializeStream();
922
- if (streamSuccess) return;
923
- }
924
- if (this.options.polling.enabled) {
925
- const pollingSuccess = await this.tryInitializePolling();
926
- if (pollingSuccess) return;
935
+ this.isInitializing = true;
936
+ try {
937
+ if (this.options.stream.enabled) {
938
+ const streamSuccess = await this.tryInitializeStream();
939
+ if (streamSuccess) return;
940
+ }
941
+ if (this.options.polling.enabled) {
942
+ const pollingSuccess = await this.tryInitializePolling();
943
+ if (pollingSuccess) return;
944
+ }
945
+ if (this.data) return;
946
+ await this.initializeFromBundled();
947
+ } finally {
948
+ this.isInitializing = false;
927
949
  }
928
- if (this.data) return;
929
- await this.initializeFromBundled();
930
950
  }
931
951
  /**
932
952
  * Reads the current datafile with metrics.
@@ -965,6 +985,7 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
965
985
  this.stopStream();
966
986
  this.stopPolling();
967
987
  this.data = this.options.datafile;
988
+ this.isInitializing = false;
968
989
  this.isStreamConnected = false;
969
990
  this.hasWarnedAboutStaleData = false;
970
991
  await this.usageTracker.flush();
@@ -1100,7 +1121,7 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
1100
1121
  },
1101
1122
  onDisconnect: () => {
1102
1123
  this.isStreamConnected = false;
1103
- if (this.options.polling.enabled && !this.pollingIntervalId) {
1124
+ if (this.options.polling.enabled && !this.pollingIntervalId && !this.isInitializing) {
1104
1125
  this.startPolling();
1105
1126
  }
1106
1127
  }
@@ -1493,4 +1514,4 @@ export {
1493
1514
  resetDefaultFlagsClient,
1494
1515
  createClient
1495
1516
  };
1496
- //# sourceMappingURL=chunk-7BUTND2Q.js.map
1517
+ //# sourceMappingURL=chunk-5CDNQMQ6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client-fns.ts","../src/client-map.ts","../src/evaluate.ts","../src/types.ts","../src/utils.ts","../package.json","../src/lib/report-value.ts","../src/create-raw-client.ts","../src/errors.ts","../src/utils/read-bundled-definitions.ts","../src/utils/sleep.ts","../src/utils/usage-tracker.ts","../src/data-source/stream-connection.ts","../src/data-source/flag-network-data-source.ts","../src/utils/sdk-keys.ts","../src/index.make.ts","../src/index.default.ts"],"sourcesContent":["import { clientMap } from './client-map';\nimport { evaluate as evalFlag } from './evaluate';\nimport { internalReportValue } from './lib/report-value';\nimport type { BundledDefinitions, EvaluationResult, Packed } from './types';\nimport { ErrorCode, ResolutionReason } from './types';\n\nexport function initialize(id: number): Promise<void> {\n return clientMap.get(id)!.dataSource.initialize();\n}\n\nexport function shutdown(id: number): void | Promise<void> {\n return clientMap.get(id)!.dataSource.shutdown();\n}\n\nexport function getDatafile(id: number) {\n return clientMap.get(id)!.dataSource.getDatafile();\n}\n\nexport function getFallbackDatafile(id: number): Promise<BundledDefinitions> {\n const ds = clientMap.get(id)!.dataSource;\n if (ds.getFallbackDatafile) return ds.getFallbackDatafile();\n throw new Error('flags: This data source does not support fallbacks');\n}\n\nexport async function evaluate<T, E = Record<string, unknown>>(\n id: number,\n flagKey: string,\n defaultValue?: T,\n entities?: E,\n): Promise<EvaluationResult<T>> {\n const ds = clientMap.get(id)!.dataSource;\n const datafile = await ds.read();\n const flagDefinition = datafile.definitions[flagKey] as Packed.FlagDefinition;\n\n if (flagDefinition === undefined) {\n return {\n value: defaultValue,\n reason: ResolutionReason.ERROR,\n errorCode: ErrorCode.FLAG_NOT_FOUND,\n errorMessage: `Definition not found for flag \"${flagKey}\"`,\n metrics: {\n evaluationMs: 0,\n readMs: datafile.metrics.readMs,\n source: datafile.metrics.source,\n cacheStatus: datafile.metrics.cacheStatus,\n connectionState: datafile.metrics.connectionState,\n },\n };\n }\n\n const evalStartTime = Date.now();\n const result = evalFlag<T>({\n defaultValue,\n definition: flagDefinition,\n environment: datafile.environment,\n entities: entities ?? {},\n segments: datafile.segments,\n });\n const evaluationDurationMs = Date.now() - evalStartTime;\n\n if (datafile.projectId) {\n internalReportValue(flagKey, result.value, {\n originProjectId: datafile.projectId,\n originProvider: 'vercel',\n reason: result.reason,\n outcomeType:\n result.reason !== ResolutionReason.ERROR\n ? result.outcomeType\n : undefined,\n });\n }\n\n return Object.assign(result, {\n metrics: {\n evaluationMs: evaluationDurationMs,\n readMs: datafile.metrics.readMs,\n source: datafile.metrics.source,\n cacheStatus: datafile.metrics.cacheStatus,\n connectionState: datafile.metrics.connectionState,\n },\n });\n}\n","import type { DataSource } from './types';\n\nexport type ClientInstance = {\n dataSource: DataSource;\n initialized: boolean;\n initPromise: Promise<void> | null;\n};\n\nexport const clientMap = new Map<number, ClientInstance>();\n","import { xxHash32 as hashInput } from 'js-xxhash';\nimport {\n Comparator,\n type EvaluationParams,\n type EvaluationResult,\n OutcomeType,\n Packed,\n ResolutionReason,\n} from './types';\nimport { exhaustivenessCheck } from './utils';\n\ntype PathArray = (string | number)[];\n\nfunction getProperty(obj: any, pathArray: PathArray): any {\n return pathArray.reduce((acc: any, key: string | number) => {\n if (acc && key in acc) {\n return acc[key];\n }\n return undefined; // Return undefined if the property is not found\n }, obj);\n}\n\n/**\n * Accesses the value of the given lhs on the provided entities.\n *\n * This must return unknown as we don't know what the library users will pass.\n */\n\nfunction access<T>(lhs: Packed.LHS, params: EvaluationParams<T>): any {\n // we're dealing with an entity\n if (Array.isArray(lhs)) return getProperty(params.entities, lhs);\n\n // Code should never end up here as the segment accessor is handled\n // earlier in the matchConditions() function.\n if (lhs === Packed.AccessorType.SEGMENT)\n throw new Error('Unexpected segment');\n\n throw new Error('Accessor not implemented');\n}\n\nfunction isString(input: unknown): input is string {\n return typeof input === 'string';\n}\n\nfunction isNumber(input: unknown): input is number {\n return typeof input === 'number';\n}\n\nfunction isArray(input: unknown): input is unknown[] {\n return Array.isArray(input);\n}\n\nfunction matchTargetList<T>(\n targets: Packed.TargetList,\n params: EvaluationParams<T>,\n): boolean {\n for (const [kind, attributes] of Object.entries(targets)) {\n for (const [attribute, values] of Object.entries(attributes)) {\n const entity = access([kind, attribute], params);\n if (isString(entity) && values.includes(entity)) return true;\n }\n }\n return false;\n}\n\nfunction matchSegment<T>(segment: Packed.Segment, params: EvaluationParams<T>) {\n if (segment.include && matchTargetList(segment.include, params)) return true;\n if (segment.exclude && matchTargetList(segment.exclude, params)) return false;\n if (!segment.rules?.length) return false;\n\n const firstMatchingRule = segment.rules.find((rule) =>\n matchConditions(rule.conditions, params),\n );\n\n if (!firstMatchingRule) return false;\n\n return handleSegmentOutcome(params, firstMatchingRule.outcome);\n}\n\nfunction matchSegmentCondition<T>(\n cmp: Comparator,\n rhs: Packed.RHS,\n params: EvaluationParams<T>,\n) {\n switch (cmp) {\n case Comparator.EQ: {\n const segment = params.segments?.[rhs as string];\n if (!segment) return false;\n return matchSegment<T>(segment, params);\n }\n case Comparator.NOT_EQ: {\n const segment = params.segments?.[rhs as string];\n if (!segment) return false;\n return !matchSegment<T>(segment, params);\n }\n case Comparator.ONE_OF: {\n if (!isArray(rhs)) return false;\n const segmentIds = rhs;\n return segmentIds.some((segmentId) => {\n const segment = params.segments?.[segmentId];\n if (!segment) return false;\n return matchSegment<T>(segment, params);\n });\n }\n case Comparator.NOT_ONE_OF: {\n const segmentIds = rhs as string[];\n return segmentIds.every((segmentId) => {\n const segment = params.segments?.[segmentId];\n if (!segment) return false;\n return matchSegment<T>(segment, params);\n });\n }\n default:\n throw new Error(`Comparator ${cmp} not implemented for segment`);\n }\n}\n\nfunction matchConditions<T>(\n conditions: Packed.Condition[],\n params: EvaluationParams<T>,\n): boolean {\n return conditions.every((condition) => {\n const [lhsAccessor, cmpKey, rhs] = condition;\n\n if (lhsAccessor === Packed.AccessorType.SEGMENT) {\n return rhs && matchSegmentCondition(cmpKey, rhs, params);\n }\n\n const lhs = access(lhsAccessor, params);\n try {\n switch (cmpKey) {\n case Comparator.EQ:\n return lhs === rhs;\n case Comparator.NOT_EQ:\n return lhs !== rhs;\n case Comparator.ONE_OF:\n return isArray(rhs) && rhs.includes(lhs);\n case Comparator.NOT_ONE_OF:\n // lhs would be undefined when the value was not provided, in which\n // case we should not match the rule\n return (\n isArray(rhs) && typeof lhs !== 'undefined' && !rhs.includes(lhs)\n );\n case Comparator.CONTAINS_ALL_OF: {\n if (!Array.isArray(rhs) || !Array.isArray(lhs)) return false;\n\n const lhsSet = new Set(lhs.filter(isString));\n\n // try to use a set if the lhs is a list of strings - O(1)\n // otherwise we need to iterate over the values - O(n)\n if (lhsSet.size === lhs.length) {\n return rhs.filter(isString).every((item) => lhsSet.has(item));\n }\n\n // this shouldn't happen since we only allow string[] on the lhs\n return rhs.every((item) => lhs.includes(item));\n }\n case Comparator.CONTAINS_ANY_OF: {\n if (!Array.isArray(rhs) || !Array.isArray(lhs)) return false;\n\n const rhsSet = new Set(rhs.filter(isString));\n return lhs.some(\n rhsSet.size === rhs.length\n ? // try to use a set if the rhs is a list of strings - O(1)\n (item) => rhsSet.has(item)\n : // otherwise we need to iterate over the values - O(n)\n (item) => rhs.includes(item),\n );\n }\n case Comparator.CONTAINS_NONE_OF: {\n // if the rhs is not an array something went wrong and we should not match\n if (!Array.isArray(rhs)) return false;\n\n // if it's not an array it doesn't contain any of the values\n if (!Array.isArray(lhs)) return true;\n\n const rhsSet = new Set(rhs.filter(isString));\n return lhs.every(\n rhsSet.size === rhs.length\n ? // try to use a set if the rhs is a list of strings - O(1)\n (item) => !rhsSet.has(item)\n : // otherwise we need to iterate over the values - O(n)\n (item) => !rhs.includes(item),\n );\n }\n case Comparator.STARTS_WITH:\n return isString(lhs) && isString(rhs) && lhs.startsWith(rhs);\n case Comparator.NOT_STARTS_WITH:\n return isString(lhs) && isString(rhs) && !lhs.startsWith(rhs);\n case Comparator.ENDS_WITH:\n return isString(lhs) && isString(rhs) && lhs.endsWith(rhs);\n case Comparator.NOT_ENDS_WITH:\n return isString(lhs) && isString(rhs) && !lhs.endsWith(rhs);\n case Comparator.EXISTS:\n return lhs !== undefined && lhs !== null;\n case Comparator.NOT_EXISTS:\n return lhs === undefined || lhs === null;\n case Comparator.GT:\n // NaN will return false for any comparisons\n if (lhs === null || lhs === undefined) return false;\n return (isNumber(rhs) || isString(rhs)) && lhs > rhs;\n case Comparator.GTE:\n if (lhs === null || lhs === undefined) return false;\n return (isNumber(rhs) || isString(rhs)) && lhs >= rhs;\n case Comparator.LT:\n if (lhs === null || lhs === undefined) return false;\n return (isNumber(rhs) || isString(rhs)) && lhs < rhs;\n case Comparator.LTE:\n if (lhs === null || lhs === undefined) return false;\n return (isNumber(rhs) || isString(rhs)) && lhs <= rhs;\n case Comparator.REGEX:\n if (\n isString(lhs) &&\n typeof rhs === 'object' &&\n !Array.isArray(rhs) &&\n rhs?.type === 'regex'\n ) {\n return new RegExp(rhs.pattern, rhs.flags).test(lhs);\n }\n return false;\n\n case Comparator.NOT_REGEX:\n if (\n isString(lhs) &&\n typeof rhs === 'object' &&\n !Array.isArray(rhs) &&\n rhs?.type === 'regex'\n ) {\n return !new RegExp(rhs.pattern, rhs.flags).test(lhs);\n }\n return false;\n case Comparator.BEFORE: {\n if (!isString(lhs) || !isString(rhs)) return false;\n const a = new Date(lhs);\n const b = new Date(rhs);\n // if any date fails to parse getTime will return NaN, which will cause\n // comparisons to fail.\n return a.getTime() < b.getTime();\n }\n case Comparator.AFTER: {\n if (!isString(lhs) || !isString(rhs)) return false;\n const a = new Date(lhs);\n const b = new Date(rhs);\n return a.getTime() > b.getTime();\n }\n default: {\n const _x: never = cmpKey; // exhaustive check\n return false;\n }\n }\n } catch (error) {\n console.error('flags: Error matching conditions', error);\n return false;\n }\n });\n}\n\nfunction sum(list: number[]) {\n return list.reduce((acc, n) => acc + n, 0);\n}\n\nfunction handleSegmentOutcome<T>(\n params: EvaluationParams<T>,\n outcome: Packed.SegmentOutcome,\n) {\n // when everyone is flagged in the segment we can return true immediately\n if (outcome === 1) return true;\n\n switch (outcome.type) {\n case 'split': {\n const lhs = access(outcome.base, params);\n\n // exclude from segment if the lhs is not a string\n if (typeof lhs !== 'string') return false;\n\n const maxValue = 100_000;\n\n // bypass hashing for common values and edges\n if (outcome.passPromille <= 0) return false;\n if (outcome.passPromille >= maxValue) return true;\n\n const value = hashInput(lhs, params.definition.seed) % maxValue;\n return value < outcome.passPromille;\n }\n default: {\n const { type } = outcome;\n exhaustivenessCheck(type);\n }\n }\n}\n\nfunction getVariant<T>(variants: unknown[], index: number): T {\n if (index < 0 || index >= variants.length) {\n throw new Error(\n `@vercel/flags-core: Invalid variant index ${index}, variants length is ${variants.length}`,\n );\n }\n return variants[index] as T;\n}\n\nfunction handleOutcome<T>(\n params: EvaluationParams<T>,\n outcome: Packed.Outcome,\n): {\n value: T;\n outcomeType: OutcomeType;\n} {\n if (typeof outcome === 'number') {\n return {\n value: getVariant<T>(params.definition.variants, outcome),\n outcomeType: OutcomeType.VALUE,\n };\n }\n switch (outcome.type) {\n case 'split': {\n const lhs = access(outcome.base, params);\n const defaultOutcome = getVariant<T>(\n params.definition.variants,\n outcome.defaultVariant,\n );\n\n // serve the default variant if the lhs is not a string\n if (typeof lhs !== 'string') {\n return { value: defaultOutcome, outcomeType: OutcomeType.SPLIT };\n }\n\n /** 2^32-1 */\n const maxValue = 4_294_967_295;\n /**\n * (xxHash32): turns the string into a number between 0 and 2^32-1 (max uint32 value)\n * Since we know the range of the hash function, we don't use modulo here. If we change\n * the hash function, or if the range changes, we should add a modulo here and/or adjust maxValue.\n */\n const value = hashInput(lhs, params.definition.seed);\n const sumOfWeights = sum(outcome.weights);\n const scaledWeights = outcome.weights.map(\n (weight) => (weight / sumOfWeights) * maxValue,\n );\n const variantIndex = findWeightedIndex(scaledWeights, value, maxValue);\n return {\n value:\n variantIndex === -1\n ? defaultOutcome\n : getVariant<T>(params.definition.variants, variantIndex),\n outcomeType: OutcomeType.SPLIT,\n };\n }\n default: {\n const { type } = outcome;\n exhaustivenessCheck(type);\n }\n }\n}\n\n/**\n * Evaluates a single feature flag.\n *\n * This function should never throw for expected errors, instead it returns\n * { reason: Reason.ERROR, errorMessage: ... }.\n *\n * The function can however throw for situations which should not happen under\n * normal circumstances, for example if the environment config is not found.\n */\nexport function evaluate<T>(\n /**\n * The params used for the evaluation\n */\n params: EvaluationParams<T>,\n): EvaluationResult<T> {\n const envConfig = params.definition.environments[params.environment];\n\n // handle shortcut where a value is a number directly\n if (typeof envConfig === 'number') {\n return Object.assign(handleOutcome<T>(params, envConfig), {\n reason: ResolutionReason.PAUSED as const,\n }) satisfies EvaluationResult<T>;\n }\n\n if (!envConfig) {\n return {\n reason: ResolutionReason.ERROR,\n errorMessage: `Could not find envConfig for \"${params.environment}\"`,\n value: params.defaultValue,\n };\n }\n\n if ('reuse' in envConfig) {\n const reuseEnvConfig = params.definition.environments[envConfig.reuse];\n\n if (reuseEnvConfig === undefined) {\n // this is an unexpected error as this should have never been saved in\n // the first place\n throw new Error(\n `Could not find envConfig for \"${envConfig.reuse}\" when reusing`,\n );\n }\n\n return evaluate<T>({ ...params, environment: envConfig.reuse });\n }\n\n if (envConfig.targets) {\n const matchedIndex = envConfig.targets.findIndex((targetList) =>\n matchTargetList(targetList, params),\n );\n\n if (matchedIndex > -1) {\n return Object.assign(handleOutcome<T>(params, matchedIndex), {\n reason: ResolutionReason.TARGET_MATCH as const,\n }) satisfies EvaluationResult<T>;\n }\n }\n\n const firstMatchingRule = envConfig.rules\n ? envConfig.rules.find((rule) => matchConditions(rule.conditions, params))\n : undefined;\n\n if (firstMatchingRule) {\n return Object.assign(handleOutcome<T>(params, firstMatchingRule.outcome), {\n reason: ResolutionReason.RULE_MATCH as const,\n }) satisfies EvaluationResult<T>;\n }\n\n return Object.assign(handleOutcome<T>(params, envConfig.fallthrough), {\n reason: ResolutionReason.FALLTHROUGH as const,\n }) satisfies EvaluationResult<T>;\n}\n\n/**\n * Find the weighted index that the given value falls into.\n *\n * Takes a set of weights that add up to maxValue, and returns the index\n * that corresponds to the given value.\n *\n * @returns index or -1\n */\nexport function findWeightedIndex(\n weights: number[],\n value: number,\n maxValue: number,\n): number {\n if (value < 0 || value >= maxValue) return -1;\n\n let sum = 0;\n for (let i = 0; i < weights.length; i++) {\n sum += weights[i] as number;\n if (value < sum) return i;\n }\n\n return -1;\n}\n","/**\n * Options for stream connection behavior\n */\nexport type StreamOptions = {\n /** Timeout in ms to wait for initial stream connection before falling back */\n initTimeoutMs: number;\n};\n\n/**\n * Options for polling behavior\n */\nexport type PollingOptions = {\n /** Interval in ms between polling requests */\n intervalMs: number;\n /** Timeout in ms to wait for initial poll before falling back */\n initTimeoutMs: number;\n};\n\n/** Input type for creating a datafile (without metrics) */\nexport type DatafileInput = Packed.Data & {\n /**\n * If a data source is used with a specific sdk key then\n * the sdk key or data source might contain information\n * about the environment to be evaluated\n */\n environment: string;\n /** Vercel project id of the source of these flags */\n projectId: string;\n /**\n * Some older responses might return a string instead of a number. Both will be timestamps.\n */\n configUpdatedAt?: number | string;\n};\n\n/** Datafile with metrics attached (returned by the client) */\nexport type Datafile = DatafileInput & {\n /** Metrics about how the data was retrieved */\n metrics: Metrics;\n};\n\n/** Flag Definitions of a Vercel project */\nexport type BundledDefinitions = DatafileInput & {\n /** when the data was last updated */\n configUpdatedAt: number;\n /** hash of the data */\n digest: string;\n /** version number of the dat */\n revision: number;\n};\n\nexport type BundledDefinitionsResult =\n | { definitions: BundledDefinitions; state: 'ok' }\n | { definitions: null; state: 'missing-file' | 'missing-entry' }\n | { definitions: null; state: 'unexpected-error'; error: unknown };\n\n/**\n * Metrics about how data was retrieved and evaluated\n */\nexport type Metrics = {\n /** Time in ms to read the datafile */\n readMs: number;\n /** Where the data came from */\n source: 'in-memory' | 'embedded' | 'remote';\n /** Whether data was already cached, or stale (fallback used) */\n cacheStatus: 'HIT' | 'MISS' | 'STALE';\n /** Whether the stream is currently connected */\n connectionState: 'connected' | 'disconnected';\n /** Time in ms for the pure flag evaluation logic (only present on EvaluationResult) */\n evaluationMs?: number;\n};\n\n/**\n * DataSource interface for the Vercel Flags client\n */\nexport interface DataSource {\n /**\n * Initialize the data source by fetching the initial file or setting up polling or\n * subscriptions.\n *\n * @see https://openfeature.dev/specification/sections/providers#requirement-241\n */\n initialize: () => Promise<void>;\n\n /**\n * Returns the in-memory data file, which was loaded from initialize and maybe updated from streams.\n */\n read(): Promise<Datafile>;\n\n /**\n * End polling or subscriptions. Flush any remaining data.\n */\n shutdown(): void;\n\n /**\n * Return the actual datafile containing flag definitions.\n */\n getDatafile(): Promise<Datafile>;\n\n /**\n * Returns the bundled fallback definitions.\n * Throws FallbackNotFoundError if the fallback file doesn't exist.\n * Throws FallbackEntryNotFoundError if the file exists but has no entry for the SDK key.\n */\n getFallbackDatafile?(): Promise<BundledDefinitions>;\n}\n\nexport type Source = {\n orgId: string;\n orgSlug: string;\n projectId: string;\n projectSlug: string;\n};\n\n/**\n * A client for Vercel Flags\n */\nexport type FlagsClient = {\n /**\n * Origin information for this client (provider and sdkKey)\n */\n origin?: {\n provider: string;\n sdkKey: string;\n };\n /**\n * Evaluate a feature flag\n *\n * Requires initialize() to have been called and awaited first.\n *\n * @param flagKey\n * @param defaultValue\n * @param entities\n * @returns\n */\n evaluate: <T = Value, E = Record<string, unknown>>(\n flagKey: string,\n defaultValue?: T,\n entities?: E,\n ) => Promise<EvaluationResult<T>>;\n /**\n * Retrieve the latest datafile during startup, and set up subscriptions if needed.\n */\n initialize(): void | Promise<void>;\n /**\n * Facilitates a clean shutdown process which may include flushing telemetry information, or closing remote connections.\n */\n shutdown(): void | Promise<void>;\n /**\n * Returns the actual datafile containing flag definitions\n */\n getDatafile(): Promise<Datafile>;\n /**\n * Returns the bundled fallback definitions.\n * Throws FallbackNotFoundError if the fallback file doesn't exist.\n * Throws FallbackEntryNotFoundError if the file exists but has no entry for the SDK key.\n */\n getFallbackDatafile(): Promise<BundledDefinitions>;\n};\n\nexport type EvaluationParams<T> = {\n entities?: Record<string, unknown>;\n environment: string;\n segments?: Record<SegmentId, Packed.Segment>;\n definition: Packed.FlagDefinition;\n defaultValue?: T;\n};\n\n// Copied from the OpenFeature ErrorCode and commented out unused types\n/**\n * ErrorCodes that can happen during evaluation\n */\nexport enum ErrorCode {\n /**\n * The value was resolved before the provider was ready.\n */\n // PROVIDER_NOT_READY = 'PROVIDER_NOT_READY',\n /**\n * The provider has entered an irrecoverable error state.\n */\n // PROVIDER_FATAL = 'PROVIDER_FATAL',\n /**\n * The flag could not be found.\n */\n FLAG_NOT_FOUND = 'FLAG_NOT_FOUND',\n /**\n * An error was encountered parsing data, such as a flag configuration.\n */\n // PARSE_ERROR = 'PARSE_ERROR',\n /**\n * The type of the flag value does not match the expected type.\n */\n // TYPE_MISMATCH = 'TYPE_MISMATCH',\n /**\n * The provider requires a targeting key and one was not provided in the evaluation context.\n */\n // TARGETING_KEY_MISSING = 'TARGETING_KEY_MISSING',\n /**\n * The evaluation context does not meet provider requirements.\n */\n // INVALID_CONTEXT = 'INVALID_CONTEXT',\n /**\n * An error with an unspecified code.\n */\n // GENERAL = 'GENERAL',\n}\n\n/**\n * The detailed result of a flag evaluation as returned by the client's `evaluate` function.\n */\nexport type EvaluationResult<T> =\n | {\n /**\n * In case of successful evaluations this holds the evaluated value\n */\n value: T;\n /**\n * Indicates whether the outcome was a single variant or a split\n */\n outcomeType?: OutcomeType;\n /**\n * Indicates why the flag evaluated to a certain value\n */\n reason: Exclude<ResolutionReason, ResolutionReason.ERROR>;\n errorMessage?: never;\n errorCode?: never;\n /** Metrics about the evaluation (optional) */\n metrics?: Metrics;\n }\n | {\n reason: ResolutionReason.ERROR;\n errorMessage: string;\n errorCode?: ErrorCode;\n outcomeType?: never;\n /**\n * In cases of errors this is the defaultValue if one was provided\n */\n value?: T;\n /** Metrics about the evaluation (optional) */\n metrics?: Metrics;\n };\n\nexport type FlagKey = string;\nexport type VariantId = string;\nexport type EnvironmentKey = string;\nexport type SegmentId = string;\nexport type Value = string | number | boolean;\n\nexport enum ResolutionReason {\n PAUSED = 'paused',\n TARGET_MATCH = 'target_match',\n RULE_MATCH = 'rule_match',\n FALLTHROUGH = 'fallthrough',\n ERROR = 'error',\n}\n\nexport enum OutcomeType {\n /** When the outcome type was a single variant */\n VALUE = 'value',\n /** When the outcome type was a split */\n SPLIT = 'split',\n}\n\n/**\n * Vercel Flags\n * - is equal to (eq)\n * - is not equal to (!eq)\n * - is one of (oneOf)\n * - is not one of (!oneOf)\n * - contains (contains)\n * - does not contain (!contains)\n * - starts with (startsWith)\n * - does not start with (!startsWith)\n * - ends with (endsWith)\n * - does not end with (!endsWith)\n * - exists (ex)\n * - deos not exist (!ex)\n * - is greater than (gt)\n * - is greater than or equal to (gte)\n * - is lower than (lt)\n * - is lower than or equal to (lte)\n * - matches regex (regex)\n * - does not match regex (!regex)\n * - is before (before)\n * - is after (after)\n */\n\nexport enum Comparator {\n /**\n * lhs must be string | number\n * rhs must be string | number\n * does a strict equality check\n */\n EQ = 'eq',\n /**\n * lhs must be string | number\n * rhs must be string | number\n * does a strict equality check\n */\n NOT_EQ = '!eq',\n /**\n * lhs must be string\n * rhs must be string[]\n */\n ONE_OF = 'oneOf',\n /**\n * lhs must be string\n * rhs must be string[]\n */\n NOT_ONE_OF = '!oneOf',\n /**\n * lhs must be string[]\n * rhs must be string[]\n */\n CONTAINS_ALL_OF = 'containsAllOf',\n /**\n * lhs must be string[]\n * rhs must be string[]\n */\n CONTAINS_ANY_OF = 'containsAnyOf',\n /**\n * lhs must be string[]\n * rhs must be string[]\n */\n CONTAINS_NONE_OF = 'containsNoneOf',\n /**\n * lhs must be string\n * rhs must be string\n *\n * other comparisons have to be handled with a regex\n */\n STARTS_WITH = 'startsWith',\n /**\n * lhs must be string\n * rhs must be string\n *\n * other comparisons have to be handled with a regex\n */\n NOT_STARTS_WITH = '!startsWith',\n /**\n * lhs must be string\n * rhs must be string\n *\n * other comparisons have to be handled with a regex\n */\n ENDS_WITH = 'endsWith',\n /**\n * lhs must be string\n * rhs must be string\n *\n * other comparisons have to be handled with a regex\n */\n NOT_ENDS_WITH = '!endsWith',\n /**\n * lhs must be string\n * rhs must be never\n */\n EXISTS = 'ex',\n /**\n * lhs must be string\n * rhs must be never\n */\n NOT_EXISTS = '!ex',\n /**\n * lhs must be string | number\n * rhs must be string | number\n */\n GT = 'gt',\n /**\n * lhs must be string | number\n * rhs must be string | number\n */\n GTE = 'gte',\n /** */\n /**\n * lhs must be string | number\n * rhs must be string | number\n */\n LT = 'lt',\n /**\n * lhs must be string | number\n * rhs must be string | number\n */\n LTE = 'lte',\n /**\n * lhs must be string\n * rhs must be string\n */\n REGEX = 'regex',\n /**\n * lhs must be string\n * rhs must be string\n */\n NOT_REGEX = '!regex',\n /**\n * lhs must be date string\n * rhs must be date string\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format\n */\n BEFORE = 'before',\n /**\n * lhs must be date string\n * rhs must be date string\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format\n */\n AFTER = 'after',\n}\n\n// -----------------------------------------------------------------------------\n// Original data\n// -----------------------------------------------------------------------------\n\nexport namespace Original {\n export type Data = {\n definitions: Record<string, FlagDefinition>;\n segments?: Original.Segment[];\n };\n\n export enum AccessorType {\n SEGMENT = 'segment',\n ENTITY = 'entity',\n }\n\n export type SegmentOutcome = SegmentAllOutcome | SegmentSplitOutcome;\n\n export type Outcome =\n | {\n type: 'variant';\n variantId: VariantId;\n }\n | {\n type: 'split';\n /**\n * Based on which attribute the traffic should be split\n */\n base: EntityAccessor;\n /**\n * The distribution for each variant\n */\n weights: Record<VariantId, number>;\n /**\n * This variant will be used when the base attribute does not exist\n */\n defaultVariantId: VariantId;\n };\n\n export type SegmentAllOutcome = {\n type: 'all';\n };\n\n export type SegmentSplitOutcome = {\n type: 'split';\n /**\n * Based on which attribute the passing percentage should be split.\n *\n * When the attribute does not exist the segment will not match.\n */\n base: EntityAccessor;\n /**\n * The promille that should pass the segment\n * 1 = 0.001%\n * 1_000 = 1%\n * 100_000 = 100%\n */\n passPromille: number;\n };\n\n export type EntityAccessor = {\n type: AccessorType.ENTITY;\n kind: string;\n attribute: string;\n };\n export type SegmentAccessor = { type: AccessorType.SEGMENT };\n\n export type List = {\n // backwards compatibility, we should only use \"list\" going forward\n type: 'list/inline' | 'list';\n items: { note?: string; value: string | number }[];\n id?: never;\n };\n\n export type LHS = SegmentAccessor | EntityAccessor;\n export type RHS =\n | string\n | number\n | boolean\n | List\n | { type: 'regex'; pattern: string; flags: string };\n\n export type Condition = {\n lhs: LHS;\n cmp: Comparator;\n rhs: RHS;\n };\n\n export type Rule = {\n conditions: Condition[];\n outcome: Outcome;\n };\n\n export type SegmentRule = {\n conditions: Condition[];\n outcome: SegmentAllOutcome | SegmentSplitOutcome;\n };\n\n export type FlagVariant = {\n id: string;\n label?: string;\n description?: string;\n value: Value;\n };\n\n export type EnvironmentConfig = {\n active: boolean;\n pausedOutcome: Outcome;\n /**\n * If enabled, the flag will be reused from the given environment.\n *\n * The flag will not be evaluated, and the outcome will be the same as the given environment.\n * This environment must be active and the flag must be active in this environment.\n */\n reuse: {\n active: boolean;\n environment: EnvironmentKey;\n };\n targets: Record<VariantId, TargetList>;\n rules: Rule[];\n fallthrough: Outcome;\n };\n\n /**\n * A list of targets\n *\n * @example\n * {\n * user: { id: { note?: string; value: string }[] }\n * }\n */\n export type TargetList = Record<\n string,\n Record<string, { note?: string; value: string }[]>\n >;\n\n /**\n * reusable conditions, with no outcome attached\n */\n export type Segment = {\n id: string;\n rules: SegmentRule[];\n /**\n * Explicitly include targets. Included targets will bypass conditions and exclusion.\n *\n * @example\n * include: {\n * user: { id: { note?: string, value: string }[] }\n * }\n */\n include: TargetList;\n /**\n * Explicitly exclude targets. Excluded targets will not be included in the segment, and bypass conditions.\n *\n * @example\n * exclude: {\n * user: { id: { note?: string, value: string }[] }\n * }\n */\n exclude: TargetList;\n };\n\n export type FlagDefinition = {\n variants: FlagVariant[];\n environments: Record<EnvironmentKey, EnvironmentConfig>;\n\n /**\n * A random seed to prevent split points in different flags\n * from having the same targets. Otherwise the same set of ids would be\n * opted into all flags for every rollout. By using a different seed for\n * each flag the distribution is different for every flag.\n *\n * We don't use the slug as it might change, but we don't want the distribution\n * to change when the slug changes.\n *\n * We don't use the id or createdAt etc as we want to be able to redistirbute\n * by changing the seed.\n */\n seed: number;\n };\n}\n\n// -----------------------------------------------------------------------------\n// Packed data\n// -----------------------------------------------------------------------------\n\nexport namespace Packed {\n /**\n * Idenitifies a variant based on its index in the variants array.\n */\n export type VariantIndex = number;\n\n export type Data = {\n /** map of flag keys to definitions */\n definitions: Record<FlagKey, FlagDefinition>;\n /** segments keyed by id */\n segments?: Record<SegmentId, Segment>;\n };\n\n export enum AccessorType {\n SEGMENT = 'segment',\n ENTITY = 'entity',\n }\n\n export type SplitOutcome = {\n type: 'split';\n /**\n * Based on which attribute the traffic should be split.\n */\n base: EntityAccessor;\n /**\n * The distribution of the individual groups.\n *\n * We use a single number array as the numbers will be placed in the\n * same order as the variant list.\n *\n * So index 0 here is the distribution for variant 0, and so on.\n */\n weights: number[];\n /**\n * This variant will be used when the lhs does not exist\n */\n defaultVariant: VariantIndex;\n };\n\n export type SegmentAllOutcome = 1;\n\n export type SegmentSplitOutcome = {\n type: 'split';\n /**\n * Based on which attribute the traffic should be split.\n *\n * When the attribute does not exist the segment will not match.\n */\n base: EntityAccessor;\n /**\n * The promille that should pass the segment (1 = 0.001%; 1000 = 1%)\n */\n passPromille: number;\n };\n\n export type SegmentOutcome = SegmentAllOutcome | SegmentSplitOutcome;\n\n export type Outcome = VariantIndex | SplitOutcome;\n\n // an array means it's an entity, the string \"segment\" means a segment\n export type EntityAccessor = (string | number)[];\n export type SegmentAccessor = 'segment';\n\n /**\n * An array means an entity\n */\n export type LHS = EntityAccessor | SegmentAccessor;\n\n /**\n * undefined when the rhs is not used by the comparator\n * string[] when the rhs is a list of segments\n * { type: 'regex'; pattern: string; flags: string } when the rhs is a regex\n */\n export type RHS =\n | undefined\n | string\n | number\n | boolean\n | (string | number)[]\n | { type: 'regex'; pattern: string; flags: string };\n\n export type Condition =\n | [LHS, Comparator, RHS]\n | [LHS, Comparator.EXISTS]\n | [LHS, Comparator.NOT_EXISTS];\n\n export type Rule = {\n conditions: Condition[];\n outcome: Outcome;\n };\n\n export type SegmentRule = {\n conditions: Condition[];\n outcome: SegmentAllOutcome | SegmentSplitOutcome;\n };\n\n export type EnvironmentConfig =\n /**\n * Paused flags contain the pausedOutcome only.\n */\n | number\n /** Allows reusing the configuration of another environment */\n | { reuse: EnvironmentKey }\n /**\n * Active flags don't contain an explicit \"active\" state.\n * The fact that they have a config means they are active.\n */\n | {\n /**\n * Each array item represents a variant.\n *\n * Each slot holds the targets for that variant.\n *\n * So the target list at index 0 is the targets for variant 0, and so on.\n */\n targets?: TargetList[];\n rules?: Rule[];\n fallthrough: Outcome;\n };\n\n /**\n * A list of targets\n *\n * @example\n * {\n * user: { id: string[] }\n * }\n */\n export type TargetList = Record<string, Record<string, string[]>>;\n\n /**\n * reusable conditions, with no outcome attached\n */\n export type Segment = {\n rules?: SegmentRule[];\n /**\n * Explicitly include targets. Included targets will bypass conditions and exclusion.\n *\n * @example\n * include: {\n * user: { id: string[] }\n * }\n */\n include?: TargetList;\n /**\n * Explicitly exclude targets. Excluded targets will not be included in the segment, and bypass conditions.\n *\n * @example\n * exclude: {\n * user: { id: string[] }\n * }\n */\n exclude?: TargetList;\n };\n\n export type FlagDefinition = {\n /** for backwards compatibility with HappyKit */\n variantIds?: string[];\n /** variants, packed down to just their values */\n variants: Value[];\n /** environments */\n environments: Record<EnvironmentKey, EnvironmentConfig>;\n /**\n * A random seed to prevent split points in different flags\n * from having the same targets. Otherwise the same set of ids would be\n * opted into all flags for every rollout. By using a different seed for\n * each flag the distribution is different for every flag.\n *\n * We don't use the slug as it might change, but we don't want the distribution\n * to change when the slug changes.\n *\n * We don't use the id or createdAt etc as we want to be able to redistirbute\n * by changing the seed.\n */\n seed?: number;\n };\n}\n","/**\n * This function is used to check for exhaustiveness in switch statements.\n *\n * @param _ - The value to check.\n *\n * @example\n * Given `type Union = 'a' | 'b' | 'c'`, the following code will not compile:\n * ```ts\n * switch (union) {\n * case 'a':\n * return 'a';\n * case 'b':\n * return 'b';\n * default:\n * exhaustivenessCheck(union); // This will throw an error\n * }\n * ```\n * This is because `value` has been narrowed to `'c'` by the `default` arm,\n * which is not assignable to `never`. If we covered the `'c'` case, the type\n * would narrow to `never`, which is assignable to `never` and would not cause an error.\n */\nexport function exhaustivenessCheck(_: never): never {\n throw new Error('Exhaustiveness check failed');\n}\n","{\n \"name\": \"@vercel/flags-core\",\n \"version\": \"1.0.1\",\n \"description\": \"\",\n \"keywords\": [],\n \"license\": \"MIT\",\n \"author\": \"\",\n \"sideEffects\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"next-js\": {\n \"types\": \"./dist/index.next-js.d.ts\",\n \"default\": \"./dist/index.next-js.js\"\n },\n \"types\": \"./dist/index.default.d.ts\",\n \"default\": \"./dist/index.default.js\"\n },\n \"./openfeature\": {\n \"next-js\": {\n \"types\": \"./dist/openfeature.next-js.d.ts\",\n \"default\": \"./dist/openfeature.next-js.js\"\n },\n \"types\": \"./dist/openfeature.default.d.ts\",\n \"default\": \"./dist/openfeature.default.js\"\n }\n },\n \"main\": \"./dist/index.default.js\",\n \"typesVersions\": {\n \"*\": {\n \".\": [\n \"dist/index.default.d.ts\"\n ],\n \"openfeature\": [\n \"dist/openfeature.default.d.ts\"\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 \"dependencies\": {\n \"@vercel/functions\": \"^3.3.6\",\n \"jose\": \"5.2.1\",\n \"js-xxhash\": \"4.0.0\"\n },\n \"devDependencies\": {\n \"@arethetypeswrong/cli\": \"0.18.2\",\n \"@types/node\": \"20.11.17\",\n \"flags\": \"workspace:*\",\n \"msw\": \"2.6.4\",\n \"next\": \"16.1.6\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"5.6.3\",\n \"vite\": \"6.4.1\",\n \"vitest\": \"2.1.9\"\n },\n \"peerDependencies\": {\n \"next\": \"*\",\n \"@openfeature/server-sdk\": \"1.18.0\",\n \"flags\": \"*\"\n },\n \"peerDependenciesMeta\": {\n \"@openfeature/server-sdk\": {\n \"optional\": true\n },\n \"next\": {\n \"optional\": true\n }\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import { version } from '../../package.json';\nimport type { OutcomeType, ResolutionReason } from '../types';\n\n/**\n * Only used interally for now.\n */\nexport function internalReportValue(\n key: string,\n value: unknown,\n data: {\n originProjectId?: string;\n originProvider?: 'vercel';\n outcomeType?: OutcomeType;\n reason?: ResolutionReason | 'override';\n },\n) {\n const symbol = Symbol.for('@vercel/request-context');\n const ctx = Reflect.get(globalThis, symbol)?.get();\n ctx?.flags?.reportValue(key, value, {\n sdkVersion: version,\n ...data,\n });\n}\n","import type {\n evaluate,\n getDatafile,\n getFallbackDatafile,\n initialize,\n shutdown,\n} from './client-fns';\nimport { type ClientInstance, clientMap } from './client-map';\nimport type {\n BundledDefinitions,\n DataSource,\n EvaluationResult,\n FlagsClient,\n Value,\n} from './types';\n\nlet idCount = 0;\n\nasync function performInitialize(\n instance: ClientInstance,\n initFn: () => Promise<void>,\n): Promise<void> {\n try {\n await initFn();\n instance.initialized = true;\n } catch (error) {\n // Clear so next call can retry\n instance.initPromise = null;\n throw error;\n }\n}\n\nexport function createCreateRawClient(fns: {\n initialize: typeof initialize;\n shutdown: typeof shutdown;\n getFallbackDatafile: typeof getFallbackDatafile;\n evaluate: typeof evaluate;\n getDatafile: typeof getDatafile;\n}) {\n return function createRawClient({\n dataSource,\n origin,\n }: {\n dataSource: DataSource;\n origin?: { provider: string; sdkKey: string };\n }): FlagsClient {\n const id = idCount++;\n clientMap.set(id, { dataSource, initialized: false, initPromise: null });\n\n const api = {\n origin,\n initialize: async () => {\n let instance = clientMap.get(id);\n if (!instance) {\n instance = { dataSource, initialized: false, initPromise: null };\n clientMap.set(id, instance);\n }\n\n // skip if already initialized\n if (instance.initialized) return;\n\n if (!instance.initPromise) {\n instance.initPromise = performInitialize(instance, () =>\n fns.initialize(id),\n );\n }\n\n return instance.initPromise;\n },\n shutdown: async () => {\n await fns.shutdown(id);\n clientMap.delete(id);\n },\n getDatafile: () => fns.getDatafile(id),\n getFallbackDatafile: (): Promise<BundledDefinitions> => {\n return fns.getFallbackDatafile(id);\n },\n evaluate: async <T = Value, E = Record<string, unknown>>(\n flagKey: string,\n defaultValue?: T,\n entities?: E,\n ): Promise<EvaluationResult<T>> => {\n const instance = clientMap.get(id);\n if (!instance?.initialized) await api.initialize();\n return fns.evaluate<T, E>(id, flagKey, defaultValue, entities);\n },\n };\n return api;\n };\n}\n","/**\n * Error thrown when the fallback definitions file does not exist.\n * This typically means the \"vercel-flags prepare\" command was not run before building.\n */\nexport class FallbackNotFoundError extends Error {\n constructor() {\n super('@vercel/flags-core: Bundled definitions file not found.');\n this.name = 'FallbackNotFoundError';\n }\n}\n\n/**\n * Error thrown when the fallback definitions file exists but has no entry for the SDK key.\n * This means the SDK key was not included when running \"vercel-flags prepare\".\n */\nexport class FallbackEntryNotFoundError extends Error {\n constructor() {\n super('@vercel/flags-core: No bundled definitions found for SDK key.');\n this.name = 'FallbackEntryNotFoundError';\n }\n}\n","// The @vercel/flags-definitions module is created at build time by Vercel CLI\n// in node_modules/. This is a fallback mechanism used so the app can always\n// fall back to a bundled version of the definitions, even if the flags network\n// is degraded or unavailable.\n//\n\nimport type { BundledDefinitions, BundledDefinitionsResult } from '../types';\n\n/** In-memory cache of SDK key to its hashed value, so we don't re-hash repeatedly. */\nconst sdkKeyHashCache = new Map<string, Promise<string>>();\n\n/** Computes a SHA-256 hex digest of the given SDK key. */\nasync function computeHash(sdkKey: string): Promise<string> {\n const hashBuffer = await crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(sdkKey),\n );\n const hashArray = new Uint8Array(hashBuffer);\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/** Returns a cached promise for the SHA-256 hash of the given SDK key. */\nfunction hashSdkKey(sdkKey: string): Promise<string> {\n const cached = sdkKeyHashCache.get(sdkKey);\n if (cached) return cached;\n\n const promise = computeHash(sdkKey);\n sdkKeyHashCache.set(sdkKey, promise);\n return promise;\n}\n\n/**\n * Reads the local definitions that get bundled at build time.\n */\nexport async function readBundledDefinitions(\n sdkKey: string,\n): Promise<BundledDefinitionsResult> {\n let get: (sdkKey: string) => BundledDefinitions | null;\n try {\n const module = await import(\n /* turbopackOptional: true */\n // @ts-expect-error this only exists at build time\n '@vercel/flags-definitions'\n );\n get = module.get;\n } catch (error) {\n // If the module doesn't exist, the prepare script didn't run\n if (\n error &&\n typeof error === 'object' &&\n 'code' in error &&\n error.code === 'MODULE_NOT_FOUND'\n ) {\n return { definitions: null, state: 'missing-file' };\n }\n\n return { definitions: null, state: 'unexpected-error', error };\n }\n\n // try plain sdk key first\n const entry = get(sdkKey);\n if (entry) return { definitions: entry, state: 'ok' };\n\n // try hashed key but catch any errors\n try {\n const hashedKey = await hashSdkKey(sdkKey);\n // try original key (older cli versions) and hashed key (newer cli versions)\n const hashedEntry = get(hashedKey);\n if (hashedEntry) return { definitions: hashedEntry, state: 'ok' };\n } catch (error) {\n return { definitions: null, state: 'unexpected-error', error };\n }\n\n return { definitions: null, state: 'missing-entry' };\n}\n","export function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { waitUntil } from '@vercel/functions';\nimport { version } from '../../package.json';\n\nconst RESOLVED_VOID: Promise<void> = Promise.resolve();\n\nconst isDebugMode = process.env.DEBUG?.includes('@vercel/flags-core');\n\nconst debugLog = (...args: any[]) => {\n if (!isDebugMode) return;\n console.log(...args);\n};\n\nexport interface FlagsConfigReadEvent {\n type: 'FLAGS_CONFIG_READ';\n ts: number;\n payload: {\n deploymentId?: string;\n region?: string;\n invocationHost?: string;\n vercelRequestId?: string;\n cacheStatus?: 'HIT' | 'MISS';\n cacheIsBlocking?: boolean;\n cacheIsFirstRead?: boolean;\n duration?: number;\n configUpdatedAt?: number;\n configOrigin?: 'in-memory' | 'embedded';\n };\n}\n\ninterface EventBatcher {\n events: FlagsConfigReadEvent[];\n /** Resolves the current wait period early (e.g., when batch size is reached) */\n resolveWait: (() => void) | null;\n /** Promise for flush operation */\n pending: null | Promise<void>;\n}\n\nconst MAX_BATCH_SIZE = 50;\nconst MAX_BATCH_WAIT_MS = 5000;\n\n// WeakSet to track request contexts that have already been recorded\n// Using WeakSet allows the context objects to be garbage collected\nconst trackedRequests = new WeakSet<object>();\n\ninterface RequestContext {\n ctx: object | undefined;\n headers: Record<string, string> | undefined;\n}\n\nconst SYMBOL_FOR_REQ_CONTEXT = Symbol.for('@vercel/request-context');\nconst fromSymbol = globalThis as typeof globalThis & {\n [key: symbol]:\n | { get?: () => { headers?: Record<string, string> } }\n | undefined;\n};\n\n/**\n * Gets the Vercel request context and headers from the global symbol.\n */\nfunction getRequestContext(): RequestContext {\n try {\n const ctx = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.();\n if (ctx && Object.hasOwn(ctx, 'headers')) {\n return {\n ctx,\n headers: ctx.headers as Record<string, string>,\n };\n }\n return { ctx, headers: undefined };\n } catch {\n return { ctx: undefined, headers: undefined };\n }\n}\n\nexport interface UsageTrackerOptions {\n sdkKey: string;\n host: string;\n}\n\nexport interface TrackReadOptions {\n /** Whether the config was read from in-memory cache or embedded bundle */\n configOrigin: 'in-memory' | 'embedded';\n /** HIT when definitions exist in memory, MISS when not. Omitted for embedded reads. */\n cacheStatus?: 'HIT' | 'MISS';\n /** True for the very first getData call */\n cacheIsFirstRead?: boolean;\n /** Whether the cache read was blocking */\n cacheIsBlocking?: boolean;\n /** Duration in milliseconds from start of getData until trackRead */\n duration?: number;\n /** Timestamp when the config was last updated */\n configUpdatedAt?: number;\n}\n\n/**\n * Tracks usage events and batches them for submission to the ingest endpoint.\n */\nexport class UsageTracker {\n private sdkKey: string;\n private host: string;\n private batcher: EventBatcher = {\n events: [],\n resolveWait: null,\n pending: null,\n };\n\n constructor(options: UsageTrackerOptions) {\n this.sdkKey = options.sdkKey;\n this.host = options.host;\n }\n\n /**\n * Triggers an immediate flush of any pending events.\n * Returns a promise that resolves when the flush completes.\n */\n flush(): Promise<void> {\n this.batcher.resolveWait?.();\n return this.batcher.pending ?? RESOLVED_VOID;\n }\n\n /**\n * Tracks a config read event. Deduplicates by request context.\n */\n trackRead(options?: TrackReadOptions): void {\n try {\n const { ctx, headers } = getRequestContext();\n\n // Skip if we've already tracked this request\n if (ctx) {\n if (trackedRequests.has(ctx)) return;\n trackedRequests.add(ctx);\n }\n\n const event: FlagsConfigReadEvent = {\n type: 'FLAGS_CONFIG_READ',\n ts: Date.now(),\n payload: {\n deploymentId: process.env.VERCEL_DEPLOYMENT_ID,\n region: process.env.VERCEL_REGION,\n },\n };\n\n if (headers) {\n event.payload.vercelRequestId = headers['x-vercel-id'] ?? undefined;\n event.payload.invocationHost = headers.host ?? undefined;\n }\n\n if (options) {\n event.payload.configOrigin = options.configOrigin;\n if (options.cacheStatus !== undefined) {\n event.payload.cacheStatus = options.cacheStatus;\n }\n if (options.cacheIsFirstRead !== undefined) {\n event.payload.cacheIsFirstRead = options.cacheIsFirstRead;\n }\n if (options.cacheIsBlocking !== undefined) {\n event.payload.cacheIsBlocking = options.cacheIsBlocking;\n }\n if (options.duration !== undefined) {\n event.payload.duration = options.duration;\n }\n if (options.configUpdatedAt !== undefined) {\n event.payload.configUpdatedAt = options.configUpdatedAt;\n }\n }\n\n this.batcher.events.push(event);\n this.scheduleFlush();\n } catch (error) {\n // trackRead should never throw, but log the error\n console.error('@vercel/flags-core: Failed to record event:', error);\n }\n }\n\n private scheduleFlush(): void {\n if (!this.batcher.pending) {\n let timeout: null | ReturnType<typeof setTimeout> = null;\n\n const pending = (async () => {\n await new Promise<void>((res) => {\n this.batcher.resolveWait = res;\n timeout = setTimeout(res, MAX_BATCH_WAIT_MS);\n });\n\n this.batcher.pending = null;\n this.batcher.resolveWait = null;\n if (timeout) clearTimeout(timeout);\n\n await this.flushEvents();\n })();\n\n // Use waitUntil to keep the function alive until flush completes\n // If `waitUntil` is not available this will be a no-op and leave\n // a floating promise that will be completed in the background\n waitUntil(pending);\n\n this.batcher.pending = pending;\n }\n\n // Trigger early flush if threshold was reached\n if (this.batcher.events.length >= MAX_BATCH_SIZE) {\n this.batcher.resolveWait?.();\n }\n }\n\n private async flushEvents(): Promise<void> {\n if (this.batcher.events.length === 0) return;\n\n // Take all events and clear the queue\n const eventsToSend = this.batcher.events;\n this.batcher.events = [];\n\n try {\n const response = await fetch(`${this.host}/v1/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.sdkKey}`,\n 'User-Agent': `VercelFlagsCore/${version}`,\n ...(isDebugMode ? { 'x-vercel-debug-ingest': '1' } : null),\n },\n body: JSON.stringify(eventsToSend),\n });\n\n debugLog(\n `@vercel/flags-core: Ingest response ${response.status} for ${eventsToSend.length} events on ${response.headers.get('x-vercel-id')}`,\n );\n\n if (!response.ok) {\n debugLog(\n '@vercel/flags-core: Failed to send events:',\n response.statusText,\n );\n }\n } catch (error) {\n debugLog('@vercel/flags-core: Error sending events:', error);\n }\n }\n}\n","import { version } from '../../package.json';\nimport type { BundledDefinitions } from '../types';\nimport { sleep } from '../utils/sleep';\n\nexport type StreamMessage =\n | { type: 'datafile'; data: BundledDefinitions }\n | { type: 'ping' };\n\nconst MAX_RETRY_COUNT = 15;\nconst BASE_DELAY_MS = 1000;\nconst MAX_DELAY_MS = 60_000;\n\nfunction backoff(retryCount: number): number {\n if (retryCount === 1) return 0;\n const delay = Math.min(BASE_DELAY_MS * 2 ** (retryCount - 2), MAX_DELAY_MS);\n return delay + Math.random() * 1000;\n}\n\nexport type StreamCallbacks = {\n onMessage: (data: BundledDefinitions) => void;\n onDisconnect?: () => void;\n};\n\nexport type StreamConfig = {\n host: string;\n sdkKey: string;\n abortController: AbortController;\n fetch?: typeof globalThis.fetch;\n};\n\n/**\n * Connects to the flags stream endpoint and handles reconnection with backoff.\n * Resolves when the first datafile message is received.\n * Rejects if the connection fails before receiving any data.\n */\nexport async function connectStream(\n config: StreamConfig,\n callbacks: StreamCallbacks,\n): Promise<void> {\n const {\n host,\n sdkKey,\n abortController,\n fetch: fetchFn = globalThis.fetch,\n } = config;\n const { onMessage, onDisconnect } = callbacks;\n let retryCount = 0;\n\n let resolveInit: () => void;\n let rejectInit: (error: unknown) => void;\n const initPromise = new Promise<void>((resolve, reject) => {\n resolveInit = resolve;\n rejectInit = reject;\n });\n\n void (async () => {\n let initialDataReceived = false;\n\n while (!abortController.signal.aborted) {\n if (retryCount > MAX_RETRY_COUNT) {\n console.error('@vercel/flags-core: Max retry count exceeded');\n abortController.abort();\n break;\n }\n\n try {\n const response = await fetchFn(`${host}/v1/stream`, {\n headers: {\n Authorization: `Bearer ${sdkKey}`,\n 'User-Agent': `VercelFlagsCore/${version}`,\n 'X-Retry-Attempt': String(retryCount),\n },\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n abortController.abort();\n }\n\n throw new Error(`stream was not ok: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error('stream body was not present');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n for await (const chunk of response.body) {\n if (abortController.signal.aborted) break;\n\n buffer += decoder.decode(chunk, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop()!;\n\n for (const line of lines) {\n if (line === '') continue;\n\n let message: StreamMessage;\n try {\n message = JSON.parse(line) as StreamMessage;\n } catch {\n console.warn(\n '@vercel/flags-core: Failed to parse stream message, skipping',\n );\n continue;\n }\n\n if (message.type === 'datafile') {\n onMessage(message.data);\n retryCount = 0;\n if (!initialDataReceived) {\n initialDataReceived = true;\n resolveInit!();\n }\n }\n }\n }\n\n // Stream ended normally (server closed connection) - reconnect\n if (!abortController.signal.aborted) {\n onDisconnect?.();\n retryCount++;\n await sleep(backoff(retryCount));\n continue;\n }\n } catch (error) {\n if (abortController.signal.aborted) {\n break;\n }\n console.error('@vercel/flags-core: Stream error', error);\n onDisconnect?.();\n if (!initialDataReceived) {\n rejectInit!(error);\n break;\n }\n retryCount++;\n await sleep(backoff(retryCount));\n }\n }\n })();\n\n return initPromise;\n}\n","import { version } from '../../package.json';\nimport { FallbackEntryNotFoundError, FallbackNotFoundError } from '../errors';\nimport type {\n BundledDefinitions,\n BundledDefinitionsResult,\n Datafile,\n DatafileInput,\n DataSource,\n Metrics,\n PollingOptions,\n StreamOptions,\n} from '../types';\nimport { readBundledDefinitions } from '../utils/read-bundled-definitions';\nimport { sleep } from '../utils/sleep';\nimport { type TrackReadOptions, UsageTracker } from '../utils/usage-tracker';\nimport { connectStream } from './stream-connection';\n\nconst FLAGS_HOST = 'https://flags.vercel.com';\nconst DEFAULT_STREAM_INIT_TIMEOUT_MS = 3000;\nconst DEFAULT_POLLING_INTERVAL_MS = 30_000;\nconst DEFAULT_POLLING_INIT_TIMEOUT_MS = 3_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\nconst MAX_FETCH_RETRIES = 3;\nconst FETCH_RETRY_BASE_DELAY_MS = 500;\n\n/**\n * Configuration options for FlagNetworkDataSource\n */\nexport type FlagNetworkDataSourceOptions = {\n /** SDK key for authentication (must start with \"vf_\") */\n sdkKey: string;\n\n /**\n * Initial datafile to use immediately\n * - At runtime: used while waiting for stream/poll, then updated in background\n * - At build step: used as primary source (skips network)\n */\n datafile?: DatafileInput;\n\n /**\n * Configure streaming connection (runtime only, ignored during build step)\n * - `true`: Enable with default options (initTimeoutMs: 3000)\n * - `false`: Disable streaming\n * - `{ initTimeoutMs: number }`: Enable with custom timeout\n * @default true\n */\n stream?: boolean | StreamOptions;\n\n /**\n * Configure polling fallback (runtime only, ignored during build step)\n * - `true`: Enable with default options (intervalMs: 30000, initTimeoutMs: 3000)\n * - `false`: Disable polling\n * - `{ intervalMs: number, initTimeoutMs: number }`: Enable with custom options\n * @default true\n */\n polling?: boolean | PollingOptions;\n\n /**\n * Override build step detection\n * - `true`: Treat as build step (use datafile/bundled only, no network)\n * - `false`: Treat as runtime (try stream/poll first)\n * @default auto-detected via CI=1 or NEXT_PHASE=phase-production-build\n */\n buildStep?: boolean;\n\n /**\n * Custom fetch function for making HTTP requests.\n * Useful for testing (e.g. resolving to a different IP).\n * @default globalThis.fetch\n */\n fetch?: typeof globalThis.fetch;\n};\n\n/**\n * Normalized internal options\n */\ntype NormalizedOptions = {\n sdkKey: string;\n datafile: DatafileInput | undefined;\n stream: { enabled: boolean; initTimeoutMs: number };\n polling: { enabled: boolean; intervalMs: number; initTimeoutMs: number };\n buildStep: boolean;\n fetch: typeof globalThis.fetch;\n};\n\n/**\n * Normalizes user-provided options to internal format with defaults\n */\nfunction normalizeOptions(\n options: FlagNetworkDataSourceOptions,\n): NormalizedOptions {\n const autoDetectedBuildStep =\n process.env.CI === '1' ||\n process.env.NEXT_PHASE === 'phase-production-build';\n const buildStep = options.buildStep ?? autoDetectedBuildStep;\n\n let stream: NormalizedOptions['stream'];\n if (options.stream === undefined || options.stream === true) {\n stream = { enabled: true, initTimeoutMs: DEFAULT_STREAM_INIT_TIMEOUT_MS };\n } else if (options.stream === false) {\n stream = { enabled: false, initTimeoutMs: 0 };\n } else {\n stream = { enabled: true, initTimeoutMs: options.stream.initTimeoutMs };\n }\n\n let polling: NormalizedOptions['polling'];\n if (options.polling === undefined || options.polling === true) {\n polling = {\n enabled: true,\n intervalMs: DEFAULT_POLLING_INTERVAL_MS,\n initTimeoutMs: DEFAULT_POLLING_INIT_TIMEOUT_MS,\n };\n } else if (options.polling === false) {\n polling = { enabled: false, intervalMs: 0, initTimeoutMs: 0 };\n } else {\n polling = {\n enabled: true,\n intervalMs: options.polling.intervalMs,\n initTimeoutMs: options.polling.initTimeoutMs,\n };\n }\n\n return {\n sdkKey: options.sdkKey,\n datafile: options.datafile,\n stream,\n polling,\n buildStep,\n fetch: options.fetch ?? globalThis.fetch,\n };\n}\n\n/**\n * Fetches the datafile from the flags service with retry logic.\n *\n * Implements exponential backoff with jitter for transient failures.\n * Does not retry 4xx errors (except 429) as they indicate client errors.\n */\nasync function fetchDatafile(\n host: string,\n sdkKey: string,\n fetchFn: typeof globalThis.fetch,\n): Promise<BundledDefinitions> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < MAX_FETCH_RETRIES; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n DEFAULT_FETCH_TIMEOUT_MS,\n );\n\n let shouldRetry = true;\n try {\n const res = await fetchFn(`${host}/v1/datafile`, {\n headers: {\n Authorization: `Bearer ${sdkKey}`,\n 'User-Agent': `VercelFlagsCore/${version}`,\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!res.ok) {\n // Don't retry 4xx errors (except 429)\n if (res.status >= 400 && res.status < 500 && res.status !== 429) {\n shouldRetry = false;\n }\n throw new Error(`Failed to fetch data: ${res.statusText}`);\n }\n\n return res.json() as Promise<BundledDefinitions>;\n } catch (error) {\n clearTimeout(timeoutId);\n lastError =\n error instanceof Error ? error : new Error('Unknown fetch error');\n\n if (!shouldRetry) throw lastError;\n\n if (attempt < MAX_FETCH_RETRIES - 1) {\n const delay =\n FETCH_RETRY_BASE_DELAY_MS * 2 ** attempt + Math.random() * 500;\n await sleep(delay);\n }\n }\n }\n\n throw lastError ?? new Error('Failed to fetch data after retries');\n}\n\n/**\n * A DataSource implementation that connects to flags.vercel.com.\n *\n * Behavior differs based on environment:\n *\n * **Build step** (CI=1 or Next.js build, or buildStep: true):\n * - Uses datafile (if provided) or bundled definitions\n * - No streaming or polling (avoids network during build)\n *\n * **Runtime** (default):\n * - Tries stream first, then poll, then datafile, then bundled\n * - Stream and polling never run simultaneously\n * - If stream reconnects while polling → stop polling\n * - If stream disconnects → start polling (if enabled)\n */\nexport class FlagNetworkDataSource implements DataSource {\n private options: NormalizedOptions;\n private host = FLAGS_HOST;\n\n // Data state\n private data: DatafileInput | undefined;\n private bundledDefinitionsPromise:\n | Promise<BundledDefinitionsResult>\n | undefined;\n\n // Stream state\n private streamAbortController: AbortController | undefined;\n private streamPromise: Promise<void> | undefined;\n private isStreamConnected: boolean = false;\n private hasWarnedAboutStaleData: boolean = false;\n\n // Polling state\n private pollingIntervalId: ReturnType<typeof setInterval> | undefined;\n private pollingAbortController: AbortController | undefined;\n\n // Initialization state — suppresses onDisconnect from starting polling\n // while initialize() is still running its own fallback chain\n private isInitializing: boolean = false;\n\n // Usage tracking\n private usageTracker: UsageTracker;\n private isFirstGetData: boolean = true;\n\n /**\n * Creates a new FlagNetworkDataSource instance.\n */\n constructor(options: FlagNetworkDataSourceOptions) {\n if (\n !options.sdkKey ||\n typeof options.sdkKey !== 'string' ||\n !options.sdkKey.startsWith('vf_')\n ) {\n throw new Error(\n '@vercel/flags-core: SDK key must be a string starting with \"vf_\"',\n );\n }\n\n this.options = normalizeOptions(options);\n\n // Always load bundled definitions as ultimate fallback\n this.bundledDefinitionsPromise = readBundledDefinitions(\n this.options.sdkKey,\n );\n\n // If datafile provided, use it immediately\n if (this.options.datafile) {\n this.data = this.options.datafile;\n }\n\n this.usageTracker = new UsageTracker({\n sdkKey: this.options.sdkKey,\n host: this.host,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Public API (DataSource interface)\n // ---------------------------------------------------------------------------\n\n /**\n * Initializes the data source.\n *\n * Build step: datafile → bundled → fetch\n * Runtime: stream → poll → datafile → bundled\n */\n async initialize(): Promise<void> {\n if (this.options.buildStep) {\n await this.initializeForBuildStep();\n return;\n }\n\n // Hydrate from provided datafile if not already set (e.g., after shutdown)\n // Usually the constructor sets this, but if the client was shutdown and\n // then init'd again we need to set it again. This also means that any\n // previous data we've seen before shutdown is lost. We'll \"start fresh\".\n if (!this.data && this.options.datafile) {\n this.data = this.options.datafile;\n }\n\n // If we already have data (from provided datafile), start background updates\n // but don't block on them\n if (this.data) {\n this.startBackgroundUpdates();\n return;\n }\n\n this.isInitializing = true;\n try {\n // Try stream first\n if (this.options.stream.enabled) {\n const streamSuccess = await this.tryInitializeStream();\n if (streamSuccess) return;\n }\n\n // Fall back to polling\n if (this.options.polling.enabled) {\n const pollingSuccess = await this.tryInitializePolling();\n if (pollingSuccess) return;\n }\n\n // Fall back to provided datafile (already set in constructor if provided)\n if (this.data) return;\n\n // Fall back to bundled definitions\n await this.initializeFromBundled();\n } finally {\n this.isInitializing = false;\n }\n }\n\n /**\n * Reads the current datafile with metrics.\n */\n async read(): Promise<Datafile> {\n const startTime = Date.now();\n const cachedData = this.data;\n const cacheHadDefinitions = cachedData !== undefined;\n const isFirstRead = this.isFirstGetData;\n this.isFirstGetData = false;\n\n let result: DatafileInput;\n let source: Metrics['source'];\n let cacheStatus: Metrics['cacheStatus'];\n\n if (this.options.buildStep) {\n [result, source, cacheStatus] = await this.getDataForBuildStep();\n } else if (cachedData) {\n [result, source, cacheStatus] = this.getDataFromCache(cachedData);\n } else {\n [result, source, cacheStatus] = await this.getDataWithFallbacks();\n }\n\n const readMs = Date.now() - startTime;\n this.trackRead(startTime, cacheHadDefinitions, isFirstRead, source);\n\n return Object.assign(result, {\n metrics: {\n readMs,\n source,\n cacheStatus,\n connectionState: this.isStreamConnected\n ? ('connected' as const)\n : ('disconnected' as const),\n },\n }) satisfies Datafile;\n }\n\n /**\n * Shuts down the data source and releases resources.\n */\n async shutdown(): Promise<void> {\n this.stopStream();\n this.stopPolling();\n this.data = this.options.datafile;\n this.isInitializing = false;\n this.isStreamConnected = false;\n this.hasWarnedAboutStaleData = false;\n await this.usageTracker.flush();\n }\n\n /**\n * Returns the datafile with metrics.\n *\n * During builds this will read from the bundled file if available.\n *\n * This method never opens a streaming connection, but will read from\n * the stream if it is already open. Otherwise it fetches over the network.\n */\n async getDatafile(): Promise<Datafile> {\n const startTime = Date.now();\n\n let result: DatafileInput;\n let source: Metrics['source'];\n let cacheStatus: Metrics['cacheStatus'];\n\n if (this.options.buildStep) {\n [result, source, cacheStatus] = await this.getDataForBuildStep();\n } else if (this.isStreamConnected && this.data) {\n [result, source, cacheStatus] = this.getDataFromCache();\n } else {\n const fetched = await fetchDatafile(\n this.host,\n this.options.sdkKey,\n this.options.fetch,\n );\n if (this.isNewerData(fetched)) {\n this.data = fetched;\n }\n [result, source, cacheStatus] = [this.data ?? fetched, 'remote', 'MISS'];\n }\n\n return Object.assign(result, {\n metrics: {\n readMs: Date.now() - startTime,\n source,\n cacheStatus,\n connectionState: this.isStreamConnected\n ? ('connected' as const)\n : ('disconnected' as const),\n },\n }) satisfies Datafile;\n }\n\n /**\n * Returns the bundled fallback datafile.\n */\n async getFallbackDatafile(): Promise<BundledDefinitions> {\n if (!this.bundledDefinitionsPromise) {\n throw new FallbackNotFoundError();\n }\n\n const bundledResult = await this.bundledDefinitionsPromise;\n\n if (!bundledResult) {\n throw new FallbackNotFoundError();\n }\n\n switch (bundledResult.state) {\n case 'ok':\n return bundledResult.definitions;\n case 'missing-file':\n throw new FallbackNotFoundError();\n case 'missing-entry':\n throw new FallbackEntryNotFoundError();\n case 'unexpected-error':\n throw new Error(\n '@vercel/flags-core: Failed to read bundled definitions: ' +\n String(bundledResult.error),\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // Stream management\n // ---------------------------------------------------------------------------\n\n /**\n * Attempts to initialize via stream with timeout.\n * Returns true if stream connected successfully within timeout.\n */\n private async tryInitializeStream(): Promise<boolean> {\n let streamPromise: Promise<void>;\n\n if (this.options.stream.initTimeoutMs <= 0) {\n // No timeout - wait indefinitely\n try {\n streamPromise = this.startStream();\n await streamPromise;\n return true;\n } catch {\n return false;\n }\n }\n\n // Race against timeout\n let timeoutId: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<'timeout'>((resolve) => {\n timeoutId = setTimeout(\n () => resolve('timeout'),\n this.options.stream.initTimeoutMs,\n );\n });\n\n try {\n streamPromise = this.startStream();\n const result = await Promise.race([streamPromise, timeoutPromise]);\n clearTimeout(timeoutId!);\n\n if (result === 'timeout') {\n console.warn(\n '@vercel/flags-core: Stream initialization timeout, falling back',\n );\n // Don't abort stream - let it continue trying in background\n return false;\n }\n\n return true;\n } catch {\n clearTimeout(timeoutId!);\n return false;\n }\n }\n\n /**\n * Starts the stream connection with callbacks for data and disconnect.\n */\n private startStream(): Promise<void> {\n if (this.streamPromise) return this.streamPromise;\n\n this.streamAbortController = new AbortController();\n this.isStreamConnected = false;\n this.hasWarnedAboutStaleData = false;\n\n try {\n const streamPromise = connectStream(\n {\n host: this.host,\n sdkKey: this.options.sdkKey,\n abortController: this.streamAbortController,\n fetch: this.options.fetch,\n },\n {\n onMessage: (newData) => {\n if (this.isNewerData(newData)) {\n this.data = newData;\n }\n this.isStreamConnected = true;\n this.hasWarnedAboutStaleData = false;\n\n // Stream is working - stop polling if it's running\n if (this.pollingIntervalId) {\n this.stopPolling();\n }\n },\n onDisconnect: () => {\n this.isStreamConnected = false;\n\n // Fall back to polling if enabled and not already polling.\n // Skip during initialization — initialize() manages its own\n // fallback chain and will start polling itself if needed.\n if (\n this.options.polling.enabled &&\n !this.pollingIntervalId &&\n !this.isInitializing\n ) {\n this.startPolling();\n }\n },\n },\n );\n\n this.streamPromise = streamPromise;\n return streamPromise;\n } catch (error) {\n this.streamPromise = undefined;\n this.streamAbortController = undefined;\n throw error;\n }\n }\n\n /**\n * Stops the stream connection.\n */\n private stopStream(): void {\n this.streamAbortController?.abort();\n this.streamAbortController = undefined;\n this.streamPromise = undefined;\n }\n\n // ---------------------------------------------------------------------------\n // Polling management\n // ---------------------------------------------------------------------------\n\n /**\n * Attempts to initialize via polling with timeout.\n * Returns true if first poll succeeded within timeout.\n */\n private async tryInitializePolling(): Promise<boolean> {\n this.pollingAbortController = new AbortController();\n\n // Perform initial poll\n const pollPromise = this.performPoll();\n\n if (this.options.polling.initTimeoutMs <= 0) {\n // No timeout - wait indefinitely\n try {\n await pollPromise;\n if (this.data) {\n this.startPollingInterval();\n return true;\n }\n return false;\n } catch {\n return false;\n }\n }\n\n // Race against timeout\n let timeoutId: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<'timeout'>((resolve) => {\n timeoutId = setTimeout(\n () => resolve('timeout'),\n this.options.polling.initTimeoutMs,\n );\n });\n\n try {\n const result = await Promise.race([pollPromise, timeoutPromise]);\n clearTimeout(timeoutId!);\n\n if (result === 'timeout') {\n console.warn(\n '@vercel/flags-core: Polling initialization timeout, falling back',\n );\n return false;\n }\n\n if (this.data) {\n this.startPollingInterval();\n return true;\n }\n return false;\n } catch {\n clearTimeout(timeoutId!);\n return false;\n }\n }\n\n /**\n * Starts polling (initial poll + interval).\n */\n private startPolling(): void {\n if (this.pollingIntervalId) return;\n\n this.pollingAbortController = new AbortController();\n\n // Perform initial poll\n void this.performPoll();\n\n // Start interval\n this.startPollingInterval();\n }\n\n /**\n * Starts the polling interval (without initial poll).\n */\n private startPollingInterval(): void {\n if (this.pollingIntervalId) return;\n\n this.pollingIntervalId = setInterval(\n () => void this.performPoll(),\n this.options.polling.intervalMs,\n );\n }\n\n /**\n * Stops polling.\n */\n private stopPolling(): void {\n if (this.pollingIntervalId) {\n clearInterval(this.pollingIntervalId);\n this.pollingIntervalId = undefined;\n }\n this.pollingAbortController?.abort();\n this.pollingAbortController = undefined;\n }\n\n /**\n * Performs a single poll request.\n */\n private async performPoll(): Promise<void> {\n if (this.pollingAbortController?.signal.aborted) return;\n\n try {\n const data = await fetchDatafile(\n this.host,\n this.options.sdkKey,\n this.options.fetch,\n );\n if (this.isNewerData(data)) {\n this.data = data;\n }\n } catch (error) {\n console.error('@vercel/flags-core: Poll failed:', error);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Background updates\n // ---------------------------------------------------------------------------\n\n /**\n * Starts background updates (stream or polling) without blocking.\n * Used when we already have data from provided datafile.\n */\n private startBackgroundUpdates(): void {\n if (this.options.stream.enabled) {\n void this.startStream();\n } else if (this.options.polling.enabled) {\n this.startPolling();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Build step helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Initializes data for build step environments.\n */\n private async initializeForBuildStep(): Promise<void> {\n if (this.data) return;\n\n if (this.bundledDefinitionsPromise) {\n const bundledResult = await this.bundledDefinitionsPromise;\n if (bundledResult?.state === 'ok' && bundledResult.definitions) {\n this.data = bundledResult.definitions;\n return;\n }\n }\n\n this.data = await fetchDatafile(\n this.host,\n this.options.sdkKey,\n this.options.fetch,\n );\n }\n\n /**\n * Retrieves data during build steps.\n */\n private async getDataForBuildStep(): Promise<\n [DatafileInput, Metrics['source'], Metrics['cacheStatus']]\n > {\n if (this.data) {\n return [this.data, 'in-memory', 'HIT'];\n }\n\n if (this.bundledDefinitionsPromise) {\n const bundledResult = await this.bundledDefinitionsPromise;\n if (bundledResult?.state === 'ok' && bundledResult.definitions) {\n this.data = bundledResult.definitions;\n return [this.data, 'embedded', 'MISS'];\n }\n }\n\n this.data = await fetchDatafile(\n this.host,\n this.options.sdkKey,\n this.options.fetch,\n );\n return [this.data, 'remote', 'MISS'];\n }\n\n // ---------------------------------------------------------------------------\n // Runtime helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Returns data from the in-memory cache.\n */\n private getDataFromCache(\n cachedData?: DatafileInput,\n ): [DatafileInput, Metrics['source'], Metrics['cacheStatus']] {\n const data = cachedData ?? this.data!;\n this.warnIfDisconnected();\n const cacheStatus = this.isStreamConnected ? 'HIT' : 'STALE';\n return [data, 'in-memory', cacheStatus];\n }\n\n /**\n * Retrieves data using the fallback chain.\n */\n private async getDataWithFallbacks(): Promise<\n [DatafileInput, Metrics['source'], Metrics['cacheStatus']]\n > {\n // Try stream with timeout\n if (this.options.stream.enabled) {\n const streamSuccess = await this.tryInitializeStream();\n if (streamSuccess && this.data) {\n return [this.data, 'in-memory', 'MISS'];\n }\n }\n\n // Try polling with timeout\n if (this.options.polling.enabled) {\n const pollingSuccess = await this.tryInitializePolling();\n if (pollingSuccess && this.data) {\n return [this.data, 'remote', 'MISS'];\n }\n }\n\n // Use provided datafile\n if (this.options.datafile) {\n this.data = this.options.datafile;\n return [this.data, 'in-memory', 'STALE'];\n }\n\n // Use bundled definitions\n if (this.bundledDefinitionsPromise) {\n const bundledResult = await this.bundledDefinitionsPromise;\n if (bundledResult?.state === 'ok' && bundledResult.definitions) {\n console.warn(\n '@vercel/flags-core: Using bundled definitions as fallback',\n );\n this.data = bundledResult.definitions;\n return [this.data, 'embedded', 'STALE'];\n }\n }\n\n throw new Error(\n '@vercel/flags-core: No flag definitions available. ' +\n 'Ensure streaming/polling is enabled or provide a datafile.',\n );\n }\n\n /**\n * Initializes from bundled definitions.\n */\n private async initializeFromBundled(): Promise<void> {\n if (!this.bundledDefinitionsPromise) {\n throw new Error(\n '@vercel/flags-core: No flag definitions available. ' +\n 'Ensure streaming/polling is enabled or provide a datafile.',\n );\n }\n\n const bundledResult = await this.bundledDefinitionsPromise;\n if (bundledResult?.state === 'ok' && bundledResult.definitions) {\n this.data = bundledResult.definitions;\n return;\n }\n\n throw new Error(\n '@vercel/flags-core: No flag definitions available. ' +\n 'Bundled definitions not found.',\n );\n }\n\n /**\n * Parses a configUpdatedAt value (number or string) into a numeric timestamp.\n * Returns undefined if the value is missing or cannot be parsed.\n */\n private static parseConfigUpdatedAt(value: unknown): number | undefined {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n return undefined;\n }\n\n /**\n * Checks if the incoming data is newer than the current in-memory data.\n * Returns true if the update should proceed, false if it should be skipped.\n *\n * Always accepts the update if:\n * - There is no current data\n * - The current data has no configUpdatedAt\n * - The incoming data has no configUpdatedAt\n *\n * Skips the update only when both have configUpdatedAt and incoming is older.\n */\n private isNewerData(incoming: DatafileInput): boolean {\n if (!this.data) return true;\n\n const currentTs = FlagNetworkDataSource.parseConfigUpdatedAt(\n this.data.configUpdatedAt,\n );\n const incomingTs = FlagNetworkDataSource.parseConfigUpdatedAt(\n incoming.configUpdatedAt,\n );\n\n if (currentTs === undefined || incomingTs === undefined) {\n return true;\n }\n\n return incomingTs >= currentTs;\n }\n\n /**\n * Logs a warning if returning cached data while stream is disconnected.\n */\n private warnIfDisconnected(): void {\n if (!this.isStreamConnected && !this.hasWarnedAboutStaleData) {\n this.hasWarnedAboutStaleData = true;\n console.warn(\n '@vercel/flags-core: Returning in-memory flag definitions while stream is disconnected. Data may be stale.',\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // Usage tracking\n // ---------------------------------------------------------------------------\n\n /**\n * Tracks a read operation for usage analytics.\n */\n private trackRead(\n startTime: number,\n cacheHadDefinitions: boolean,\n isFirstRead: boolean,\n source: Metrics['source'],\n ): void {\n const configOrigin: 'in-memory' | 'embedded' =\n source === 'embedded' ? 'embedded' : 'in-memory';\n const trackOptions: TrackReadOptions = {\n configOrigin,\n cacheStatus: cacheHadDefinitions ? 'HIT' : 'MISS',\n cacheIsBlocking: !cacheHadDefinitions,\n duration: Date.now() - startTime,\n };\n const configUpdatedAt = this.data?.configUpdatedAt;\n if (typeof configUpdatedAt === 'number') {\n trackOptions.configUpdatedAt = configUpdatedAt;\n }\n if (isFirstRead) {\n trackOptions.cacheIsFirstRead = true;\n }\n this.usageTracker.trackRead(trackOptions);\n }\n}\n","/**\n * Parses sdk keys from connection strings with the following format:\n * `flags:edgeConfigId=ecfg_abcd&edgeConfigToken=xxx&sdkKey=xxx`\n */\nexport function parseSdkKeyFromFlagsConnectionString(\n text: string,\n): string | null {\n if (text.startsWith('vf_')) return text;\n\n try {\n if (!text.startsWith('flags:')) return null;\n const params = new URLSearchParams(text.slice(6));\n return params.get('sdkKey');\n } catch {\n // no-op\n }\n\n return null;\n}\n","/**\n * Factory functions for exports of index.default.ts and index.next-js.ts\n */\n\nimport type { createCreateRawClient } from './create-raw-client';\nimport {\n FlagNetworkDataSource,\n type FlagNetworkDataSourceOptions,\n} from './data-source/flag-network-data-source';\nimport type { FlagsClient } from './types';\nimport { parseSdkKeyFromFlagsConnectionString } from './utils/sdk-keys';\n\n/**\n * Options for createClient\n */\nexport type CreateClientOptions = Omit<FlagNetworkDataSourceOptions, 'sdkKey'>;\n\nexport function make(\n createRawClient: ReturnType<typeof createCreateRawClient>,\n): {\n flagsClient: FlagsClient;\n resetDefaultFlagsClient: () => void;\n createClient: (\n sdkKeyOrConnectionString: string,\n options?: CreateClientOptions,\n ) => FlagsClient;\n} {\n let _defaultFlagsClient: FlagsClient | null = null;\n\n // Insights\n // - data source must specify the environment & projectId as sdkKey has that info\n // - \"reuse\" functionality relies on the data source having the data for all envs\n function createClient(\n sdkKeyOrConnectionString: string,\n options?: CreateClientOptions,\n ): FlagsClient {\n if (!sdkKeyOrConnectionString) throw new Error('flags: Missing sdkKey');\n\n // Parse connection string if needed (e.g., \"flags:edgeConfigId=...&sdkKey=vf_xxx\")\n const sdkKey = parseSdkKeyFromFlagsConnectionString(\n sdkKeyOrConnectionString,\n );\n if (!sdkKey) {\n throw new Error('flags: Missing sdkKey in connection string');\n }\n\n // sdk key contains the environment\n const dataSource = new FlagNetworkDataSource({ sdkKey, ...options });\n return createRawClient({\n dataSource,\n origin: { provider: 'vercel', sdkKey },\n });\n }\n\n function resetDefaultFlagsClient() {\n _defaultFlagsClient = null;\n }\n\n const flagsClient: FlagsClient = new Proxy({} as FlagsClient, {\n get(_, prop) {\n if (!_defaultFlagsClient) {\n if (!process.env.FLAGS) {\n throw new Error('flags: Missing environment variable FLAGS');\n }\n\n const sdkKey = parseSdkKeyFromFlagsConnectionString(process.env.FLAGS);\n if (!sdkKey) {\n throw new Error('flags: Missing sdkKey');\n }\n _defaultFlagsClient = createClient(sdkKey);\n }\n return _defaultFlagsClient[prop as keyof FlagsClient];\n },\n });\n\n return {\n flagsClient,\n resetDefaultFlagsClient,\n createClient,\n };\n}\n","/**\n * Exports for default runtimes\n *\n * There is also index.next-js.ts which targets Next.js specifically.\n * If you update this file, please update index.next-js.ts as well.\n *\n * Try keeping this file small. Export through index.common and index.make.\n *\n * This file has JSDoc on its exports which will be used by the editor.\n * We do not need to repeat the JSDoc on the next-js export.\n */\n\nimport * as fns from './client-fns';\nimport { createCreateRawClient } from './create-raw-client';\nimport { make } from './index.make';\n\nexport * from './index.common';\n\nexport const {\n /**\n * A lazily-initialized default flags client.\n *\n * - relies on process.env.FLAGS\n * - does not use process.env.EDGE_CONFIG\n */\n flagsClient,\n /**\n * For testing purposes\n */\n resetDefaultFlagsClient,\n /**\n * Create a flags client based on an SDK Key\n */\n createClient,\n} = make(createCreateRawClient(fns));\n"],"mappings":"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","names":["evaluate","ResolutionReason","Original","AccessorType","Packed","sum","evaluate","createClient","resetDefaultFlagsClient","flagsClient"]}
@@ -341,7 +341,7 @@ function findWeightedIndex(weights, value, maxValue) {
341
341
  }
342
342
 
343
343
  // package.json
344
- var version = "1.0.0";
344
+ var version = "1.0.1";
345
345
 
346
346
  // src/lib/report-value.ts
347
347
  function internalReportValue(key, value, data) {
@@ -417,26 +417,38 @@ async function evaluate2(id, flagKey, defaultValue, entities) {
417
417
 
418
418
  // src/create-raw-client.ts
419
419
  var idCount = 0;
420
+ async function performInitialize(instance, initFn) {
421
+ try {
422
+ await initFn();
423
+ instance.initialized = true;
424
+ } catch (error) {
425
+ instance.initPromise = null;
426
+ throw error;
427
+ }
428
+ }
420
429
  function createCreateRawClient(fns) {
421
430
  return function createRawClient({
422
431
  dataSource,
423
432
  origin
424
433
  }) {
425
434
  const id = idCount++;
426
- clientMap.set(id, { dataSource, initialized: false });
435
+ clientMap.set(id, { dataSource, initialized: false, initPromise: null });
427
436
  const api = {
428
437
  origin,
429
438
  initialize: async () => {
430
439
  let instance = clientMap.get(id);
431
440
  if (!instance) {
432
- instance = { dataSource, initialized: false };
441
+ instance = { dataSource, initialized: false, initPromise: null };
433
442
  clientMap.set(id, instance);
434
443
  }
435
444
  if (instance.initialized) return;
436
- const promise = fns.initialize(id);
437
- await promise;
438
- instance.initialized = true;
439
- return promise;
445
+ if (!instance.initPromise) {
446
+ instance.initPromise = performInitialize(
447
+ instance,
448
+ () => fns.initialize(id)
449
+ );
450
+ }
451
+ return instance.initPromise;
440
452
  },
441
453
  shutdown: async () => {
442
454
  await fns.shutdown(id);
@@ -859,6 +871,9 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
859
871
  // Polling state
860
872
  pollingIntervalId;
861
873
  pollingAbortController;
874
+ // Initialization state — suppresses onDisconnect from starting polling
875
+ // while initialize() is still running its own fallback chain
876
+ isInitializing = false;
862
877
  // Usage tracking
863
878
  usageTracker;
864
879
  isFirstGetData = true;
@@ -904,16 +919,21 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
904
919
  this.startBackgroundUpdates();
905
920
  return;
906
921
  }
907
- if (this.options.stream.enabled) {
908
- const streamSuccess = await this.tryInitializeStream();
909
- if (streamSuccess) return;
910
- }
911
- if (this.options.polling.enabled) {
912
- const pollingSuccess = await this.tryInitializePolling();
913
- if (pollingSuccess) return;
922
+ this.isInitializing = true;
923
+ try {
924
+ if (this.options.stream.enabled) {
925
+ const streamSuccess = await this.tryInitializeStream();
926
+ if (streamSuccess) return;
927
+ }
928
+ if (this.options.polling.enabled) {
929
+ const pollingSuccess = await this.tryInitializePolling();
930
+ if (pollingSuccess) return;
931
+ }
932
+ if (this.data) return;
933
+ await this.initializeFromBundled();
934
+ } finally {
935
+ this.isInitializing = false;
914
936
  }
915
- if (this.data) return;
916
- await this.initializeFromBundled();
917
937
  }
918
938
  /**
919
939
  * Reads the current datafile with metrics.
@@ -952,6 +972,7 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
952
972
  this.stopStream();
953
973
  this.stopPolling();
954
974
  this.data = this.options.datafile;
975
+ this.isInitializing = false;
955
976
  this.isStreamConnected = false;
956
977
  this.hasWarnedAboutStaleData = false;
957
978
  await this.usageTracker.flush();
@@ -1087,7 +1108,7 @@ var FlagNetworkDataSource = class _FlagNetworkDataSource {
1087
1108
  },
1088
1109
  onDisconnect: () => {
1089
1110
  this.isStreamConnected = false;
1090
- if (this.options.polling.enabled && !this.pollingIntervalId) {
1111
+ if (this.options.polling.enabled && !this.pollingIntervalId && !this.isInitializing) {
1091
1112
  this.startPolling();
1092
1113
  }
1093
1114
  }
@@ -1500,4 +1521,4 @@ export {
1500
1521
  resetDefaultFlagsClient,
1501
1522
  createClient
1502
1523
  };
1503
- //# sourceMappingURL=chunk-UQEFJL4F.js.map
1524
+ //# sourceMappingURL=chunk-BVKIEFFY.js.map