UNPKG

@web-widget/flags-kit

Version:

Flags SDK by Vercel - The feature flags toolkit for Next.js, SvelteKit, and Web Router - Enhanced fork with improved Web Router support

236 lines (230 loc) 10.1 kB
import { MiddlewareHandler, MiddlewareContext } from '@web-widget/schema'; import { J as JsonValue, f as FlagDeclaration, i as FlagOption, I as Identify, e as FlagDefinitionType, P as ProviderData, c as ApiData } from './types-5yiq7z-v.js'; import 'http'; import '@edge-runtime/cookies'; /** * Metadata on a feature flag function */ type FlagMeta<ValueType, EntitiesType> = { /** * The key of the feature flag */ key: FlagDeclaration<ValueType, EntitiesType>['key']; /** * An optional defaultValue which will be used when the flag's `decide` function returns undefined or throws an error. Catches async errors too. */ defaultValue?: FlagDeclaration<ValueType, EntitiesType>['defaultValue']; /** * A URL where this feature flag can be managed. Will show up in Vercel Toolbar. */ origin?: FlagDeclaration<ValueType, EntitiesType>['origin']; /** * A description of this feature flag. Will show up in Vercel Toolbar. */ description?: FlagDeclaration<ValueType, EntitiesType>['description']; /** * An array containing available options. * * * The returend value does not need to be declared in `options`, but it's recommended as all declared options show up in Vercel Toolbar. * * Value is required, but the label is optional. * @example `[{ label: "Off", value: false }, { label: "On", value: true }]` * * Non-objects like strings can be passed using shorthands which will be used as values without labels. * @example `["EUR", "USD"]` */ options?: FlagOption<ValueType>[]; /** * This function is called when the feature flag is used (and no override is present) to return a value. */ decide: FlagDeclaration<ValueType, EntitiesType>['decide']; /** * This function can establish entities which the `decide` function will be called with. */ identify?: FlagDeclaration<ValueType, EntitiesType>['identify']; /** * Evaluates a feature flag with custom entities. * * Calling .run() bypasses the identify call and uses the provided entities directly. */ run: (options: { identify: FlagDeclaration<ValueType, EntitiesType>['identify'] | EntitiesType; request?: Request; }) => Promise<ValueType>; }; /** * A web-router feature flag function */ type Flag<ValueType extends JsonValue, EntitiesType = any> = { (): Promise<ValueType>; (request: Request): Promise<ValueType>; (request: Request, secret: string): Promise<ValueType>; (code: string, flags: Flag<any>[]): Promise<ValueType>; (code: string, flags: Flag<any>[], secret?: string): Promise<ValueType>; } & FlagMeta<ValueType, EntitiesType>; type FlagsArray = readonly Flag<any>[]; type ValuesArray = readonly any[]; /** * Resolves a list of flags * @param flags - list of flags * @returns - an array of evaluated flag values with one entry per flag */ declare function evaluate<T extends FlagsArray>(flags: T): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>; /** * Evaluate a list of feature flags and generate a signed string representing their values. * * This convenience function call combines `evaluate` and `serialize`. * * @param flags - list of flags * @returns - a string representing evaluated flags */ declare function precompute<T extends FlagsArray>(flags: T): Promise<string>; /** * Combines flag declarations with values. * @param flags - flag declarations * @param values - flag values * @returns - A record where the keys are flag keys and the values are flag values. */ declare function combine(flags: FlagsArray, values: ValuesArray): { [k: string]: any; }; /** * Takes a list of feature flag declarations and their values and turns them into a short, signed string. * * The returned string is signed to avoid enumeration attacks. * * 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. * * @param flags - A list of feature flags * @param values - A list of the values of the flags declared in ´flags` * @param secret - The secret to use for signing the result * @returns - A short string representing the values. */ declare function serialize(flags: FlagsArray, values: ValuesArray, secret?: string | undefined): Promise<string>; /** * Decodes all flags given the list of flags used to encode. Returns an object consisting of each flag's key and its resolved value. * @param flags - Flags used when `code` was generated by `precompute` or `serialize`. * @param code - The code returned from `serialize` * @param secret - The secret to use for signing the result * @returns - An object consisting of each flag's key and its resolved value. */ declare function deserialize(flags: FlagsArray, code: string, secret?: string | undefined): Promise<Record<string, any>>; /** * Decodes the value of one flag given the list of flags used to encode and the code. * * @param flag - Flag to decode * @param precomputeFlags - Flags used when `code` was generated by `serialize` * @param code - The code returned from `serialize` * @param secret - The secret to use for verifying the signature */ declare function getPrecomputed<T extends JsonValue>(flag: Flag<T>, precomputeFlags: FlagsArray, code: string, secret?: string): Promise<T>; /** * Decodes the value of multiple flags given the list of flags used to encode and the code. * * @param flags - Array of flags to decode * @param precomputeFlags - Flags used when `code` was generated by `serialize` * @param code - The code returned from `serialize` * @param secret - The secret to use for verifying the signature */ declare function getPrecomputed<T extends JsonValue, K extends readonly Flag<T>[]>(flags: readonly [...K], precomputeFlags: FlagsArray, code: string, secret?: string): Promise<{ [P in keyof K]: K[P] extends Flag<infer U> ? U : never; }>; /** * Generates all permutations given a list of feature flags based on the options declared on each flag. * @param flags - The list of feature flags * @param filter - An optional filter function which gets called with each permutation. * @param secret - The secret sign the generated permutation with * @returns An array of strings representing each permutation */ declare function generatePermutations(flags: FlagsArray, filter?: ((permutation: Record<string, JsonValue>) => boolean) | null, secret?: string): Promise<string[]>; /** * A web-router-friendly version of React.cache. * * Given the same arguments, the function wrapped by this function will only ever run once for the duration of a request. * * This function ensures that expensive operations like database queries or API calls * are not duplicated within the same request context. * * @param fn - The function to deduplicate * @returns A deduped version of the function */ declare function dedupe<A extends Array<unknown>, T>(fn: (...args: A) => T | Promise<T>): (...args: A) => Promise<T>; /** * Clears the cached value of a deduped function for the current request. * * This function is useful for resetting the cache after making changes to * the underlying cached information. * * @param dedupedFn - The deduped function to clear cache for */ declare function clearDedupeCacheForCurrentRequest(dedupedFn: (...args: unknown[]) => unknown): boolean; declare module '@web-widget/schema' { interface State { _flag?: FlagContext; } } /** * Declares a feature flag */ declare function flag<ValueType extends JsonValue = boolean | string | number, EntitiesType = any>(definition: FlagDeclaration<ValueType, EntitiesType>): Flag<ValueType, EntitiesType>; type KeyedFlagDefinitionType = { key: string; } & FlagDefinitionType; declare function getProviderData(flags: Record<string, KeyedFlagDefinitionType | readonly unknown[]>): ProviderData; interface FlagContext { request: Request; secret: string; usedFlags: Record<string, Promise<JsonValue>>; identifiers: Map<Identify<unknown>, ReturnType<Identify<unknown>>>; } /** * Establishes context for flags, so they have access to the * request and cookie. * * Also registers evaluated flags, except for flags used only after `resolve` calls in other handlers. * * @example Usage example in routes/(middlewares)/global.ts * * ```ts * import { createHandle } from 'flags/web-router'; * import * as flags from '#config/flags'; * * export default createHandle({ * flags, * secret: process.env.FLAGS_SECRET, * }); * ``` * * @example Usage example with other middleware handlers * * ```ts * import { composeMiddleware } from '@web-widget/helpers'; * import { createHandle } from 'flags/web-router'; * import * as flags from '#config/flags'; * * const flagsMiddleware = createHandle({ * flags, * secret: process.env.FLAGS_SECRET, * }); * * export default composeMiddleware([otherMiddleware, flagsMiddleware]); * ``` * * Note that when composing `createHandle` with other middleware, `createHandle` should come after other middleware that don't require access to flags. Only handlers after it will be able to access feature flags. */ declare function createHandle({ secret, flags, }: { secret?: string; flags?: Record<string, Flag<any>>; }): MiddlewareHandler; /** * Creates a well-known flags endpoint for WebRouter. * @param getApiData a function returning the API data * @param options accepts a secret * @returns a RequestHandler */ declare function createFlagsDiscoveryEndpoint(getApiData: (context: MiddlewareContext) => Promise<ApiData> | ApiData, options?: { secret?: string | undefined; }): MiddlewareHandler; export { type Flag, type KeyedFlagDefinitionType, clearDedupeCacheForCurrentRequest, combine, createFlagsDiscoveryEndpoint, createHandle, dedupe, deserialize, evaluate, flag, generatePermutations, getPrecomputed, getProviderData, precompute, serialize };