UNPKG

flags

Version:

Flags SDK by Vercel - The feature flags toolkit for Next.js and SvelteKit

1 lines 24.8 kB
{"version":3,"sources":["../src/sveltekit/index.ts","../src/sveltekit/precompute.ts","../src/sveltekit/env.ts"],"names":["flag","serialize","deserialize","flagImpl","valuePromise","decrypt","value","entities","encrypt","precompute","generatePermutations"],"mappings":"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","sourcesContent":["import type { Handle, RequestEvent } from '@sveltejs/kit';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n type ApiData,\n decrypt as _decrypt,\n encrypt as _encrypt,\n reportValue,\n safeJsonStringify,\n verifyAccess,\n type JsonValue,\n type FlagDefinitionsType,\n} from '..';\nimport { Decide, FlagDeclaration, Identify } from '../types';\nimport {\n type ReadonlyHeaders,\n HeadersAdapter,\n} from '../spec-extension/adapters/headers';\nimport {\n type ReadonlyRequestCookies,\n RequestCookiesAdapter,\n} from '../spec-extension/adapters/request-cookies';\nimport { normalizeOptions } from '../lib/normalize-options';\nimport { RequestCookies } from '@edge-runtime/cookies';\nimport { Flag, FlagsArray } from './types';\nimport {\n generatePermutations as _generatePermutations,\n getPrecomputed,\n precompute as _precompute,\n} from './precompute';\nimport { tryGetSecret } from './env';\n\nfunction hasOwnProperty<X extends {}, Y extends PropertyKey>(\n obj: X,\n prop: Y,\n): obj is X & Record<Y, unknown> {\n return obj.hasOwnProperty(prop);\n}\n\nconst headersMap = new WeakMap<Headers, ReadonlyHeaders>();\nconst cookiesMap = new WeakMap<Headers, ReadonlyRequestCookies>();\n\nfunction sealHeaders(headers: Headers): ReadonlyHeaders {\n const cached = headersMap.get(headers);\n if (cached !== undefined) return cached;\n\n const sealed = HeadersAdapter.seal(headers);\n headersMap.set(headers, sealed);\n return sealed;\n}\n\nfunction sealCookies(headers: Headers): ReadonlyRequestCookies {\n const cached = cookiesMap.get(headers);\n if (cached !== undefined) return cached;\n\n const sealed = RequestCookiesAdapter.seal(new RequestCookies(headers));\n cookiesMap.set(headers, sealed);\n return sealed;\n}\n\ntype PromisesMap<T> = {\n [K in keyof T]: Promise<T[K]>;\n};\n\nasync function resolveObjectPromises<T>(obj: PromisesMap<T>): Promise<T> {\n // Convert the object into an array of [key, promise] pairs\n const entries = Object.entries(obj) as [keyof T, Promise<any>][];\n\n // Use Promise.all to wait for all the promises to resolve\n const resolvedEntries = await Promise.all(\n entries.map(async ([key, promise]) => {\n const value = await promise;\n return [key, value] as [keyof T, T[keyof T]];\n }),\n );\n\n // Convert the array of resolved [key, value] pairs back into an object\n return Object.fromEntries(resolvedEntries) as T;\n}\n\nfunction getDecide<ValueType, EntitiesType>(\n definition: FlagDeclaration<ValueType, EntitiesType>,\n): Decide<ValueType, EntitiesType> {\n return function decide(params) {\n if (typeof definition.decide === 'function') {\n return definition.decide(params);\n }\n if (typeof definition.adapter?.decide === 'function') {\n return definition.adapter.decide({ key: definition.key, ...params });\n }\n throw new Error(`flags: No decide function provided for ${definition.key}`);\n };\n}\n\nfunction getIdentify<ValueType, EntitiesType>(\n definition: FlagDeclaration<ValueType, EntitiesType>,\n): Identify<EntitiesType> | undefined {\n if (typeof definition.identify === 'function') {\n return definition.identify;\n }\n if (typeof definition.adapter?.identify === 'function') {\n return definition.adapter.identify;\n }\n}\n\n/**\n * Used when a flag is called outside of a request context, i.e. outside of the lifecycle of the `handle` hook.\n * This could be the case when the flag is called from edge middleware.\n */\nconst requestMap = new WeakMap<Request, AsyncLocalContext>();\n\n/**\n * Declares a feature flag\n */\nexport function flag<\n ValueType extends JsonValue = boolean | string | number,\n EntitiesType = any,\n>(definition: FlagDeclaration<ValueType, EntitiesType>): Flag<ValueType> {\n const decide = getDecide<ValueType, EntitiesType>(definition);\n const identify = getIdentify(definition);\n\n const flagImpl = async function flagImpl(\n requestOrCode?: string | Request,\n flagsArrayOrSecret?: string | Flag<any>[],\n ): Promise<ValueType> {\n let store = flagStorage.getStore();\n\n if (!store) {\n if (requestOrCode instanceof Request) {\n store = requestMap.get(requestOrCode);\n if (!store) {\n store = createContext(\n requestOrCode,\n (flagsArrayOrSecret as string) ?? (await tryGetSecret()),\n );\n requestMap.set(requestOrCode, store);\n }\n } else {\n throw new Error('flags: Neither context found nor Request provided');\n }\n }\n\n if (\n typeof requestOrCode === 'string' &&\n Array.isArray(flagsArrayOrSecret)\n ) {\n return getPrecomputed(\n definition.key,\n flagsArrayOrSecret,\n requestOrCode,\n store.secret,\n );\n }\n\n if (hasOwnProperty(store.usedFlags, definition.key)) {\n const valuePromise = store.usedFlags[definition.key];\n if (typeof valuePromise !== 'undefined') {\n return valuePromise as Promise<ValueType>;\n }\n }\n\n const headers = sealHeaders(store.request.headers);\n const cookies = sealCookies(store.request.headers);\n\n const overridesCookie = cookies.get('vercel-flag-overrides')?.value;\n const overrides = overridesCookie\n ? await decrypt<Record<string, ValueType>>(overridesCookie, store.secret)\n : undefined;\n\n if (overrides && hasOwnProperty(overrides, definition.key)) {\n const value = overrides[definition.key];\n if (typeof value !== 'undefined') {\n reportValue(definition.key, value);\n store.usedFlags[definition.key] = Promise.resolve(value as JsonValue);\n return value;\n }\n }\n\n let entities: EntitiesType | undefined;\n if (identify) {\n // Deduplicate calls to identify, key being the function itself\n if (!store.identifiers.has(identify)) {\n const entities = identify({\n headers,\n cookies,\n });\n store.identifiers.set(identify, entities);\n }\n\n entities = (await store.identifiers.get(identify)) as EntitiesType;\n }\n\n const valuePromise = decide({\n headers,\n cookies,\n entities,\n });\n store.usedFlags[definition.key] = valuePromise as Promise<JsonValue>;\n\n const value = await valuePromise;\n reportValue(definition.key, value);\n return value;\n };\n\n flagImpl.key = definition.key;\n flagImpl.defaultValue = definition.defaultValue;\n flagImpl.origin = definition.origin;\n flagImpl.description = definition.description;\n flagImpl.options = normalizeOptions(definition.options);\n flagImpl.decide = decide;\n flagImpl.identify = identify;\n\n return flagImpl;\n}\n\nexport function getProviderData(flags: Record<string, Flag<any>>): ApiData {\n const definitions = Object.values(flags).reduce<FlagDefinitionsType>(\n (acc, d) => {\n acc[d.key] = {\n options: normalizeOptions(d.options),\n origin: d.origin,\n description: d.description,\n };\n return acc;\n },\n {},\n );\n\n return { definitions, hints: [] };\n}\n\ninterface AsyncLocalContext {\n request: Request;\n secret: string;\n params: Record<string, string>;\n usedFlags: Record<string, Promise<JsonValue>>;\n identifiers: Map<Identify<unknown>, ReturnType<Identify<unknown>>>;\n}\n\nfunction createContext(\n request: Request,\n secret: string,\n params?: Record<string, string>,\n): AsyncLocalContext {\n return {\n request,\n secret,\n params: params ?? {},\n usedFlags: {},\n identifiers: new Map(),\n };\n}\n\nconst flagStorage = new AsyncLocalStorage<AsyncLocalContext>();\n\n/**\n * Establishes context for flags, so they have access to the\n * request and cookie.\n *\n * Also registers evaluated flags, except for flags used only after `resolve` calls in other handlers.\n *\n * @example Usage example in src/hooks.server.ts\n *\n * ```ts\n * import { createHandle } from 'flags/sveltekit';\n * import * as flags from '$lib/flags';\n *\n * export const handle = createHandle({ flags });\n * ```\n *\n * @example Usage example in src/hooks.server.ts with other handlers\n *\n * Note that when composing `createHandle` with `sequence` then `createHandle` should come first. Only handlers after it will be able to access feature flags.\n */\nexport function createHandle({\n secret,\n flags,\n}: {\n secret?: string;\n flags?: Record<string, Flag<any>>;\n}): Handle {\n return async function handle({ event, resolve }) {\n secret ??= await tryGetSecret(secret);\n\n if (\n flags &&\n // avoid creating the URL object for every request by checking with includes() first\n event.request.url.includes('/.well-known/') &&\n new URL(event.request.url).pathname === '/.well-known/vercel/flags'\n ) {\n return handleWellKnownFlagsRoute(event, secret, flags);\n }\n\n const flagContext = createContext(\n event.request,\n secret,\n event.params as Record<string, string>,\n );\n return flagStorage.run(flagContext, () =>\n resolve(event, {\n transformPageChunk: async ({ html }) => {\n const store = flagStorage.getStore();\n if (!store || Object.keys(store.usedFlags).length === 0) return html;\n\n // This is for reporting which flags were used when this page was generated,\n // so the value shows up in Vercel Toolbar, without the client ever being\n // aware of this feature flag.\n const encryptedFlagValues = await encrypt(\n await resolveObjectPromises(store.usedFlags),\n secret,\n );\n\n return html.replace(\n '</body>',\n `<script type=\"application/json\" data-flag-values>${safeJsonStringify(encryptedFlagValues)}</script></body>`,\n );\n },\n }),\n );\n };\n}\n\nasync function handleWellKnownFlagsRoute(\n event: RequestEvent<Partial<Record<string, string>>, string | null>,\n secret: string,\n flags: Record<string, Flag<any>>,\n) {\n const access = await verifyAccess(\n event.request.headers.get('Authorization'),\n secret,\n );\n if (!access) return new Response(null, { status: 401 });\n return Response.json(getProviderData(flags));\n}\n\n/**\n * Function to encrypt overrides, values, definitions, and API data.\n *\n * Convenience wrapper around `encrypt` from `@vercel/flags` for not\n * having to provide a secret - it will be read from the environment\n * variable `FLAGS_SECRET` via `$env/dynamic/private` if not provided.\n */\nexport async function encrypt<T extends object>(\n value: T,\n secret?: string,\n): Promise<string> {\n return _encrypt(value, await tryGetSecret(secret));\n}\n\n/**\n * Function to decrypt overrides, values, definitions, and API data.\n *\n * Convenience wrapper around `deencrypt` from `@vercel/flags` for not\n * having to provide a secret - it will be read from the environment\n * variable `FLAGS_SECRET` via `$env/dynamic/private` if not provided.\n */\nexport async function decrypt<T extends object>(\n encryptedData: string,\n secret?: string,\n): Promise<T | undefined> {\n return _decrypt(encryptedData, await tryGetSecret(secret));\n}\n\n/**\n * Evaluate a list of feature flags and generate a signed string representing their values.\n *\n * This convenience function call combines `evaluate` and `serialize`.\n *\n * @param flags - list of flags\n * @returns - a string representing evaluated flags\n */\nexport async function precompute<T extends FlagsArray>(\n flags: T,\n request: Request,\n secret?: string,\n): Promise<string> {\n return _precompute(flags, request, await tryGetSecret(secret));\n}\n\n/**\n * Generates all permutations given a list of feature flags based on the options declared on each flag.\n * @param flags - The list of feature flags\n * @param filter - An optional filter function which gets called with each permutation.\n * @param secret - The secret sign the generated permutation with\n * @returns An array of strings representing each permutation\n */\nexport async function generatePermutations(\n flags: FlagsArray,\n filter: ((permutation: Record<string, JsonValue>) => boolean) | null = null,\n secret?: string,\n): Promise<string[]> {\n return _generatePermutations(flags, filter, await tryGetSecret(secret));\n}\n","import type { Flag, FlagsArray } from './types';\nimport type { JsonValue } from '..';\nimport * as s from '../lib/serialization';\n\ntype ValuesArray = readonly any[];\n\n/**\n * Resolves a list of flags\n * @param flags - list of flags\n * @returns - an array of evaluated flag values with one entry per flag\n */\nasync function evaluate<T extends FlagsArray>(\n flags: T,\n request: Request,\n): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>> }> {\n return Promise.all(flags.map((flag) => flag(request))) as Promise<{\n [K in keyof T]: Awaited<ReturnType<T[K]>>;\n }>;\n}\n\n/**\n * Evaluate a list of feature flags and generate a signed string representing their values.\n *\n * This convenience function call combines `evaluate` and `serialize`.\n *\n * @param flags - list of flags\n * @returns - a string representing evaluated flags\n */\nexport async function precompute<T extends FlagsArray>(\n flags: T,\n request: Request,\n secret: string,\n): Promise<string> {\n const values = await evaluate(flags, request);\n return serialize(flags, values, secret);\n}\n\n/**\n * Combines flag declarations with values.\n * @param flags - flag declarations\n * @param values - flag values\n * @returns - A record where the keys are flag keys and the values are flag values.\n */\nfunction combine(flags: FlagsArray, values: ValuesArray) {\n return Object.fromEntries(flags.map((flag, i) => [flag.key, values[i]]));\n}\n\n/**\n * Takes a list of feature flag declarations and their values and turns them into a short, signed string.\n *\n * The returned string is signed to avoid enumeration attacks.\n *\n * When a feature flag's `options` contains the value the flag resolved to, then the encoding will store it's index only, leading to better compression. Boolean values and null are compressed even when the options are not declared on the flag.\n *\n * @param flags - A list of feature flags\n * @param values - A list of the values of the flags declared in ´flags`\n * @param secret - The secret to use for signing the result\n * @returns - A short string representing the values.\n */\nasync function serialize(\n flags: FlagsArray,\n values: ValuesArray,\n secret: string,\n) {\n return s.serialize(combine(flags, values), flags, secret);\n}\n\n/**\n * Decodes all flags given the list of flags used to encode. Returns an object consisting of each flag's key and its resolved value.\n * @param flags - Flags used when `code` was generated by `precompute` or `serialize`.\n * @param code - The code returned from `serialize`\n * @param secret - The secret to use for signing the result\n * @returns - An object consisting of each flag's key and its resolved value.\n */\nasync function deserialize(flags: FlagsArray, code: string, secret: string) {\n return s.deserialize(code, flags, secret);\n}\n\n/**\n * Decodes the value of one or multiple flags given the list of flags used to encode and the code.\n *\n * @param flagKey - Flag or list of flags to decode\n * @param precomputeFlags - Flags used when `code` was generated by `serialize`\n * @param code - The code returned from `serialize`\n * @param secret - The secret to use for verifying the signature\n */\nexport async function getPrecomputed<T extends JsonValue>(\n flagKey: Flag<T>['key'],\n precomputeFlags: FlagsArray,\n code: string,\n secret: string,\n): Promise<T> {\n const flagSet = await deserialize(precomputeFlags, code, secret);\n\n return flagSet[flagKey];\n}\n\n// see https://stackoverflow.com/a/44344803\nfunction* cartesianIterator<T>(items: T[][]): Generator<T[]> {\n const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];\n for (let r of remainder) for (let h of items.at(0)!) yield [h, ...r];\n}\n\n/**\n * Generates all permutations given a list of feature flags based on the options declared on each flag.\n * @param flags - The list of feature flags\n * @param filter - An optional filter function which gets called with each permutation.\n * @param secret - The secret sign the generated permutation with\n * @returns An array of strings representing each permutation\n */\nexport async function generatePermutations(\n flags: FlagsArray,\n filter: ((permutation: Record<string, JsonValue>) => boolean) | null = null,\n secret: string,\n): Promise<string[]> {\n const options = flags.map((flag) => {\n // infer boolean permutations if you don't declare any options.\n //\n // to explicitly opt out you need to use \"filter\"\n if (!flag.options) return [false, true];\n return flag.options.map((option) => option.value);\n });\n\n const list: Record<string, JsonValue>[] = [];\n\n for (const permutation of cartesianIterator(options)) {\n const permObject = permutation.reduce<Record<string, JsonValue>>(\n (acc, value, index) => {\n acc[flags[index]!.key] = value;\n return acc;\n },\n {},\n );\n if (!filter || filter(permObject)) list.push(permObject);\n }\n\n return Promise.all(list.map((values) => s.serialize(values, flags, secret)));\n}\n","// We're doing this dance so that the flags package is usable both in the SvelteKit environment\n// as well as other environments that don't know about '$env/dynamic/private', such as Edge Middleware\nlet default_secret: string | undefined = process.env.FLAGS_SECRET;\n\nexport async function tryGetSecret(secret?: string): Promise<string> {\n if (!default_secret) {\n try {\n // @ts-expect-error SvelteKit will know about this\n // use static instead of dynamic because only the latter is available during prerendering,\n // and in case it's not available through that it should be via process.env above.\n const env = await import('$env/static/private');\n default_secret = env.FLAGS_SECRET;\n } catch (e) {\n // ignore, could happen when importing from an environment that doesn't know this import\n }\n }\n\n secret = secret || default_secret;\n\n if (!secret) {\n throw new Error(\n 'flags: No secret provided. Set an environment variable FLAGS_SECRET or provide a secret to the function.',\n );\n }\n\n return secret;\n}\n"]}