UNPKG

axiom

Version:

Axiom AI SDK provides - an API to wrap your AI calls with observability instrumentation. - offline evals - online evals

128 lines (125 loc) 5.79 kB
import { ZodObject, ZodDefault, z } from 'zod'; type DefaultMaxDepth = 8; type HasDefaults<S> = S extends { _zod: { def: { defaultValue: unknown; }; }; } ? true : S extends ZodObject<infer Shape> ? { [K in keyof Shape]: HasDefaults<Shape[K]>; } extends Record<keyof Shape, true> ? true : false : false; type UnwrapSchema<T> = T extends ZodDefault<infer U> ? U : T; type AllFieldsHaveDefaults<Schema> = Schema extends { _zod: { def: { defaultValue: unknown; }; }; } ? true : HasDefaults<UnwrapSchema<Schema>>; interface AppScopeConfig<FlagSchema extends ZodObject<any> | undefined = undefined, FactSchema extends ZodObject<any> | undefined = undefined> { flagSchema: FlagSchema; factSchema?: FactSchema; } /** * Recursive type to extract all possible paths from an object type. * Uses stack-based depth limiting for better performance. * * @template T - The object type to extract paths from * @template Stack - Internal stack counter (do not set manually) * @template MaxDepth - Maximum recursion depth (default: 8 for good balance) */ type ObjectPaths<T, Stack extends unknown[] = [], MaxDepth extends number = DefaultMaxDepth> = Stack['length'] extends MaxDepth ? never : T extends object ? { [K in keyof T]-?: K extends string | number ? `${K}` | `${K}.${ObjectPaths<T[K], [1, ...Stack], MaxDepth>}` : never; }[keyof T] : never; type ObjectPathValue<T, P extends string> = P extends keyof T ? T[P] : P extends `${infer K}.${infer Rest}` ? K extends keyof T ? ObjectPathValue<T[K], Rest> : never : never; /** * Generate deep nested paths from flag schema. * * @template T - ZodObject to extract paths from * @template MaxDepth - Maximum recursion depth (default: 8, override for deeper nesting) * @example * // Default 8-level depth * type Paths = DotPaths<MySchema> * * // Custom depth for deeper nesting (impacts performance) * type DeepPaths = DotPaths<MySchema, 12> */ type DotPaths<T extends ZodObject<any>, MaxDepth extends number = DefaultMaxDepth> = { [NS in keyof T['shape']]: (string & NS) | { [P in ObjectPaths<z.output<UnwrapSchema<T['shape'][NS]>>, [ ], MaxDepth>]: `${string & NS}.${P}`; }[ObjectPaths<z.output<UnwrapSchema<T['shape'][NS]>>, [], MaxDepth>]; }[keyof T['shape']]; type PathValue<T extends ZodObject<any>, P extends string> = P extends `${infer NS}.${infer Rest}` ? NS extends keyof T['shape'] ? ObjectPathValue<z.output<UnwrapSchema<T['shape'][NS]>>, Rest> : never : P extends keyof T['shape'] ? z.output<UnwrapSchema<T['shape'][P]>> : never; type DotNotationFlagFunction<FS extends ZodObject<any> | undefined> = FS extends ZodObject<any> ? <P extends DotPaths<FS>>(path: P) => PathValue<FS, P> : never; type FactFunction<SC extends ZodObject<any> | undefined> = SC extends ZodObject<any> ? <P extends DotPaths<SC> & string>(name: P, value: PathValue<SC, P>) => void : never; type OverrideFlagsFunction<FS extends ZodObject<any> | undefined> = FS extends ZodObject<any> ? (partial: { [K in DotPaths<FS>]?: PathValue<FS, K>; }) => void : (partial: Record<string, any>) => void; type WithFlagsFunction<FS extends ZodObject<any> | undefined> = FS extends ZodObject<any> ? <T>(overrides: { [K in DotPaths<FS>]?: PathValue<FS, K>; }, fn: () => T) => T : <T>(overrides: Record<string, any>, fn: () => T) => T; type PickFlagsFunction<FS extends ZodObject<any> | undefined> = FS extends ZodObject<any> ? { <K extends ReadonlyArray<DotPaths<FS> & string>>(...paths: K): K; <K extends ReadonlyArray<DotPaths<FS> & string>>(paths: K): K; } : never; interface AppScope<FS extends ZodObject<any> | undefined, SC extends ZodObject<any> | undefined> { flag: DotNotationFlagFunction<FS>; fact: FactFunction<SC>; overrideFlags: OverrideFlagsFunction<FS>; withFlags: WithFlagsFunction<FS>; pickFlags: PickFlagsFunction<FS>; getAllDefaultFlags: () => Record<string, any>; } /** * Create a new application-level evaluation scope. * * @param config.flagSchema A zod object describing the schema for flags **(required)** * @param config.factSchema A zod object describing the schema for facts (optional) * * @example * import { z } from 'zod'; * * const { flag, fact, withFlags, pickFlags, overrideFlags } = createAppScope({ * flagSchema: z.object({ * ui: z.object({ * darkMode: z.boolean().default(false), * theme: z.object({ * primary: z.string().default('#00f'), * }), * }), * api: z.object({ endpoint: z.string().default('/api') }), * }), * factSchema: z.object({ * userAction: z.string(), * timing: z.number(), * }), * }); * * // Typed flag access * const dark = flag('ui.darkMode'); // inferred boolean * const theme = flag('ui.theme'); // entire object * const primary = flag('ui.theme.primary'); // '#00f' * const endpoint = flag('api.endpoint'); // uses schema default * * // Typed fact recording * fact('userAction', 'clicked_button'); * fact('timing', 1250); * * // Temporarily override flags for a block of code * withFlags({ 'ui.darkMode': true }, () => { * // code here, `ui.darkMode` will be true in this block and reset after * }); * * // Override flags globally for the current evaluation run * overrideFlags({ 'api.endpoint': '/custom' }); */ declare function createAppScope<FlagSchema extends ZodObject<any>, FactSchema extends ZodObject<any> | undefined = undefined>(config: AllFieldsHaveDefaults<FlagSchema> extends true ? AppScopeConfig<FlagSchema, FactSchema> : { flagSchema: FlagSchema; factSchema?: FactSchema; __error__: 'createAppScope: flagSchema must have .default() for all leaf fields'; }): AppScope<FlagSchema, FactSchema>; export { createAppScope as c };