@vercel/flags-core 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/evaluate.ts","../src/types.ts","../src/utils.ts","../package.json","../src/lib/report-value.ts","../src/client.ts","../src/store.ts","../src/data-source/edge-config-data-source.ts","../src/data-source/in-memory-data-source.ts"],"sourcesContent":["import { createClient as createEdgeConfigClient } from '@vercel/edge-config';\nimport { createClient, type FlagsClient } from './client';\nimport { EdgeConfigDataSource } from './data-source/edge-config-data-source';\nimport { InMemoryDataSource } from './data-source/in-memory-data-source';\nimport type { ConnectionOptions } from './types';\n\nexport {\n createClient,\n type FlagsClient,\n} from './client';\nexport { EdgeConfigDataSource, InMemoryDataSource };\nexport { store } from './store';\nexport { ResolutionReason as Reason } from './types';\n\nlet defaultFlagsClient: FlagsClient | null = null;\n\n// TODO this should possibly be a generic parser for the URL, which\n// can be used with sources other than Edge Config at some point\nexport function parseFlagsConnectionString(\n connectionString: string,\n): ConnectionOptions {\n const errorMessage = 'flags: Invalid connection string';\n\n try {\n const params = new URLSearchParams(connectionString.slice(6));\n const edgeConfigId = params.get('edgeConfigId');\n const edgeConfigToken = params.get('edgeConfigToken');\n const projectId = params.get('projectId');\n if (!edgeConfigId || !edgeConfigToken || !projectId) {\n throw new Error(errorMessage);\n }\n\n return {\n edgeConfigId,\n edgeConfigToken,\n projectId,\n edgeConfigItemKey: params.get('edgeConfigItemKey'),\n env: params.get('env'),\n };\n } catch {\n throw new Error(errorMessage);\n }\n}\n\n/**\n * Internal function for testing purposes\n */\nexport function resetDefaultFlagsClient() {\n defaultFlagsClient = null;\n}\n\nexport function createClientFromConnectionString(connectionString: string) {\n if (!connectionString) {\n throw new Error('flags: Missing connection string');\n }\n\n const connectionOptions = parseFlagsConnectionString(connectionString);\n const edgeConfigItemKey = connectionOptions.edgeConfigItemKey || 'flags';\n\n if (!connectionOptions.edgeConfigId || !connectionOptions.edgeConfigToken) {\n throw new Error('flags: Missing edge config connection information');\n }\n\n // TODO use latest connection string format\n // const edgeConfigConnectionString = `edge-config:id=${connectionOptions.edgeConfigId}&token=${connectionOptions.edgeConfigToken}`;\n const edgeConfigConnectionString = `https://edge-config.vercel.com/${connectionOptions.edgeConfigId}?token=${connectionOptions.edgeConfigToken}`;\n\n const edgeConfigClient = createEdgeConfigClient(edgeConfigConnectionString);\n\n const dataSource = new EdgeConfigDataSource({\n edgeConfigClient,\n edgeConfigItemKey,\n projectId: connectionOptions.projectId,\n });\n\n const environment = getFlagsEnvironment(connectionOptions.env);\n return createClient({ dataSource, environment });\n}\n\n/**\n * This function is for internal use only.\n *\n * Produces a default flags client reading from a default edge config.\n *\n * - relies on process.env.FLAGS\n * - does not use process.env.EDGE_CONFIG\n *\n * @param connectionString - usually from process.env.FLAGS\n * @returns - a flags client\n */\nexport function getDefaultFlagsClient() {\n if (defaultFlagsClient) return defaultFlagsClient;\n\n if (!process.env.FLAGS) {\n throw new Error('flags: Missing environment variable FLAGS');\n }\n\n defaultFlagsClient = createClientFromConnectionString(process.env.FLAGS);\n return defaultFlagsClient;\n}\n\n/**\n * Resolve the Flags environment. If connectionOptionsEnv is provided, use it as-is.\n *\n * Fall back to VERCEL_ENV if it is a known Vercel environment (production, preview, development)\n * If VERCEL_ENV is unset, it will resolve 'development' (Vercel provides it in preview and production)\n * If VERCEL_ENV is not one of the known values, it will resolve 'preview'\n */\nexport function getFlagsEnvironment(connectionOptionsEnv: string | null) {\n if (connectionOptionsEnv) {\n return connectionOptionsEnv;\n }\n const vercelEnv = process.env.VERCEL_ENV;\n if (!vercelEnv || vercelEnv === 'development') {\n return 'development';\n }\n if (vercelEnv === 'production') {\n return 'production';\n }\n return 'preview';\n}\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 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: params.definition.variants[outcome] as T,\n outcomeType: OutcomeType.VALUE,\n };\n }\n switch (outcome.type) {\n case 'split': {\n const lhs = access(outcome.base, params);\n const defaultOutcome = params.definition.variants[outcome.defaultVariant];\n\n // serve the default variant if the lhs is not a string\n if (typeof lhs !== 'string') {\n return { value: defaultOutcome as T, 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 as T)\n : (params.definition.variants[variantIndex] as T),\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 {\n ...handleOutcome<T>(params, envConfig),\n reason: ResolutionReason.PAUSED,\n };\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 {\n ...handleOutcome<T>(params, matchedIndex),\n reason: ResolutionReason.TARGET_MATCH,\n };\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 {\n ...handleOutcome<T>(params, firstMatchingRule.outcome),\n reason: ResolutionReason.RULE_MATCH,\n };\n }\n\n return {\n ...handleOutcome<T>(params, envConfig.fallthrough),\n reason: ResolutionReason.FALLTHROUGH,\n };\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","export interface ConnectionOptions {\n edgeConfigId: string;\n edgeConfigToken: string;\n edgeConfigItemKey: string | null;\n env: string | null;\n projectId: string;\n}\n\n// -----------------------------------------------------------------------------\n// Shared data\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 `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 }\n | {\n reason: ResolutionReason.ERROR;\n errorMessage: string;\n errorCode?: ErrorCode;\n /**\n * In cases of errors this is the he defaultValue if one was provided\n */\n value?: T;\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: { label: 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: { label: string; value: string }[] }\n * }\n */\n export type TargetList = Record<\n string,\n Record<string, { label: 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: { label: 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: { label: string, value: string }[] }\n * }\n */\n exclude: TargetList;\n };\n\n export type FlagDefinition = {\n happykitFlagId?: string;\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 happykitFlagId?: string;\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\": \"0.1.0\",\n \"description\": \"\",\n \"keywords\": [],\n \"license\": \"MIT\",\n \"author\": \"\",\n \"sideEffects\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": \"./dist/index.js\",\n \"./openfeature\": \"./dist/openfeature.js\"\n },\n \"main\": \"./dist/index.js\",\n \"typesVersions\": {\n \"*\": {\n \".\": [\n \"dist/*.d.ts\"\n ],\n \"./openfeature\": [\n \"dist/openfeature.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 \"jose\": \"5.2.1\",\n \"js-xxhash\": \"4.0.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"20.11.17\",\n \"@vercel/edge-config\": \"1.4.0\",\n \"flags\": \"workspace:*\",\n \"msw\": \"2.6.4\",\n \"tsconfig\": \"workspace:*\",\n \"tsup\": \"8.0.1\",\n \"typescript\": \"5.6.3\",\n \"vite\": \"6.0.3\",\n \"vitest\": \"2.1.8\"\n },\n \"peerDependencies\": {\n \"@vercel/edge-config\": \"^1.2.0\",\n \"flags\": \"*\",\n \"@openfeature/server-sdk\": \"1.18.0\"\n },\n \"peerDependenciesMeta\": {\n \"@openfeature/server-sdk\": {\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","// TODO should we store the context schema (entities schema) in Edge Config and validate context?\n// TODO should we make evaluate return the variant ids as well?\nimport type { DataSource } from './data-source/interface';\nimport { evaluate } from './evaluate';\nimport { internalReportValue } from './lib/report-value';\nimport {\n ErrorCode,\n type EvaluationResult,\n type Packed,\n ResolutionReason,\n type Value,\n} from './types';\n\nexport type Source = {\n orgId: string;\n orgSlug: string;\n projectId: string;\n projectSlug: string;\n};\n\nexport type FlagsClient = {\n environment: string;\n dataSource: DataSource;\n evaluate: <T = Value, E = Record<string, unknown>>(\n flagKey: string,\n defaultValue?: T,\n entities?: E,\n ) => Promise<EvaluationResult<T>>;\n initialize(): void | Promise<void>;\n shutdown(): void | Promise<void>;\n};\n\n/**\n * Creates a Vercel Flags client\n *\n * @example\n * const edgeConfigClient = createClient('');\n * const flagsClient = createClient({\n * dataSource: new EdgeConfigDataSource({\n * edgeConfigItemKey: 'flags',\n * edgeConfigClient,\n * }),\n * environment: 'production',\n * });\n */\nexport function createClient({\n environment,\n dataSource,\n}: {\n environment: string;\n dataSource: DataSource;\n}): FlagsClient {\n return {\n dataSource,\n environment,\n initialize: () => {\n if (dataSource && typeof dataSource.initialize === 'function') {\n return dataSource.initialize();\n }\n },\n shutdown: () => {\n if (dataSource && typeof dataSource.shutdown === 'function') {\n return dataSource.shutdown();\n }\n },\n async evaluate<T = Value, E = Record<string, unknown>>(\n flagKey: string,\n defaultValue?: T,\n entities?: E,\n ): Promise<EvaluationResult<T>> {\n // TODO dataSource.getData should move into \"initialize\" and set up the subscription.\n //\n // From OpenFeature: \"It's recommended to provide non-blocking mechanisms for flag\n // evaluation, particularly in languages or environments wherein there's a\n // single thread of execution.\n const data = await dataSource.getData();\n\n const flagDefinition = data.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 };\n }\n\n const result = evaluate<T>({\n defaultValue,\n definition: flagDefinition,\n environment: this.environment,\n entities: entities ?? {},\n segments: data.segments,\n });\n\n if (dataSource.projectId) {\n internalReportValue(flagKey, result.value, {\n originProjectId: dataSource.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 result;\n },\n };\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\n\n/**\n * A store to avoid reading the Edge Config for every flag evaluation,\n * and instead reading it once per request.\n */\nexport const store = new AsyncLocalStorage<WeakKey>();\n","import type { EdgeConfigClient } from '@vercel/edge-config';\nimport { store } from '../store';\nimport type { Packed } from '../types';\nimport type { DataSource } from './interface';\n\n/**\n * Implements the DataSource interface for Edge Config.\n */\nexport class EdgeConfigDataSource implements DataSource {\n connectionString?: string;\n edgeConfigClient: EdgeConfigClient;\n edgeConfigItemKey: string;\n requestCache: WeakMap<WeakKey, Promise<Packed.Data | undefined>>;\n projectId?: string;\n\n constructor(options: {\n edgeConfigItemKey: string;\n edgeConfigClient: EdgeConfigClient;\n projectId?: string;\n }) {\n this.edgeConfigClient = options.edgeConfigClient;\n this.edgeConfigItemKey = options.edgeConfigItemKey;\n this.requestCache = new WeakMap();\n this.projectId = options.projectId;\n }\n\n // This is a temporary solution to avoid reading the Edge Config for every flag,\n // and instead reading it once per request.\n private async getCachedData() {\n const cacheKey = store.getStore();\n if (cacheKey) {\n const cached = this.requestCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n }\n const promise = this.edgeConfigClient.get<Packed.Data>(\n this.edgeConfigItemKey,\n );\n\n if (cacheKey) this.requestCache.set(cacheKey, promise);\n\n return promise;\n }\n\n async getData() {\n const data = await this.getCachedData();\n\n if (!data) {\n throw new Error(\n `No definitions found in Edge Config under key \"${this.edgeConfigItemKey}\"`,\n );\n }\n\n return data;\n }\n}\n","import type { Packed } from '../types';\nimport type { DataSource } from './interface';\n\nexport class InMemoryDataSource implements DataSource {\n private data: Packed.Data;\n public projectId?: string;\n\n constructor(data: Packed.Data, projectId?: string) {\n this.data = data;\n this.projectId = projectId;\n }\n\n async getData() {\n return this.data;\n }\n}\n"],"mappings":"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","names":["ResolutionReason","Original","AccessorType","Packed","_a","sum"]}
@@ -0,0 +1,421 @@
1
+ interface ConnectionOptions {
2
+ edgeConfigId: string;
3
+ edgeConfigToken: string;
4
+ edgeConfigItemKey: string | null;
5
+ env: string | null;
6
+ projectId: string;
7
+ }
8
+ /**
9
+ * ErrorCodes that can happen during evaluation
10
+ */
11
+ declare enum ErrorCode {
12
+ /**
13
+ * The value was resolved before the provider was ready.
14
+ */
15
+ /**
16
+ * The provider has entered an irrecoverable error state.
17
+ */
18
+ /**
19
+ * The flag could not be found.
20
+ */
21
+ FLAG_NOT_FOUND = "FLAG_NOT_FOUND"
22
+ }
23
+ /**
24
+ * The detailed result of a flag evaluation as returned by the `evaluate` function.
25
+ */
26
+ type EvaluationResult<T> = {
27
+ /**
28
+ * In case of successful evaluations this holds the evaluated value
29
+ */
30
+ value: T;
31
+ /**
32
+ * Indicates whether the outcome was a single variant or a split
33
+ */
34
+ outcomeType?: OutcomeType;
35
+ /**
36
+ * Indicates why the flag evaluated to a certain value
37
+ */
38
+ reason: Exclude<ResolutionReason, ResolutionReason.ERROR>;
39
+ errorMessage?: never;
40
+ errorCode?: never;
41
+ } | {
42
+ reason: ResolutionReason.ERROR;
43
+ errorMessage: string;
44
+ errorCode?: ErrorCode;
45
+ /**
46
+ * In cases of errors this is the he defaultValue if one was provided
47
+ */
48
+ value?: T;
49
+ };
50
+ type FlagKey = string;
51
+ type EnvironmentKey = string;
52
+ type SegmentId = string;
53
+ type Value = string | number | boolean;
54
+ declare enum ResolutionReason {
55
+ PAUSED = "paused",
56
+ TARGET_MATCH = "target_match",
57
+ RULE_MATCH = "rule_match",
58
+ FALLTHROUGH = "fallthrough",
59
+ ERROR = "error"
60
+ }
61
+ declare enum OutcomeType {
62
+ /** When the outcome type was a single variant */
63
+ VALUE = "value",
64
+ /** When the outcome type was a split */
65
+ SPLIT = "split"
66
+ }
67
+ /**
68
+ * Vercel Flags
69
+ * - is equal to (eq)
70
+ * - is not equal to (!eq)
71
+ * - is one of (oneOf)
72
+ * - is not one of (!oneOf)
73
+ * - contains (contains)
74
+ * - does not contain (!contains)
75
+ * - starts with (startsWith)
76
+ * - does not start with (!startsWith)
77
+ * - ends with (endsWith)
78
+ * - does not end with (!endsWith)
79
+ * - exists (ex)
80
+ * - deos not exist (!ex)
81
+ * - is greater than (gt)
82
+ * - is greater than or equal to (gte)
83
+ * - is lower than (lt)
84
+ * - is lower than or equal to (lte)
85
+ * - matches regex (regex)
86
+ * - does not match regex (!regex)
87
+ * - is before (before)
88
+ * - is after (after)
89
+ */
90
+ declare enum Comparator {
91
+ /**
92
+ * lhs must be string | number
93
+ * rhs must be string | number
94
+ * does a strict equality check
95
+ */
96
+ EQ = "eq",
97
+ /**
98
+ * lhs must be string | number
99
+ * rhs must be string | number
100
+ * does a strict equality check
101
+ */
102
+ NOT_EQ = "!eq",
103
+ /**
104
+ * lhs must be string
105
+ * rhs must be string[]
106
+ */
107
+ ONE_OF = "oneOf",
108
+ /**
109
+ * lhs must be string
110
+ * rhs must be string[]
111
+ */
112
+ NOT_ONE_OF = "!oneOf",
113
+ /**
114
+ * lhs must be string[]
115
+ * rhs must be string[]
116
+ */
117
+ CONTAINS_ALL_OF = "containsAllOf",
118
+ /**
119
+ * lhs must be string[]
120
+ * rhs must be string[]
121
+ */
122
+ CONTAINS_ANY_OF = "containsAnyOf",
123
+ /**
124
+ * lhs must be string[]
125
+ * rhs must be string[]
126
+ */
127
+ CONTAINS_NONE_OF = "containsNoneOf",
128
+ /**
129
+ * lhs must be string
130
+ * rhs must be string
131
+ *
132
+ * other comparisons have to be handled with a regex
133
+ */
134
+ STARTS_WITH = "startsWith",
135
+ /**
136
+ * lhs must be string
137
+ * rhs must be string
138
+ *
139
+ * other comparisons have to be handled with a regex
140
+ */
141
+ NOT_STARTS_WITH = "!startsWith",
142
+ /**
143
+ * lhs must be string
144
+ * rhs must be string
145
+ *
146
+ * other comparisons have to be handled with a regex
147
+ */
148
+ ENDS_WITH = "endsWith",
149
+ /**
150
+ * lhs must be string
151
+ * rhs must be string
152
+ *
153
+ * other comparisons have to be handled with a regex
154
+ */
155
+ NOT_ENDS_WITH = "!endsWith",
156
+ /**
157
+ * lhs must be string
158
+ * rhs must be never
159
+ */
160
+ EXISTS = "ex",
161
+ /**
162
+ * lhs must be string
163
+ * rhs must be never
164
+ */
165
+ NOT_EXISTS = "!ex",
166
+ /**
167
+ * lhs must be string | number
168
+ * rhs must be string | number
169
+ */
170
+ GT = "gt",
171
+ /**
172
+ * lhs must be string | number
173
+ * rhs must be string | number
174
+ */
175
+ GTE = "gte",
176
+ /** */
177
+ /**
178
+ * lhs must be string | number
179
+ * rhs must be string | number
180
+ */
181
+ LT = "lt",
182
+ /**
183
+ * lhs must be string | number
184
+ * rhs must be string | number
185
+ */
186
+ LTE = "lte",
187
+ /**
188
+ * lhs must be string
189
+ * rhs must be string
190
+ */
191
+ REGEX = "regex",
192
+ /**
193
+ * lhs must be string
194
+ * rhs must be string
195
+ */
196
+ NOT_REGEX = "!regex",
197
+ /**
198
+ * lhs must be date string
199
+ * rhs must be date string
200
+ *
201
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format
202
+ */
203
+ BEFORE = "before",
204
+ /**
205
+ * lhs must be date string
206
+ * rhs must be date string
207
+ *
208
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format
209
+ */
210
+ AFTER = "after"
211
+ }
212
+ declare namespace Packed {
213
+ /**
214
+ * Idenitifies a variant based on its index in the variants array.
215
+ */
216
+ type VariantIndex = number;
217
+ type Data = {
218
+ /** map of flag keys to definitions */
219
+ definitions: Record<FlagKey, FlagDefinition>;
220
+ /** segments keyed by id */
221
+ segments?: Record<SegmentId, Segment>;
222
+ };
223
+ enum AccessorType {
224
+ SEGMENT = "segment",
225
+ ENTITY = "entity"
226
+ }
227
+ type SplitOutcome = {
228
+ type: 'split';
229
+ /**
230
+ * Based on which attribute the traffic should be split.
231
+ */
232
+ base: EntityAccessor;
233
+ /**
234
+ * The distribution of the individual groups.
235
+ *
236
+ * We use a single number array as the numbers will be placed in the
237
+ * same order as the variant list.
238
+ *
239
+ * So index 0 here is the distribution for variant 0, and so on.
240
+ */
241
+ weights: number[];
242
+ /**
243
+ * This variant will be used when the lhs does not exist
244
+ */
245
+ defaultVariant: VariantIndex;
246
+ };
247
+ type SegmentAllOutcome = 1;
248
+ type SegmentSplitOutcome = {
249
+ type: 'split';
250
+ /**
251
+ * Based on which attribute the traffic should be split.
252
+ *
253
+ * When the attribute does not exist the segment will not match.
254
+ */
255
+ base: EntityAccessor;
256
+ /**
257
+ * The promille that should pass the segment (1 = 0.001%; 1000 = 1%)
258
+ */
259
+ passPromille: number;
260
+ };
261
+ type SegmentOutcome = SegmentAllOutcome | SegmentSplitOutcome;
262
+ type Outcome = VariantIndex | SplitOutcome;
263
+ type EntityAccessor = (string | number)[];
264
+ type SegmentAccessor = 'segment';
265
+ /**
266
+ * An array means an entity
267
+ */
268
+ type LHS = EntityAccessor | SegmentAccessor;
269
+ /**
270
+ * undefined when the rhs is not used by the comparator
271
+ * string[] when the rhs is a list of segments
272
+ * { type: 'regex'; pattern: string; flags: string } when the rhs is a regex
273
+ */
274
+ type RHS = undefined | string | number | boolean | (string | number)[] | {
275
+ type: 'regex';
276
+ pattern: string;
277
+ flags: string;
278
+ };
279
+ type Condition = [LHS, Comparator, RHS] | [LHS, Comparator.EXISTS] | [LHS, Comparator.NOT_EXISTS];
280
+ type Rule = {
281
+ conditions: Condition[];
282
+ outcome: Outcome;
283
+ };
284
+ type SegmentRule = {
285
+ conditions: Condition[];
286
+ outcome: SegmentAllOutcome | SegmentSplitOutcome;
287
+ };
288
+ type EnvironmentConfig =
289
+ /**
290
+ * Paused flags contain the pausedOutcome only.
291
+ */
292
+ number
293
+ /** Allows reusing the configuration of another environment */
294
+ | {
295
+ reuse: EnvironmentKey;
296
+ }
297
+ /**
298
+ * Active flags don't contain an explicit "active" state.
299
+ * The fact that they have a config means they are active.
300
+ */
301
+ | {
302
+ /**
303
+ * Each array item represents a variant.
304
+ *
305
+ * Each slot holds the targets for that variant.
306
+ *
307
+ * So the target list at index 0 is the targets for variant 0, and so on.
308
+ */
309
+ targets?: TargetList[];
310
+ rules?: Rule[];
311
+ fallthrough: Outcome;
312
+ };
313
+ /**
314
+ * A list of targets
315
+ *
316
+ * @example
317
+ * {
318
+ * user: { id: string[] }
319
+ * }
320
+ */
321
+ type TargetList = Record<string, Record<string, string[]>>;
322
+ /**
323
+ * reusable conditions, with no outcome attached
324
+ */
325
+ type Segment = {
326
+ rules?: SegmentRule[];
327
+ /**
328
+ * Explicitly include targets. Included targets will bypass conditions and exclusion.
329
+ *
330
+ * @example
331
+ * include: {
332
+ * user: { id: string[] }
333
+ * }
334
+ */
335
+ include?: TargetList;
336
+ /**
337
+ * Explicitly exclude targets. Excluded targets will not be included in the segment, and bypass conditions.
338
+ *
339
+ * @example
340
+ * exclude: {
341
+ * user: { id: string[] }
342
+ * }
343
+ */
344
+ exclude?: TargetList;
345
+ };
346
+ type FlagDefinition = {
347
+ /** for backwards compatibility with HappyKit */
348
+ happykitFlagId?: string;
349
+ /** for backwards compatibility with HappyKit */
350
+ variantIds?: string[];
351
+ /** variants, packed down to just their values */
352
+ variants: Value[];
353
+ /** environments */
354
+ environments: Record<EnvironmentKey, EnvironmentConfig>;
355
+ /**
356
+ * A random seed to prevent split points in different flags
357
+ * from having the same targets. Otherwise the same set of ids would be
358
+ * opted into all flags for every rollout. By using a different seed for
359
+ * each flag the distribution is different for every flag.
360
+ *
361
+ * We don't use the slug as it might change, but we don't want the distribution
362
+ * to change when the slug changes.
363
+ *
364
+ * We don't use the id or createdAt etc as we want to be able to redistirbute
365
+ * by changing the seed.
366
+ */
367
+ seed?: number;
368
+ };
369
+ }
370
+
371
+ /**
372
+ * DataSource interface for the Vercel Flags client
373
+ */
374
+ interface DataSource {
375
+ /**
376
+ * The datafile
377
+ */
378
+ getData(): Promise<Packed.Data>;
379
+ /**
380
+ * The project for which these flags were loaded for
381
+ */
382
+ projectId?: string;
383
+ /**
384
+ * Initialize the data source by fetching the initial file or setting up polling or
385
+ * subscriptions.
386
+ *
387
+ * @see https://openfeature.dev/specification/sections/providers#requirement-241
388
+ */
389
+ initialize?: () => Promise<void>;
390
+ /**
391
+ * End polling or subscriptions.
392
+ */
393
+ shutdown?(): void;
394
+ }
395
+
396
+ type FlagsClient = {
397
+ environment: string;
398
+ dataSource: DataSource;
399
+ evaluate: <T = Value, E = Record<string, unknown>>(flagKey: string, defaultValue?: T, entities?: E) => Promise<EvaluationResult<T>>;
400
+ initialize(): void | Promise<void>;
401
+ shutdown(): void | Promise<void>;
402
+ };
403
+ /**
404
+ * Creates a Vercel Flags client
405
+ *
406
+ * @example
407
+ * const edgeConfigClient = createClient('');
408
+ * const flagsClient = createClient({
409
+ * dataSource: new EdgeConfigDataSource({
410
+ * edgeConfigItemKey: 'flags',
411
+ * edgeConfigClient,
412
+ * }),
413
+ * environment: 'production',
414
+ * });
415
+ */
416
+ declare function createClient({ environment, dataSource, }: {
417
+ environment: string;
418
+ dataSource: DataSource;
419
+ }): FlagsClient;
420
+
421
+ export { type ConnectionOptions as C, type DataSource as D, type FlagsClient as F, Packed as P, ResolutionReason as R, createClient as c };
@@ -0,0 +1,64 @@
1
+ import { D as DataSource, P as Packed, C as ConnectionOptions, F as FlagsClient } from './client-H1UIDKJU.js';
2
+ export { R as Reason, c as createClient } from './client-H1UIDKJU.js';
3
+ import { EdgeConfigClient } from '@vercel/edge-config';
4
+ import { AsyncLocalStorage } from 'node:async_hooks';
5
+
6
+ /**
7
+ * Implements the DataSource interface for Edge Config.
8
+ */
9
+ declare class EdgeConfigDataSource implements DataSource {
10
+ connectionString?: string;
11
+ edgeConfigClient: EdgeConfigClient;
12
+ edgeConfigItemKey: string;
13
+ requestCache: WeakMap<WeakKey, Promise<Packed.Data | undefined>>;
14
+ projectId?: string;
15
+ constructor(options: {
16
+ edgeConfigItemKey: string;
17
+ edgeConfigClient: EdgeConfigClient;
18
+ projectId?: string;
19
+ });
20
+ private getCachedData;
21
+ getData(): Promise<Packed.Data>;
22
+ }
23
+
24
+ declare class InMemoryDataSource implements DataSource {
25
+ private data;
26
+ projectId?: string;
27
+ constructor(data: Packed.Data, projectId?: string);
28
+ getData(): Promise<Packed.Data>;
29
+ }
30
+
31
+ /**
32
+ * A store to avoid reading the Edge Config for every flag evaluation,
33
+ * and instead reading it once per request.
34
+ */
35
+ declare const store: AsyncLocalStorage<WeakKey>;
36
+
37
+ declare function parseFlagsConnectionString(connectionString: string): ConnectionOptions;
38
+ /**
39
+ * Internal function for testing purposes
40
+ */
41
+ declare function resetDefaultFlagsClient(): void;
42
+ declare function createClientFromConnectionString(connectionString: string): FlagsClient;
43
+ /**
44
+ * This function is for internal use only.
45
+ *
46
+ * Produces a default flags client reading from a default edge config.
47
+ *
48
+ * - relies on process.env.FLAGS
49
+ * - does not use process.env.EDGE_CONFIG
50
+ *
51
+ * @param connectionString - usually from process.env.FLAGS
52
+ * @returns - a flags client
53
+ */
54
+ declare function getDefaultFlagsClient(): FlagsClient;
55
+ /**
56
+ * Resolve the Flags environment. If connectionOptionsEnv is provided, use it as-is.
57
+ *
58
+ * Fall back to VERCEL_ENV if it is a known Vercel environment (production, preview, development)
59
+ * If VERCEL_ENV is unset, it will resolve 'development' (Vercel provides it in preview and production)
60
+ * If VERCEL_ENV is not one of the known values, it will resolve 'preview'
61
+ */
62
+ declare function getFlagsEnvironment(connectionOptionsEnv: string | null): string;
63
+
64
+ export { EdgeConfigDataSource, FlagsClient, InMemoryDataSource, createClientFromConnectionString, getDefaultFlagsClient, getFlagsEnvironment, parseFlagsConnectionString, resetDefaultFlagsClient, store };
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ import {
2
+ EdgeConfigDataSource,
3
+ InMemoryDataSource,
4
+ ResolutionReason,
5
+ createClient,
6
+ createClientFromConnectionString,
7
+ getDefaultFlagsClient,
8
+ getFlagsEnvironment,
9
+ parseFlagsConnectionString,
10
+ resetDefaultFlagsClient,
11
+ store
12
+ } from "./chunk-IUKV6LEY.js";
13
+ export {
14
+ EdgeConfigDataSource,
15
+ InMemoryDataSource,
16
+ ResolutionReason as Reason,
17
+ createClient,
18
+ createClientFromConnectionString,
19
+ getDefaultFlagsClient,
20
+ getFlagsEnvironment,
21
+ parseFlagsConnectionString,
22
+ resetDefaultFlagsClient,
23
+ store
24
+ };
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,24 @@
1
+ import { Provider, ProviderMetadata, EvaluationContext, ResolutionDetails, JsonValue } from '@openfeature/server-sdk';
2
+ import { F as FlagsClient } from './client-H1UIDKJU.js';
3
+
4
+ declare class VercelProvider implements Provider {
5
+ readonly metadata: ProviderMetadata;
6
+ readonly runsOn = "server";
7
+ private client;
8
+ /**
9
+ * Creates a VercelProvider from an existing FlagsClient
10
+ */
11
+ constructor(client: FlagsClient);
12
+ /**
13
+ * Creates a VercelProvider from a connection string
14
+ */
15
+ constructor(connectionString: string);
16
+ initialize(context?: EvaluationContext): Promise<void>;
17
+ onClose(): Promise<void>;
18
+ resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext): Promise<ResolutionDetails<boolean>>;
19
+ resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
20
+ resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext): Promise<ResolutionDetails<number>>;
21
+ resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext): Promise<ResolutionDetails<T>>;
22
+ }
23
+
24
+ export { VercelProvider };