// Code generated by @openmeter/typespec-typescript. DO NOT EDIT. import type { output, ZodType } from 'zod' export function toCamelCase(name: string): string { return name.replace(/_([a-z0-9])/g, (_m, c: string) => c.toUpperCase()) } export function toSnakeCase(name: string): string { return name.replace(/([A-Z])/g, (_m, c: string) => `_${c.toLowerCase()}`) } type ZodDef = { type: string innerType?: ZodType valueType?: ZodType element?: ZodType discriminator?: string options?: ZodType[] entries?: Record defaultValue?: unknown } function def(schema: ZodType | undefined): ZodDef | undefined { return (schema as { def?: ZodDef } | undefined)?.def } // Unwrap optional/nullable/default to the schema that describes the value's // shape. These wrappers never change keys, so the walker looks through them // before classifying a node. function unwrap(schema: ZodType | undefined): ZodType | undefined { let current = schema for (let i = 0; i < 100 && current; i++) { const d = def(current) if ( d && (d.type === 'optional' || d.type === 'nullable' || d.type === 'default') && d.innerType ) { current = d.innerType continue } return current } /* v8 ignore next -- loop returns inside; reached only past the cycle guard */ return current } // The default to write for a field the caller omitted, present only when the // field is required-with-default in the spec — emitted as `.default(x)` with no // `.optional()` in the wrapper chain (TypeSpec `field: T = x`, not // `field?: T = x`). Such fields must be present on the wire (e.g. a CloudEvents // envelope's `specversion`, which the server's parser rejects when absent), yet // the generated request type allows omitting them so callers get the documented // default for free — toWire is the layer that has to reconcile the two. // Spec-optional fields (`.optional().default(x)`) return undefined and stay off // the wire: their default is the server's to apply, and materializing them // client-side would silently overwrite server state on update requests. function requiredDefault( schema: ZodType | undefined, ): { value: unknown } | undefined { let current = schema let found: { value: unknown } | undefined for (let i = 0; i < 100 && current; i++) { const d = def(current) /* v8 ignore next 3 -- every zod schema carries a def; guards the type only */ if (!d) { break } if (d.type === 'optional') { return undefined } if (d.type === 'default') { found ??= { value: d.defaultValue } } else if (d.type !== 'nullable') { break } current = d.innerType } return found } function shapeOf( schema: ZodType | undefined, ): Record | undefined { return (schema as { shape?: Record } | undefined)?.shape } // The element schema for array data: the schema's own element when it is an // array, or the array variant's element when it is a union of T and T[] // (the single-or-batch body shape). function arrayElement(schema: ZodType | undefined): ZodType | undefined { const d = def(schema) if (d?.type === 'array') { return d.element } if (d?.type === 'union') { for (const option of d.options ?? []) { const od = def(unwrap(option)) if (od?.type === 'array') { return od.element } } } return undefined } // Whether a record value schema needs walking: it carries renamable fields // (object/record/array/union of such) or date-typed values that must map // between `Date` and the RFC 3339 wire string. Other scalars, literals, // unknown, and any are left untouched, so user data (labels, dimensions, // event payloads) is never rewritten. function needsWalk(schema: ZodType | undefined): boolean { const s = unwrap(schema) const d = def(s) /* v8 ignore next 3 -- a record always has a value schema; defensive only */ if (!d) { return false } if ( d.type === 'object' || d.type === 'record' || d.type === 'date' || d.type === 'bigint' ) { return true } if (d.type === 'array') { return needsWalk(d.element) } if (d.type === 'union') { return (d.options ?? []).some(needsWalk) } return false } // Thrown by toWire when a bigint value (an int64/uint64 field) is outside // JSON's exactly-representable integer range. The wire carries int64 as a JSON // number (the server decodes it into a Go int64), so a value beyond 2^53-1 // cannot be sent without silent precision corruption — a typed, immediate // failure is the only honest option. request() catches it like any Error and // surfaces it as Result.error. export class UnsafeIntegerError extends Error { constructor(value: bigint) { super( `bigint value ${value} exceeds JSON's safe integer range and cannot be sent without precision loss`, ) this.name = 'UnsafeIntegerError' } } // An RFC 3339 string standing in for a `Date` on request input. The // `Record` intersection keeps a plain string assignable while // stopping the union simplifier from absorbing sibling string literals — a // bare `| string` would collapse `'immediate' | 'next_billing_cycle' | Date | // string` to `string | Date` and kill literal autocomplete. export type DateString = string & Record // The request-side widening of a payload type: every `Date` also accepts its // RFC 3339 string form. Applied to the generated `…Request` aliases only — // domain interfaces and response types stay `Date`, so responses always carry // real `Date`s. At runtime the mapper passes request strings through verbatim // (never re-parses or normalizes them), so the wire sees exactly what was given // and the optional wire validation still checks the string against the RFC 3339 // wire schema. export type AcceptDateStrings = T extends Date ? Date | DateString : T extends (infer E)[] ? AcceptDateStrings[] : T extends object ? { [K in keyof T]: AcceptDateStrings } : T // Literal siblings of `Date` must survive the widening. Checked at compile // time in both the emitter build and the generated SDK's typecheck, so a // regression to a bare `| string` arm fails the build. type _LiteralsSurviveWidening = 'x' extends Extract, 'x'> ? true : { __error: 'AcceptDateStrings absorbed literal union members into string' } const _literalsSurviveWidening: _LiteralsSurviveWidening = true void _literalsSurviveWidening type Direction = { // The wire→public or public→wire key rename for object fields. rename: (key: string) => string // The data key holding a discriminated union's discriminator, given the // schema's (camelCase) discriminator key. discriminatorKey: (camelKey: string) => string // The value mapping at a date-typed node: public `Date` → RFC 3339 wire // string, wire string → `Date`. Values already in the target form (or not // convertible) pass through unchanged. mapDate: (value: unknown) => unknown // The value mapping at a bigint-typed (int64/uint64) node: public `bigint` → // JSON number (throwing UnsafeIntegerError beyond 2^53-1, where JSON numbers // lose integer precision), wire number → `bigint`. Without the public→wire // mapping, JSON.stringify throws an opaque TypeError on any bigint. Values // already in the target form (or not convertible) pass through unchanged. mapBigInt: (value: unknown) => unknown // Whether absent required-with-default fields are materialized (see // requiredDefault). True only public→wire: requests must satisfy the wire // contract, while responses are reported as the server sent them — fromWire // fabricating fields would mask genuine contract violations. applyDefaults: boolean // JSON.stringify omits object properties and record entries whose value is // undefined. True only public→wire so validation sees the effective JSON // payload instead of an intermediate object that the transport cannot send. // Array entries are deliberately unaffected: JSON serializes undefined array // values as null rather than omitting them. omitUndefinedObjectEntries: boolean } // A handful of schemas are genuinely self-referential (e.g. the `and`/`or` // legs of a filter tree), so nesting depth is bounded only by the DATA the // server sends, not by the schema. Without a limit, a crafted or // accidentally-deep response recurses until the JS engine throws a raw // `RangeError: Maximum call stack size exceeded` — still caught by request() // and surfaced as Result.error, but as an opaque native error instead of a // typed one. 500 levels is far beyond any real filter/record/array nesting // in the API today; it exists to fail predictably, not to constrain valid data. const MAX_WALK_DEPTH = 500 export class DepthLimitExceededError extends Error { constructor() { super(`wire mapping exceeded maximum nesting depth (${MAX_WALK_DEPTH})`) this.name = 'DepthLimitExceededError' } } function walk( data: unknown, schema: ZodType | undefined, dir: Direction, depth = 0, ): unknown { if (data === null || data === undefined) { return data } // A Date can only ever mean its wire serialization, wherever it sits — a // typed date field, a record value, or an unknown-schema position. Wire→ // public data never contains Date instances (it comes from JSON.parse), so // this only rewrites public→wire. The same holds for bigint: JSON.parse // never produces one, and public→wire it must become a JSON number wherever // it sits. if (data instanceof Date) { return dir.mapDate(data) } if (typeof data === 'bigint') { return dir.mapBigInt(data) } if (depth > MAX_WALK_DEPTH) { throw new DepthLimitExceededError() } const s = unwrap(schema) const d = def(s) // A date-typed node maps between the public `Date` and the RFC 3339 wire // string (fromWire revives the string; a string handed to toWire by an // untyped caller passes through as-is). if (d?.type === 'date') { return dir.mapDate(data) } // A bigint-typed node revives the wire's JSON number into the public // `bigint` (public→wire bigints were already mapped by the value check // above, so only fromWire reaches a number here). if (d?.type === 'bigint') { return dir.mapBigInt(data) } if (Array.isArray(data)) { // The schema may be the array itself or a union with an array variant // (e.g. a single-or-batch body `T | T[]`); resolve the element schema from // whichever applies so array items are still walked with their shape. const element = arrayElement(s) return data.map((item) => walk(item, element, dir, depth + 1)) } if (typeof data !== 'object') { // A wire datetime can sit behind a union (`DateTime | null`, // enum-or-DateTime): revive the string only when the union's date variant // is its sole plausible owner, so enum literals and plain-string variants // pass through untouched. if ( typeof data === 'string' && d?.type === 'union' && unionDateClaims(s, data) ) { return dir.mapDate(data) } return data } const record = data as Record if (d?.type === 'record') { // Record keys are user data (label/dimension names) — preserved verbatim. // Only the value is walked, and only when it needs mapping. A null // prototype avoids the `__proto__` key silently reassigning `out`'s own // prototype instead of becoming a visible entry (user data may contain // any key, including reserved object-literal property names). The // prototype is restored once every key is a plain own property, so the // returned object still behaves normally for consumers (instanceof, // template literals) — `Object.prototype` itself was never touched. const valueSchema = needsWalk(d.valueType) ? d.valueType : undefined const out: Record = Object.create(null) for (const [key, value] of Object.entries(record)) { if (dir.omitUndefinedObjectEntries && value === undefined) { continue } out[key] = valueSchema ? walk(value, valueSchema, dir, depth + 1) : value } Object.setPrototypeOf(out, Object.prototype) return out } if (d?.type === 'union') { const variant = selectVariant(record, s, dir) if (!variant) { // No confident match: leave keys untransformed rather than guess. return data } return walk(data, variant, dir, depth + 1) } if (d?.type === 'object') { const shape = shapeOf(s) ?? {} // A null prototype avoids two failure modes from data-controlled keys // like `__proto__`/`constructor`: (1) `fieldFor` below reading an // inherited Object.prototype member instead of correctly treating the // key as schema-undeclared, and (2) the assignment at the end of this // loop reassigning `out`'s own prototype instead of adding a visible key. const out: Record = Object.create(null) for (const [key, value] of Object.entries(record)) { if (dir.omitUndefinedObjectEntries && value === undefined) { continue } const fieldSchema = fieldFor(shape, key) // Keys the schema does not declare are dropped, so the result matches the // typed shape exactly (a server-added field has no place in the type). if (fieldSchema === undefined) { continue } out[dir.rename(key)] = walk(value, fieldSchema, dir, depth + 1) } if (dir.applyDefaults) { // Shape keys are generated camelCase identifiers (never data-controlled), // so direct indexing into `record` is safe here. Runs after the data loop // so an explicit `key: undefined` entry is also replaced by the default. for (const [key, fieldSchema] of Object.entries(shape)) { if (record[key] !== undefined) { continue } const dflt = requiredDefault(fieldSchema) if (dflt !== undefined) { out[dir.rename(key)] = walk(dflt.value, fieldSchema, dir, depth + 1) } } } Object.setPrototypeOf(out, Object.prototype) return out } // Scalar or unknown schema: pass through untransformed. return data } // Resolve a data key to its field schema. The schema is camelCase-keyed; a // wire→public data key is snake, so it is camelized to index the shape. // Own-property checks (not `shape[key]`) so a data-controlled key like // `__proto__` or `constructor` cannot resolve to an inherited // Object.prototype member and be mistaken for a declared schema field. function fieldFor( shape: Record, dataKey: string, ): ZodType | undefined { if (Object.hasOwn(shape, dataKey)) { return shape[dataKey] } const camelKey = toCamelCase(dataKey) return Object.hasOwn(shape, camelKey) ? shape[camelKey] : undefined } function selectVariant( data: Record, schema: ZodType | undefined, dir: Direction, ): ZodType | undefined { const d = def(schema) const options = d?.options ?? [] if (d?.discriminator && schema) { // O(1) dispatch on the discriminator literal. The data key is the wire-name in // fromWire (snake) and the public name in toWire (camel); the variant map is // keyed by the literal value, which is identical in both directions. const dataKey = dir.discriminatorKey(d.discriminator) return variantsByDiscriminator(schema, d).get(data[dataKey]) } // Non-discriminated union: the codegen gate guarantees at most one object // variant (it fails the build for a mapped union with two or more), so the single // object-shaped option is unambiguous. Other variants (scalars, arrays) reach the // walk through their own data-kind branches, not here. return options.find((option) => def(unwrap(option))?.type === 'object') } // Memoized literal→variant map for a discriminated union, built once per schema. const variantMapCache = new WeakMap>() function variantsByDiscriminator( schema: ZodType, d: ZodDef, ): Map { const cached = variantMapCache.get(schema) if (cached) { return cached } const map = new Map() for (const option of d.options ?? []) { const shape = shapeOf(unwrap(option)) const literal = literalValue(shape?.[d.discriminator as string]) if (literal !== undefined) { map.set(literal, option) } } variantMapCache.set(schema, map) return map } function literalValue(schema: ZodType | undefined): unknown { const s = unwrap(schema) if (def(s)?.type === 'literal') { return (s as { value?: unknown }).value } /* v8 ignore next -- a discriminated-union variant's discriminator is a literal */ return undefined } // Whether a union's date variant is the sole plausible owner of a string // value: the union carries a date option, no string-capable sibling (a plain // string variant, an enum containing the value, an equal string literal) // claims it, and the value actually parses as a date. `DateTime | null` // revives its RFC 3339 string; `'immediate' | DateTime` keeps the enum // literal a string. Fail-open: an unclaimed string stays a string. function unionDateClaims(schema: ZodType | undefined, value: string): boolean { let hasDate = false for (const option of def(schema)?.options ?? []) { const od = def(unwrap(option)) if (od?.type === 'date') { hasDate = true } else if (od?.type === 'string') { return false } else if ( od?.type === 'enum' && Object.values(od.entries ?? {}).includes(value) ) { return false } else if (od?.type === 'literal' && literalValue(option) === value) { return false } } return hasDate && !Number.isNaN(Date.parse(value)) } const toWireDirection: Direction = { rename: toSnakeCase, discriminatorKey: (camelKey) => camelKey, mapDate: (value) => (value instanceof Date ? value.toISOString() : value), mapBigInt: (value) => { if (typeof value !== 'bigint') { return value } if ( value > BigInt(Number.MAX_SAFE_INTEGER) || value < -BigInt(Number.MAX_SAFE_INTEGER) ) { throw new UnsafeIntegerError(value) } return Number(value) }, applyDefaults: true, omitUndefinedObjectEntries: true, } // Path binding names are transport metadata, not JSON object member names, so // they must remain exactly as declared while their values receive the same // Date/bigint/default mapping used by request bodies and query parameters. const toPathWireDirection: Direction = { ...toWireDirection, rename: (key) => key, } const fromWireDirection: Direction = { rename: toCamelCase, discriminatorKey: (camelKey) => toSnakeCase(camelKey), mapDate: (value) => (typeof value === 'string' ? new Date(value) : value), mapBigInt: (value) => typeof value === 'number' && Number.isInteger(value) ? BigInt(value) : value, applyDefaults: false, omitUndefinedObjectEntries: false, } // Rewrite a request body or query object from the camelCase public shape to the // snake_case wire shape, driven by its schema. Record keys (label/dimension names) // are preserved; `Date` values serialize to RFC 3339 strings; `bigint` values // (int64 fields) become JSON numbers; omitted required-with-default fields are // filled with their declared default (see requiredDefault); explicit undefined // object/record entries are omitted just as JSON.stringify would omit them. The // return is typed as the input `T` so call sites stay cast-free (the runtime object // has snake keys and wire-encoded dates, but the value is write-only — it flows // straight into `json:`/`toURLSearchParams`, both of which accept any object). export function toWire(data: T, schema: ZodType): T { return walk(data, schema, toWireDirection) as T } // Rewrite path-parameter values to their transport representation without // renaming the path binding keys. The returned object is subsequently validated // against the generated `…PathParamsWire` schema and URL-encoded by the func. export function toPathWire(data: T, schema: ZodType): T { return walk(data, schema, toPathWireDirection) as T } // Rewrite a response body from the snake_case wire shape to the camelCase public // shape: renames keys and revives RFC 3339 strings into `Date`s at date-typed // nodes — never applies defaults or any other coercion. The result is the // schema's output shape: `walk` produces exactly the schema's known fields in // camelCase, so the inferred `output` type describes the runtime value (the // same wire-trust boundary as a plain `.json()`, with no `.parse()`). export function fromWire( data: unknown, schema: S, ): output { return walk(data, schema, fromWireDirection) as output } // Thrown by assertValid when the optional `validate` client option is on and data // fails its schema. request() catches it like any Error and surfaces it as // Result.error. export class ValidationError extends Error { constructor( message: string, public readonly issues: unknown, ) { super(message) this.name = 'ValidationError' } } // Opt-in schema check used by the funcs (when the validate option is on) against // the snake_case wire payload: the request body after toWire, the raw response // before fromWire, each against its generated `…Wire` schema. It is a GATE, not a // transform — the safeParse output (coercions/defaults) is discarded, so validation // never mutates the payload or return value. Off by default; the SDK does not // validate by default (additive server fields must not break clients). export function assertValid(schema: ZodType, data: unknown): void { const result = schema.safeParse(data) if (!result.success) { throw new ValidationError('schema validation failed', result.error.issues) } }