@emeryld/rrroutes-contract 2.4.21 → 2.4.22

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.
@@ -253,11 +253,11 @@ export type LeafLowProfile<M extends HttpMethod = HttpMethod, P extends string =
253
253
  readonly cfg: Readonly<C>;
254
254
  };
255
255
  /** Infer params either from the explicit params schema or from the path literal. */
256
- export type InferParams<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['paramsSchema'] extends RouteSchema<any, infer PIn> ? PIn : L['cfg']['paramsSchema'] extends ZodType<any, infer PIn> ? PIn : Fallback;
256
+ export type InferParams<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['paramsSchema'] extends RouteSchema<infer POut> ? POut : L['cfg']['paramsSchema'] extends ZodType<infer POut> ? POut : Fallback;
257
257
  /** Infer query shape from a Zod schema when present. */
258
- export type InferQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['querySchema'] extends RouteSchema<any, infer QIn> ? QIn : L['cfg']['querySchema'] extends ZodType<any, infer QIn> ? QIn : Fallback;
258
+ export type InferQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['querySchema'] extends RouteSchema<infer QOut> ? QOut : L['cfg']['querySchema'] extends ZodType<infer QOut> ? QOut : Fallback;
259
259
  /** Infer request body shape from a Zod schema when present. */
260
- export type InferBody<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['bodySchema'] extends RouteSchema<any, infer BIn> ? BIn : L['cfg']['bodySchema'] extends ZodType<any, infer BIn> ? BIn : Fallback;
260
+ export type InferBody<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['bodySchema'] extends RouteSchema<infer BOut> ? BOut : L['cfg']['bodySchema'] extends ZodType<infer BOut> ? BOut : Fallback;
261
261
  /** Infer handler output shape from a Zod schema. Defaults to unknown. */
262
262
  type InferMetaFromCfg<L extends AnyLeafLowProfile> = L['cfg']['outputMetaSchema'] extends RouteSchema<infer O> ? O : L['cfg']['outputMetaSchema'] extends ZodType<infer O> ? O : string | undefined;
263
263
  type ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends [never] | [unknown] ? InferMetaFromCfg<L> : M;
@@ -269,8 +269,6 @@ type ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {
269
269
  meta: ResolvedMeta<L, M>;
270
270
  }) & Omit<O, 'meta'> : O;
271
271
  export type InferOutput<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['outputSchema'] extends RouteSchema<infer O> ? ApplyMetaFallback<L, O> : L['cfg']['outputSchema'] extends ZodType<infer O> ? ApplyMetaFallback<L, O> : Fallback;
272
- export type InferFeedOutputMeta<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['outputMetaSchema'] extends RouteSchema<infer O> ? O : L['cfg']['outputMetaSchema'] extends ZodType<infer O> ? O : Fallback;
273
- export type InferFeedQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['queryExtensionSchema'] extends RouteSchema<any, infer QIn> ? QIn : L['cfg']['queryExtensionSchema'] extends ZodType<any, infer QIn> ? QIn : Fallback;
274
272
  /** Render a type as if it were a simple object literal. */
275
273
  export type Prettify<T> = {
276
274
  [K in keyof T]: T[K];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/routesV3.builder.ts","../src/core/routesV3.core.ts","../src/core/routesV3.finalize.ts","../src/sockets/socket.index.ts"],"sourcesContent":["export * from './core/routesV3.builder'\nexport * from './core/routesV3.core'\nexport * from './core/routesV3.finalize'\nexport * from './sockets/socket.index'\n","import { z, ZodObject, ZodType } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n buildLowProfileLeaf,\n FeedQueryField,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n mergeSchemas,\n MethodCfg,\n NodeCfg,\n OutputField,\n Prettify,\n} from './routesV3.core'\n\ntype ParamZod<Name extends string, S extends ZodType> = ZodObject<{\n [K in Name]: S\n}>\ntype BaseMethodCfg<C extends MethodCfg> = Merge<\n Omit<MethodCfg, 'querySchema' | 'outputSchema' | 'feed'>,\n Omit<C, 'querySchema' | 'outputSchema' | 'feed'>\n>\n\ntype FeedField<C extends MethodCfg> = C['feed'] extends true\n ? { feed: true }\n : { feed?: boolean }\n\ntype NonFeedQueryField<C extends MethodCfg> = C['querySchema'] extends ZodType\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodType\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n : FeedField<C> & NonFeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n\ntype WithNodeDefaults<C extends MethodCfg, I extends NodeCfg> = Merge<\n C,\n {\n queryExtensionSchema: C['queryExtensionSchema'] extends ZodType\n ? C['queryExtensionSchema']\n : NodeQueryExtension<I>\n outputMetaSchema: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : NodeOutputMeta<I>\n }\n>\n\n// Avoids the previous MethodCfg merge step so TS doesn't have to repeatedly\n// expand the entire MethodCfg intersection for every method call.\ntype EffectiveCfgWithDefaults<C extends MethodCfg, PS> = Prettify<\n BaseMethodCfg<C> & EffectiveFeedFields<C, PS>\n>\n\ntype EffectiveCfg<C extends MethodCfg, PS, I extends NodeCfg> =\n WithNodeDefaults<C, I> extends infer WithDefaults extends MethodCfg\n ? EffectiveCfgWithDefaults<WithDefaults, PS>\n : never\n\ntype NodeWithoutSchemas<I extends NodeCfg> = Omit<\n I,\n 'queryExtensionSchema' | 'outputMetaSchema'\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<\n M,\n Base,\n Merge<NodeWithoutSchemas<I>, LowProfileCfg<EffectiveCfg<C, PS, I>>>\n>\n\ntype StripParamName<Name extends string> = Name extends `:${infer P}` ? P : Name\ntype NormalizeBaseLiteral<\n Base extends string,\n HasParam extends boolean,\n> = HasParam extends true\n ? Base extends `:${string}`\n ? Base\n : Base extends ''\n ? ''\n : `:${Base}`\n : Base\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType ? ParamZod<StripParamName<Base>, Param> : undefined\ntype ResourceBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = NormalizeBaseLiteral<Base, Param extends ZodType ? true : false>\ntype NodeQueryExtension<I extends NodeCfg> = I extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\ntype NodeOutputMeta<I extends NodeCfg> = I extends {\n outputMetaSchema?: infer OE\n}\n ? OE extends ZodType\n ? OE\n : undefined\n : undefined\n\ntype SubResourceCollections = readonly [\n ReadonlyArray<AnyLeafLowProfile>,\n ...ReadonlyArray<AnyLeafLowProfile>[],\n]\n\n// Bundling the branch generics keeps MethodFns<State, Used> from re-instantiating\n// four independent parameters for every chained call, which speeds up inference.\ntype BranchState<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n> = {\n base: Base\n leaves: Acc\n node: I\n params: PS\n}\n\ntype AnyBranchState = BranchState<\n string,\n readonly AnyLeafLowProfile[],\n NodeCfg,\n ZodType | undefined\n>\n\nexport type MergeAugmentedCollections<\n Base extends string,\n Param extends ZodType | undefined,\n Collections extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = Collections extends readonly [infer First, ...infer Rest]\n ? First extends ReadonlyArray<AnyLeafLowProfile>\n ? Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? MergeAugmentedCollections<\n Base,\n Param,\n Rest,\n MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n >\n : MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n : MergeAugmentedCollections<\n Base,\n Param,\n Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? Rest\n : [],\n Acc\n >\n : Acc\n\ntype MethodFns<\n State extends AnyBranchState,\n Used extends HttpMethod | 'sub',\n> = {\n /**\n * Register a GET leaf at the current path.\n */\n get: 'get' extends Used\n ? never\n : <C extends MethodCfg>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<'get', State['base'], State['node'], C, State['params']>\n >,\n State['node'],\n State['params'],\n Used | 'get'\n >\n\n /**\n * Register a POST leaf at the current path.\n */\n post: 'post' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'post',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'post'\n >\n\n /**\n * Register a PUT leaf at the current path.\n */\n put: 'put' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'put',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'put'\n >\n\n /**\n * Register a PATCH leaf at the current path.\n */\n patch: 'patch' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'patch',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'patch'\n >\n\n /**\n * Register a DELETE leaf at the current path.\n */\n delete: 'delete' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'delete',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'delete'\n >\n}\n\n/** Builder surface used by `resource(...)` to accumulate leaves. */\nexport interface Branch<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n Used extends HttpMethod | 'sub' = never,\n> extends MethodFns<BranchState<Base, Acc, I, PS>, Used> {\n /**\n * Mount one or more sub-resources that were built via `resource(...)`.\n * Each resource carries its own base path (e.g. `users`, `:userId`, `posts`)\n * so this branch simply prefixes its current `Base` and merges param schemas.\n */\n sub: 'sub' extends Used\n ? never\n : <\n const Collections extends SubResourceCollections,\n NextAcc extends readonly AnyLeafLowProfile[] = MergeArray<\n Acc,\n MergeAugmentedCollections<Base, PS, Collections>\n >,\n >(\n ...collections: Collections\n ) => Branch<Base, NextAcc, I, PS, Used | 'sub'>\n\n /**\n * Finish the branch and return the collected leaves.\n * @returns Readonly tuple of accumulated leaves.\n */\n done(): Readonly<Acc>\n}\n\n/**\n * Start building a resource at the given base path.\n * @param base Root path for the resource (e.g. `/v1`).\n * @param inherited Optional node configuration applied to all descendants.\n * @returns Root `Branch` instance used to compose the route tree.\n */\nexport function resource<\n Base extends string = '',\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base?: Base,\n inherited?: I,\n idSchema?: Param,\n): Branch<\n ResourceBase<Base, Param>,\n readonly [],\n I,\n ParamSchemaForBase<Base, Param>\n> {\n const rawBase = (base ?? '') as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as ResourceBase<Base, Param>\n const rootInherited: I =\n inherited === undefined ? ({} as I) : ({ ...inherited } as I)\n const rootParams = createParamSchema(rawBase, idSchema) as\n | ParamSchemaForBase<Base, Param>\n | undefined\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodType | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeafLowProfile[] = []\n const currentBase: Base2 = base2\n const inheritedCfg: I2 = inherited2\n let currentParamsSchema: PS2 = mergedParamsSchema as PS2\n\n function add<M extends HttpMethod, C extends MethodCfg>(method: M, cfg: C) {\n const effectiveParamsSchema = (cfg.paramsSchema ??\n currentParamsSchema) as PS2 | undefined\n const fullCfg = (\n effectiveParamsSchema\n ? { ...cfg, paramsSchema: effectiveParamsSchema }\n : { ...cfg }\n ) as MethodCfg\n\n const leaf = buildLowProfileLeaf({\n method,\n path: currentBase as Base2,\n node: inheritedCfg,\n cfg: fullCfg,\n })\n\n stack.push(leaf as AnyLeafLowProfile)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount one or more subtrees built elsewhere.\n * Usage:\n * resource('/api').sub(\n * resource('users').get(...).done(),\n * resource('projects').get(...).done()\n * )\n */\n sub(...collections: readonly AnyLeafLowProfile[][]) {\n if (collections.length === 0) {\n throw new Error('sub() expects at least one resource')\n }\n\n for (const leaves of collections) {\n for (const leafLow of leaves) {\n const leaf = leafLow as unknown as AnyLeaf\n const leafCfg = leaf.cfg as MethodCfg\n const leafParams = leafCfg.paramsSchema as ZodType | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...inheritedCfg,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: joinPaths(currentBase, leaf.path),\n cfg: newCfg,\n }\n\n stack.push(newLeaf as AnyLeafLowProfile)\n }\n }\n\n return api\n },\n\n // methods (inject current params schema if missing)\n get<C extends MethodCfg>(cfg: C) {\n return add('get', cfg)\n },\n post<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('post', { ...cfg, feed: false })\n },\n put<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('put', { ...cfg, feed: false })\n },\n patch<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('patch', { ...cfg, feed: false })\n },\n delete<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('delete', { ...cfg, feed: false })\n },\n\n done() {\n return stack as readonly AnyLeafLowProfile[]\n },\n }\n\n return api as Branch<Base2, readonly [], I2, PS2>\n }\n\n // Root branch starts with no params schema (PS = undefined)\n return makeBranch(normalizedBase, rootInherited, rootParams)\n}\n\n/**\n * Merge two readonly tuples (preserves literal tuple information).\n * @param arr1 First tuple.\n * @param arr2 Second tuple.\n * @returns New tuple containing values from both inputs.\n */\nexport const mergeArrays = <T extends readonly any[], S extends readonly any[]>(\n arr1: T,\n arr2: S,\n) => {\n return [...arr1, ...arr2] as [...T, ...S]\n}\n\nfunction normalizeBaseSegment(base: string, hasParam: boolean) {\n const value = base ?? ''\n if (!hasParam) return value\n if (!value) {\n throw new Error(\n 'resource() requires a segment name when defining an id schema',\n )\n }\n if (value.includes('/')) {\n const segments = value.split('/').filter(Boolean)\n if (segments.length === 0) {\n throw new Error(\n 'resource() received an invalid segment for param injection',\n )\n }\n const lastIndex = segments.length - 1\n const last = segments[lastIndex]\n segments[lastIndex] = last.startsWith(':') ? last : `:${last}`\n return `${value.startsWith('/') ? '/' : ''}${segments.join('/')}`\n }\n return value.startsWith(':') ? value : `:${value}`\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const segments = nameSegment.split('/').filter(Boolean)\n const rawName =\n segments.length > 0 ? segments[segments.length - 1] : nameSegment\n const normalized = rawName.startsWith(':') ? rawName.slice(1) : rawName\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n return z.object({ [normalized]: schema } as Record<string, ZodType>)\n}\n\nfunction joinPaths(parent: string, child: string) {\n if (!parent) return child\n if (!child) return parent\n const trimmedParent = parent.endsWith('/')\n ? parent.replace(/\\/+$/, '')\n : parent\n const trimmedChild = child.startsWith('/') ? child.replace(/^\\/+/, '') : child\n if (!trimmedChild) return trimmedParent\n return `${trimmedParent}/${trimmedChild}`\n}\n","import { z, ZodObject, ZodSafeParseResult, ZodType } from 'zod'\n\n/** Supported HTTP verbs for the routes DSL. */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** Declarative description of a multipart upload field. */\nexport type FileField = {\n /** Form field name used for uploads. */\n name: string\n /** Maximum number of files accepted for this field. */\n maxCount: number\n}\n\n/** Configuration that applies to an entire branch of the route tree. */\nexport interface NodeCfg {\n /**\n * Feed-specific query schema applied to all descendants unless they override it.\n */\n queryExtensionSchema?: ZodType\n /**\n * Feed meta schema applied to all descendants unless they override it.\n */\n outputMetaSchema?: ZodType\n}\n\nexport type RouteSchema<Output = unknown, Input = Output> = {\n __out: Output\n __in?: Input\n}\n\ntype RouteSchemaOrUndefined<S extends ZodType | undefined> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : undefined\n\ntype FeedAwareQueryRoute<\n Feed extends boolean,\n Query extends ZodType | undefined,\n Extension extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Feed extends true\n ? ToRouteSchema<\n FeedQueryField<{\n querySchema: Query\n queryExtensionSchema: EffectiveQueryExtensionSchema<Extension, Node>\n }>['querySchema']\n >\n : RouteSchemaOrUndefined<Query>\n\ntype OutputRouteSchema<\n O extends ZodType | undefined,\n Meta extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = ToRouteSchema<\n OutputField<{\n outputSchema: O\n outputMetaSchema: EffectiveOutputMetaSchema<Meta, Node>\n }>['outputSchema']\n>\n\nexport type FeedQueryField<C extends MethodCfg> = {\n querySchema: IntersectZod<\n C['querySchema'] extends ZodObject ? C['querySchema'] : undefined,\n C['queryExtensionSchema']\n >\n}\n\nexport type OutputField<C extends MethodCfg> = C['outputSchema'] extends ZodType\n ? {\n outputSchema: ZodObject<{\n out: C['outputSchema']\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n : {\n outputSchema: ZodObject<{\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n\nexport type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {\n __out: infer Out\n}\n ? Out\n : unknown\nexport type RouteSchemaInput<Schema extends RouteSchema> = Schema extends {\n __in?: infer In\n}\n ? In\n : unknown\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return (schema as any as ZodType).parse(data) as RouteSchemaOutput<T>\n}\n\nexport const lowProfileSafeParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): ZodSafeParseResult<RouteSchemaOutput<T>> => {\n return (schema as any as ZodType).safeParse(data) as ZodSafeParseResult<\n RouteSchemaOutput<T>\n >\n}\n\nexport const routeSchemaParse = <T>(\n routeSchema: RouteSchema<T>,\n): ZodType<T> => {\n return routeSchema as any as ZodType<T>\n}\n\n/**\n * Runtime helper that mirrors the typed merge used by the builder.\n * @param a Previously merged params schema inherited from parent segments.\n * @param b Newly introduced params schema.\n * @returns Intersection of schemas when both exist, otherwise whichever is defined.\n */\nexport function mergeSchemas<A extends ZodType, B extends ZodType>(\n a: A,\n b: B,\n): ZodType\nexport function mergeSchemas<A extends ZodType>(a: A, b: undefined): A\nexport function mergeSchemas<B extends ZodType>(a: undefined, b: B): B\nexport function mergeSchemas(\n a: ZodType | undefined,\n b: ZodType | undefined,\n): ZodType | undefined\nexport function mergeSchemas(a: ZodType | undefined, b: ZodType | undefined) {\n if (a && b) {\n if (a === b) return a\n return z.intersection(a as any, b as any)\n }\n return (a ?? b) as ZodType | undefined\n}\n\nexport function getZodShape(schema: ZodObject) {\n const shapeOrGetter = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n if (!shapeOrGetter) return {}\n return typeof shapeOrGetter === 'function'\n ? shapeOrGetter.call(schema)\n : shapeOrGetter\n}\n\nexport function collectNestedFieldSuggestions(\n shape: Record<string, ZodType> | undefined,\n prefix: string[] = [],\n): string[] {\n if (!shape) return []\n const suggestions: string[] = []\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodObject) {\n const nestedShape = getZodShape(value as ZodObject)\n const nestedSuggestions = collectNestedFieldSuggestions(nestedShape, [\n ...prefix,\n key,\n ])\n suggestions.push(\n ...(nestedSuggestions.length\n ? nestedSuggestions\n : [[...prefix, key].join('_')]),\n )\n } else if (prefix.length > 0) {\n suggestions.push([...prefix, key].join('_'))\n }\n }\n return suggestions\n}\n\n// Use the output generic of ZodType instead of z.output<S>\nexport type ToRouteSchema<S> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg = MethodCfg> = Prettify<\n Omit<\n Cfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n > & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\n outputMetaSchema: ToRouteSchema<Cfg['outputMetaSchema']>\n queryExtensionSchema: ToRouteSchema<Cfg['queryExtensionSchema']>\n }\n>\n\n/** Per-method configuration merged with inherited node config. */\nexport type MethodCfg = {\n /** Zod schema describing the request body. */\n bodySchema?: ZodType\n /** Zod schema describing the query string. */\n querySchema?: ZodType\n /** Zod schema describing path params (internal only, set through resource segments). */\n paramsSchema?: ZodType\n /** Zod schema describing the response payload. */\n outputSchema?: ZodType\n /** Multipart upload definitions for the route. */\n bodyFiles?: FileField[]\n /** Marks the route as an infinite feed (enables cursor helpers). */\n feed?: boolean\n /** feed handlers */\n outputMetaSchema?: ZodType\n queryExtensionSchema?: ZodType\n\n /** Optional human-readable description for docs/debugging. */\n description?: string\n /**\n * Short one-line summary for docs list views.\n * Shown in navigation / tables instead of the full description.\n */\n summary?: string\n /**\n * Group name used for navigation sections in docs UIs.\n * e.g. \"Users\", \"Billing\", \"Auth\".\n */\n docsGroup?: string\n /**\n * Tags that can be used to filter / facet in interactive docs.\n * e.g. [\"users\", \"admin\", \"internal\"].\n */\n tags?: string[]\n /**\n * Mark the route as deprecated in docs.\n * Renderers can badge this and/or hide by default.\n */\n deprecated?: boolean\n /**\n * Optional stability information for the route.\n * Renderers can surface this prominently.\n */\n stability?: 'experimental' | 'beta' | 'stable' | 'deprecated'\n /**\n * Hide this route from public docs while keeping it usable in code.\n */\n docsHidden?: boolean\n /**\n * Arbitrary extra metadata for docs renderers.\n * Can be used for auth requirements, rate limits, feature flags, etc.\n */\n docsMeta?: Record<string, unknown>\n}\n\n/** Immutable representation of a single HTTP route in the tree. */\nexport type Leaf<\n M extends HttpMethod,\n P extends string,\n C extends MethodCfg,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n\n/** Convenience union covering all generated leaves. */\nexport type AnyLeaf = Leaf<HttpMethod, string, MethodCfg>\n\n/** Merge two object types while keeping nice IntelliSense output. */\nexport type Merge<A, B> = Prettify<Omit<A, keyof B> & B>\n\n/** Append a new element to a readonly tuple type. */\nexport type Append<T extends readonly unknown[], X> = [...T, X]\n\n/** Concatenate two readonly tuple types. */\nexport type MergeArray<\n A extends readonly unknown[],\n B extends readonly unknown[],\n> = [...A, ...B]\n\ntype TrimTrailingSlash<S extends string> = S extends `${infer R}/`\n ? TrimTrailingSlash<R>\n : S\ntype TrimLeadingSlash<S extends string> = S extends `/${infer R}`\n ? TrimLeadingSlash<R>\n : S\n\ntype NormalizedBase<Base extends string> = TrimTrailingSlash<Base>\ntype NormalizedChild<Child extends string> = TrimLeadingSlash<Child>\n\nexport type JoinPath<Base extends string, Child extends string> =\n NormalizedBase<Base> extends ''\n ? Child\n : NormalizedChild<Child> extends ''\n ? NormalizedBase<Base>\n : `${NormalizedBase<Base>}/${NormalizedChild<Child>}`\nexport type IntersectZod<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n> = B extends ZodType\n ? A extends ZodType\n ? z.ZodIntersection<A, B>\n : B\n : A extends ZodType\n ? A\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> =\n Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ExistingOut & ParentOut>\n : Existing\n : Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ParentOut>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> & {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n }\n>\n\n// Tuple-mapped helper avoids recursive instantiation while re-basing nested leaves.\ntype RebasedLeaf<\n P extends string,\n Param extends ZodType | undefined,\n L extends LeafLowProfile,\n> = LeafLowProfile<\n L['method'],\n JoinPath<P, L['path']>,\n AugmentedCfg<L['cfg'], Param>\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n> = {\n [K in keyof R]: R[K] extends LeafLowProfile\n ? RebasedLeaf<P, Param, R[K]>\n : never\n}\n\ntype NodeQueryExtension<Node> = Node extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\n\ntype NodeOutputMeta<Node> = Node extends { outputMetaSchema?: infer OM }\n ? OM extends ZodType\n ? OM\n : undefined\n : undefined\n\ntype EffectiveQueryExtensionSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeQueryExtension<Node>\n\ntype EffectiveOutputMetaSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeOutputMeta<Node>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\ntype ParamValue<Params, Key extends string> =\n Params extends Record<Key, infer V> ? V : undefined\ntype MapKeySegments<\n Segments extends readonly string[],\n Params,\n> = Segments extends [infer A, ...infer Rest]\n ? A extends string\n ? A extends `:${infer Key}`\n ? [\n [ParamValue<Params, Key>],\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : [\n A,\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : []\n : []\ntype CacheKeyForLeaf<L extends AnyLeafLowProfile> = readonly [\n L['method'],\n ...MapKeySegments<SplitPath<L['path']>, ExtractParamsFromPath<L['path']>>,\n InferQuery<L> extends never ? {} : InferQuery<L>,\n]\nexport function buildCacheKey<L extends AnyLeafLowProfile>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}): CacheKeyForLeaf<L> {\n const segments = args.leaf.path.split('/').filter(Boolean) as SplitPath<\n L['path']\n >\n const keyParts: unknown[] = [args.leaf.method]\n for (const segment of segments) {\n if (segment.startsWith(':')) {\n const paramName = segment.slice(1)\n const value =\n args.params && paramName in args.params\n ? (args.params as Record<string, unknown>)[paramName]\n : undefined\n keyParts.push([value])\n continue\n }\n keyParts.push(segment)\n }\n keyParts.push(args.query ?? {})\n return keyParts as unknown as CacheKeyForLeaf<L>\n}\n\n/** Definition-time method config (for clarity). */\nexport type MethodCfgDef = MethodCfg\n\n/** Low-profile method config where schemas carry a phantom __out like SocketSchema. */\nexport type MethodCfgLowProfile = Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n// keep the overload as you have it\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\n const Node extends NodeCfg | undefined = undefined,\n const O extends ZodType | undefined = undefined,\n const P extends ZodType | undefined = undefined,\n const Q extends ZodType | undefined = undefined,\n const B extends ZodType | undefined = undefined,\n const FO extends ZodType | undefined = undefined,\n const FQ extends ZodType | undefined = undefined,\n const Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n node?: Node\n cfg: Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed: Feed\n bodySchema: RouteSchemaOrUndefined<B>\n querySchema: FeedAwareQueryRoute<Feed, Q, FQ, Node>\n paramsSchema: RouteSchemaOrUndefined<P>\n outputSchema: OutputRouteSchema<O, FO, Node>\n outputMetaSchema: RouteSchemaOrUndefined<\n EffectiveOutputMetaSchema<FO, Node>\n >\n queryExtensionSchema: RouteSchemaOrUndefined<\n EffectiveQueryExtensionSchema<FQ, Node>\n >\n }\n >\n>\n\n// implementation: NO z.infer here\nexport function buildLowProfileLeaf(leaf: any): any {\n const nodeCfg = (leaf.node ?? {}) as NodeCfg\n const mergedCfg = { ...nodeCfg, ...leaf.cfg }\n const effectiveQuerySchema =\n mergedCfg.feed === true\n ? mergeSchemas(mergedCfg.querySchema, mergedCfg.queryExtensionSchema)\n : mergedCfg.querySchema\n const effectiveOutputSchema = mergedCfg.outputSchema\n ? z.object({\n out: mergedCfg.outputSchema,\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n : z.object({\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n\n // ensure query schema is not nested\n if (mergedCfg.feed === true && effectiveQuerySchema instanceof ZodObject) {\n const shape = getZodShape(effectiveQuerySchema as ZodObject)\n const nestedFieldSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedFieldSuggestions.length > 0) {\n console.warn(\n `[routesV3.builder] Warning: feed query schema for ${leaf.method.toUpperCase()} ${leaf.path} contains nested objects. Consider using flat keys instead: ${nestedFieldSuggestions.join(\n ', ',\n )}`,\n )\n }\n }\n return {\n method: leaf.method,\n path: leaf.path,\n cfg: {\n ...mergedCfg,\n bodySchema: mergedCfg.bodySchema as RouteSchema<any> | undefined,\n querySchema: effectiveQuerySchema as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as\n | RouteSchema<any>\n | undefined,\n outputMetaSchema: mergedCfg.outputMetaSchema as\n | RouteSchema<any>\n | undefined,\n queryExtensionSchema: mergedCfg.queryExtensionSchema as\n | RouteSchema<any>\n | undefined,\n },\n }\n}\n\nexport const keyOf = (\n method: HttpMethod,\n path: string,\n encodeSafe?: boolean,\n) => {\n const key = `${method.toUpperCase()} ${path}` as const\n return encodeSafe ? encodeURIComponent(key) : key\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<any, infer PIn>\n ? PIn\n : L['cfg']['paramsSchema'] extends ZodType<any, infer PIn>\n ? PIn\n : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<any, infer QIn>\n ? QIn\n : L['cfg']['querySchema'] extends ZodType<any, infer QIn>\n ? QIn\n : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<any, infer BIn>\n ? BIn\n : L['cfg']['bodySchema'] extends ZodType<any, infer BIn>\n ? BIn\n : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\ntype InferMetaFromCfg<L extends AnyLeafLowProfile> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : string | undefined\n\ntype ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends\n | [never]\n | [unknown]\n ? InferMetaFromCfg<L>\n : M\n\ntype ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {\n meta: infer M\n}\n ? (undefined extends ResolvedMeta<L, M>\n ? { meta?: ResolvedMeta<L, M> }\n : { meta: ResolvedMeta<L, M> }) &\n Omit<O, 'meta'>\n : O\n\nexport type InferOutput<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O>\n ? ApplyMetaFallback<L, O>\n : L['cfg']['outputSchema'] extends ZodType<infer O>\n ? ApplyMetaFallback<L, O>\n : Fallback\n\nexport type InferFeedOutputMeta<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : Fallback\n\nexport type InferFeedQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['queryExtensionSchema'] extends RouteSchema<any, infer QIn>\n ? QIn\n : L['cfg']['queryExtensionSchema'] extends ZodType<any, infer QIn>\n ? QIn\n : Fallback\n\n/** Render a type as if it were a simple object literal. */\nexport type Prettify<T> = { [K in keyof T]: T[K] }\n","import { AnyLeafLowProfile, HttpMethod, Prettify } from './routesV3.core'\n\n/** Build the key type for a leaf — distributive so method/path stay paired. */\nexport type KeyOf<L extends AnyLeafLowProfile> = L extends AnyLeafLowProfile\n ? `${Uppercase<L['method']>} ${L['path']}`\n : never\n\n// From a tuple of leaves, get the union of keys (pairwise, no cartesian blow-up)\ntype KeysOf<Leaves extends readonly AnyLeafLowProfile[]> = KeyOf<Leaves[number]>\n\n// Parse method & path out of a key\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n// Given Leaves and a Key, pick the exact leaf that matches method+path\ntype LeafForKey<\n Leaves extends readonly AnyLeafLowProfile[],\n K extends string,\n> = Extract<\n Leaves[number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\ntype FilterRoute<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? First extends { path: `${string}${F}${string}` }\n ? FilterRoute<Rest, F, [...Acc, First]>\n : FilterRoute<Rest, F, Acc>\n : Acc\n\ntype UpperCase<S extends string> = S extends `${infer First}${infer Rest}`\n ? `${Uppercase<First>}${UpperCase<Rest>}`\n : S\n\ntype Routes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = FilterRoute<T, F>\ntype ByKey<\n T extends readonly AnyLeafLowProfile[],\n Acc extends Record<string, AnyLeafLowProfile> = {},\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? ByKey<\n Rest,\n Acc & { [K in `${UpperCase<First['method']>} ${First['path']}`]: First }\n >\n : Acc\n\n/**\n * Convenience helper for extracting a subset of routes by path fragment.\n * @param T Tuple of leaves produced by the DSL.\n * @param F String fragment to match against the route path.\n */\nexport type SubsetRoutes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = {\n byKey: ByKey<Routes<T, F>>\n all: Routes<T, F>\n}\n\n// In the same module as finalize\n\nexport interface FinalizedRegistry<L extends readonly AnyLeafLowProfile[]> {\n all: L\n byKey: { [K in KeysOf<L>]: Prettify<LeafForKey<L, K>> }\n log(logger: { system: (...args: unknown[]) => void }): void\n}\n\n// Optionally keep this alias if you like the name\nexport type Registry<L extends readonly AnyLeafLowProfile[]> =\n FinalizedRegistry<L>\n\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n): FinalizedRegistry<L> {\n type Keys = KeysOf<L>\n type MapByKey = { [K in Keys]: Prettify<LeafForKey<L, K>> }\n\n const byKey = Object.fromEntries(\n leaves.map((l) => [`${l.method.toUpperCase()} ${l.path}`, l] as const),\n ) as unknown as MapByKey\n\n const log = (logger: { system: (...args: unknown[]) => void }) => {\n logger.system('Finalized routes:')\n ;(Object.keys(byKey) as Keys[]).forEach((k) => {\n const leaf = byKey[k]\n logger.system(`- ${k}`)\n })\n }\n\n return { all: leaves, byKey, log }\n}\n","// socket.index.ts (shared client/server)\n\nimport { z } from 'zod'\n\nexport type SocketSchema<Output = unknown> = z.ZodType & {\n __out: Output\n}\n\nexport type SocketSchemaOutput<Schema extends z.ZodTypeAny> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport type SocketEvent<Out = unknown> = {\n message: z.ZodTypeAny\n /** phantom field, only for typing; not meant to be used at runtime */\n __out: Out\n}\n\nexport type EventMap = Record<string, SocketEvent<any>>\n\n/**\n * System event names – shared so server and client\n * don't drift on naming.\n */\nexport type SysEventName =\n | 'sys:connect'\n | 'sys:disconnect'\n | 'sys:reconnect'\n | 'sys:connect_error'\n | 'sys:ping'\n | 'sys:pong'\n | 'sys:room_join'\n | 'sys:room_leave'\nexport function defineSocketEvents<\n const C extends SocketConnectionConfig,\n const Schemas extends Record<\n string,\n {\n message: z.ZodTypeAny\n }\n >,\n>(\n config: C,\n events: Schemas,\n): {\n config: {\n [K in keyof C]: SocketSchema<z.output<C[K]>>\n }\n events: {\n [K in keyof Schemas]: SocketEvent<z.output<Schemas[K]['message']>>\n }\n}\n\nexport function defineSocketEvents(config: any, events: any) {\n return { config, events }\n}\n\nexport type Payload<T extends EventMap, K extends keyof T> =\n T[K] extends SocketEvent<infer Out> ? Out : never\nexport type SocketConnectionConfig = {\n joinMetaMessage: z.ZodTypeAny\n leaveMetaMessage: z.ZodTypeAny\n pingPayload: z.ZodTypeAny\n pongPayload: z.ZodTypeAny\n}\n\nexport type SocketConnectionConfigOutput = {\n joinMetaMessage: SocketSchema<any>\n leaveMetaMessage: SocketSchema<any>\n pingPayload: SocketSchema<any>\n pongPayload: SocketSchema<any>\n}\n"],"mappings":"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","names":["import_zod"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/routesV3.builder.ts","../src/core/routesV3.core.ts","../src/core/routesV3.finalize.ts","../src/sockets/socket.index.ts"],"sourcesContent":["export * from './core/routesV3.builder'\nexport * from './core/routesV3.core'\nexport * from './core/routesV3.finalize'\nexport * from './sockets/socket.index'\n","import { z, ZodObject, ZodType } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n buildLowProfileLeaf,\n FeedQueryField,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n mergeSchemas,\n MethodCfg,\n NodeCfg,\n OutputField,\n Prettify,\n} from './routesV3.core'\n\ntype ParamZod<Name extends string, S extends ZodType> = ZodObject<{\n [K in Name]: S\n}>\ntype BaseMethodCfg<C extends MethodCfg> = Merge<\n Omit<MethodCfg, 'querySchema' | 'outputSchema' | 'feed'>,\n Omit<C, 'querySchema' | 'outputSchema' | 'feed'>\n>\n\ntype FeedField<C extends MethodCfg> = C['feed'] extends true\n ? { feed: true }\n : { feed?: boolean }\n\ntype NonFeedQueryField<C extends MethodCfg> = C['querySchema'] extends ZodType\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodType\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n : FeedField<C> & NonFeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n\ntype WithNodeDefaults<C extends MethodCfg, I extends NodeCfg> = Merge<\n C,\n {\n queryExtensionSchema: C['queryExtensionSchema'] extends ZodType\n ? C['queryExtensionSchema']\n : NodeQueryExtension<I>\n outputMetaSchema: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : NodeOutputMeta<I>\n }\n>\n\n// Avoids the previous MethodCfg merge step so TS doesn't have to repeatedly\n// expand the entire MethodCfg intersection for every method call.\ntype EffectiveCfgWithDefaults<C extends MethodCfg, PS> = Prettify<\n BaseMethodCfg<C> & EffectiveFeedFields<C, PS>\n>\n\ntype EffectiveCfg<C extends MethodCfg, PS, I extends NodeCfg> =\n WithNodeDefaults<C, I> extends infer WithDefaults extends MethodCfg\n ? EffectiveCfgWithDefaults<WithDefaults, PS>\n : never\n\ntype NodeWithoutSchemas<I extends NodeCfg> = Omit<\n I,\n 'queryExtensionSchema' | 'outputMetaSchema'\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<\n M,\n Base,\n Merge<NodeWithoutSchemas<I>, LowProfileCfg<EffectiveCfg<C, PS, I>>>\n>\n\ntype StripParamName<Name extends string> = Name extends `:${infer P}` ? P : Name\ntype NormalizeBaseLiteral<\n Base extends string,\n HasParam extends boolean,\n> = HasParam extends true\n ? Base extends `:${string}`\n ? Base\n : Base extends ''\n ? ''\n : `:${Base}`\n : Base\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType ? ParamZod<StripParamName<Base>, Param> : undefined\ntype ResourceBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = NormalizeBaseLiteral<Base, Param extends ZodType ? true : false>\ntype NodeQueryExtension<I extends NodeCfg> = I extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\ntype NodeOutputMeta<I extends NodeCfg> = I extends {\n outputMetaSchema?: infer OE\n}\n ? OE extends ZodType\n ? OE\n : undefined\n : undefined\n\ntype SubResourceCollections = readonly [\n ReadonlyArray<AnyLeafLowProfile>,\n ...ReadonlyArray<AnyLeafLowProfile>[],\n]\n\n// Bundling the branch generics keeps MethodFns<State, Used> from re-instantiating\n// four independent parameters for every chained call, which speeds up inference.\ntype BranchState<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n> = {\n base: Base\n leaves: Acc\n node: I\n params: PS\n}\n\ntype AnyBranchState = BranchState<\n string,\n readonly AnyLeafLowProfile[],\n NodeCfg,\n ZodType | undefined\n>\n\nexport type MergeAugmentedCollections<\n Base extends string,\n Param extends ZodType | undefined,\n Collections extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = Collections extends readonly [infer First, ...infer Rest]\n ? First extends ReadonlyArray<AnyLeafLowProfile>\n ? Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? MergeAugmentedCollections<\n Base,\n Param,\n Rest,\n MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n >\n : MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n : MergeAugmentedCollections<\n Base,\n Param,\n Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? Rest\n : [],\n Acc\n >\n : Acc\n\ntype MethodFns<\n State extends AnyBranchState,\n Used extends HttpMethod | 'sub',\n> = {\n /**\n * Register a GET leaf at the current path.\n */\n get: 'get' extends Used\n ? never\n : <C extends MethodCfg>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<'get', State['base'], State['node'], C, State['params']>\n >,\n State['node'],\n State['params'],\n Used | 'get'\n >\n\n /**\n * Register a POST leaf at the current path.\n */\n post: 'post' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'post',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'post'\n >\n\n /**\n * Register a PUT leaf at the current path.\n */\n put: 'put' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'put',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'put'\n >\n\n /**\n * Register a PATCH leaf at the current path.\n */\n patch: 'patch' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'patch',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'patch'\n >\n\n /**\n * Register a DELETE leaf at the current path.\n */\n delete: 'delete' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'delete',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'delete'\n >\n}\n\n/** Builder surface used by `resource(...)` to accumulate leaves. */\nexport interface Branch<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n Used extends HttpMethod | 'sub' = never,\n> extends MethodFns<BranchState<Base, Acc, I, PS>, Used> {\n /**\n * Mount one or more sub-resources that were built via `resource(...)`.\n * Each resource carries its own base path (e.g. `users`, `:userId`, `posts`)\n * so this branch simply prefixes its current `Base` and merges param schemas.\n */\n sub: 'sub' extends Used\n ? never\n : <\n const Collections extends SubResourceCollections,\n NextAcc extends readonly AnyLeafLowProfile[] = MergeArray<\n Acc,\n MergeAugmentedCollections<Base, PS, Collections>\n >,\n >(\n ...collections: Collections\n ) => Branch<Base, NextAcc, I, PS, Used | 'sub'>\n\n /**\n * Finish the branch and return the collected leaves.\n * @returns Readonly tuple of accumulated leaves.\n */\n done(): Readonly<Acc>\n}\n\n/**\n * Start building a resource at the given base path.\n * @param base Root path for the resource (e.g. `/v1`).\n * @param inherited Optional node configuration applied to all descendants.\n * @returns Root `Branch` instance used to compose the route tree.\n */\nexport function resource<\n Base extends string = '',\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base?: Base,\n inherited?: I,\n idSchema?: Param,\n): Branch<\n ResourceBase<Base, Param>,\n readonly [],\n I,\n ParamSchemaForBase<Base, Param>\n> {\n const rawBase = (base ?? '') as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as ResourceBase<Base, Param>\n const rootInherited: I =\n inherited === undefined ? ({} as I) : ({ ...inherited } as I)\n const rootParams = createParamSchema(rawBase, idSchema) as\n | ParamSchemaForBase<Base, Param>\n | undefined\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodType | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeafLowProfile[] = []\n const currentBase: Base2 = base2\n const inheritedCfg: I2 = inherited2\n let currentParamsSchema: PS2 = mergedParamsSchema as PS2\n\n function add<M extends HttpMethod, C extends MethodCfg>(method: M, cfg: C) {\n const effectiveParamsSchema = (cfg.paramsSchema ??\n currentParamsSchema) as PS2 | undefined\n const fullCfg = (\n effectiveParamsSchema\n ? { ...cfg, paramsSchema: effectiveParamsSchema }\n : { ...cfg }\n ) as MethodCfg\n\n const leaf = buildLowProfileLeaf({\n method,\n path: currentBase as Base2,\n node: inheritedCfg,\n cfg: fullCfg,\n })\n\n stack.push(leaf as AnyLeafLowProfile)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount one or more subtrees built elsewhere.\n * Usage:\n * resource('/api').sub(\n * resource('users').get(...).done(),\n * resource('projects').get(...).done()\n * )\n */\n sub(...collections: readonly AnyLeafLowProfile[][]) {\n if (collections.length === 0) {\n throw new Error('sub() expects at least one resource')\n }\n\n for (const leaves of collections) {\n for (const leafLow of leaves) {\n const leaf = leafLow as unknown as AnyLeaf\n const leafCfg = leaf.cfg as MethodCfg\n const leafParams = leafCfg.paramsSchema as ZodType | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...inheritedCfg,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: joinPaths(currentBase, leaf.path),\n cfg: newCfg,\n }\n\n stack.push(newLeaf as AnyLeafLowProfile)\n }\n }\n\n return api\n },\n\n // methods (inject current params schema if missing)\n get<C extends MethodCfg>(cfg: C) {\n return add('get', cfg)\n },\n post<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('post', { ...cfg, feed: false })\n },\n put<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('put', { ...cfg, feed: false })\n },\n patch<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('patch', { ...cfg, feed: false })\n },\n delete<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('delete', { ...cfg, feed: false })\n },\n\n done() {\n return stack as readonly AnyLeafLowProfile[]\n },\n }\n\n return api as Branch<Base2, readonly [], I2, PS2>\n }\n\n // Root branch starts with no params schema (PS = undefined)\n return makeBranch(normalizedBase, rootInherited, rootParams)\n}\n\n/**\n * Merge two readonly tuples (preserves literal tuple information).\n * @param arr1 First tuple.\n * @param arr2 Second tuple.\n * @returns New tuple containing values from both inputs.\n */\nexport const mergeArrays = <T extends readonly any[], S extends readonly any[]>(\n arr1: T,\n arr2: S,\n) => {\n return [...arr1, ...arr2] as [...T, ...S]\n}\n\nfunction normalizeBaseSegment(base: string, hasParam: boolean) {\n const value = base ?? ''\n if (!hasParam) return value\n if (!value) {\n throw new Error(\n 'resource() requires a segment name when defining an id schema',\n )\n }\n if (value.includes('/')) {\n const segments = value.split('/').filter(Boolean)\n if (segments.length === 0) {\n throw new Error(\n 'resource() received an invalid segment for param injection',\n )\n }\n const lastIndex = segments.length - 1\n const last = segments[lastIndex]\n segments[lastIndex] = last.startsWith(':') ? last : `:${last}`\n return `${value.startsWith('/') ? '/' : ''}${segments.join('/')}`\n }\n return value.startsWith(':') ? value : `:${value}`\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const segments = nameSegment.split('/').filter(Boolean)\n const rawName =\n segments.length > 0 ? segments[segments.length - 1] : nameSegment\n const normalized = rawName.startsWith(':') ? rawName.slice(1) : rawName\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n return z.object({ [normalized]: schema } as Record<string, ZodType>)\n}\n\nfunction joinPaths(parent: string, child: string) {\n if (!parent) return child\n if (!child) return parent\n const trimmedParent = parent.endsWith('/')\n ? parent.replace(/\\/+$/, '')\n : parent\n const trimmedChild = child.startsWith('/') ? child.replace(/^\\/+/, '') : child\n if (!trimmedChild) return trimmedParent\n return `${trimmedParent}/${trimmedChild}`\n}\n","import { z, ZodObject, ZodSafeParseResult, ZodType } from 'zod'\n\n/** Supported HTTP verbs for the routes DSL. */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** Declarative description of a multipart upload field. */\nexport type FileField = {\n /** Form field name used for uploads. */\n name: string\n /** Maximum number of files accepted for this field. */\n maxCount: number\n}\n\n/** Configuration that applies to an entire branch of the route tree. */\nexport interface NodeCfg {\n /**\n * Feed-specific query schema applied to all descendants unless they override it.\n */\n queryExtensionSchema?: ZodType\n /**\n * Feed meta schema applied to all descendants unless they override it.\n */\n outputMetaSchema?: ZodType\n}\n\nexport type RouteSchema<Output = unknown, Input = Output> = {\n __out: Output\n __in?: Input\n}\n\ntype RouteSchemaOrUndefined<S extends ZodType | undefined> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : undefined\n\ntype FeedAwareQueryRoute<\n Feed extends boolean,\n Query extends ZodType | undefined,\n Extension extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Feed extends true\n ? ToRouteSchema<\n FeedQueryField<{\n querySchema: Query\n queryExtensionSchema: EffectiveQueryExtensionSchema<Extension, Node>\n }>['querySchema']\n >\n : RouteSchemaOrUndefined<Query>\n\ntype OutputRouteSchema<\n O extends ZodType | undefined,\n Meta extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = ToRouteSchema<\n OutputField<{\n outputSchema: O\n outputMetaSchema: EffectiveOutputMetaSchema<Meta, Node>\n }>['outputSchema']\n>\n\nexport type FeedQueryField<C extends MethodCfg> = {\n querySchema: IntersectZod<\n C['querySchema'] extends ZodObject ? C['querySchema'] : undefined,\n C['queryExtensionSchema']\n >\n}\n\nexport type OutputField<C extends MethodCfg> = C['outputSchema'] extends ZodType\n ? {\n outputSchema: ZodObject<{\n out: C['outputSchema']\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n : {\n outputSchema: ZodObject<{\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n\nexport type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {\n __out: infer Out\n}\n ? Out\n : unknown\nexport type RouteSchemaInput<Schema extends RouteSchema> = Schema extends {\n __in?: infer In\n}\n ? In\n : unknown\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return (schema as any as ZodType).parse(data) as RouteSchemaOutput<T>\n}\n\nexport const lowProfileSafeParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): ZodSafeParseResult<RouteSchemaOutput<T>> => {\n return (schema as any as ZodType).safeParse(data) as ZodSafeParseResult<\n RouteSchemaOutput<T>\n >\n}\n\nexport const routeSchemaParse = <T>(\n routeSchema: RouteSchema<T>,\n): ZodType<T> => {\n return routeSchema as any as ZodType<T>\n}\n\n/**\n * Runtime helper that mirrors the typed merge used by the builder.\n * @param a Previously merged params schema inherited from parent segments.\n * @param b Newly introduced params schema.\n * @returns Intersection of schemas when both exist, otherwise whichever is defined.\n */\nexport function mergeSchemas<A extends ZodType, B extends ZodType>(\n a: A,\n b: B,\n): ZodType\nexport function mergeSchemas<A extends ZodType>(a: A, b: undefined): A\nexport function mergeSchemas<B extends ZodType>(a: undefined, b: B): B\nexport function mergeSchemas(\n a: ZodType | undefined,\n b: ZodType | undefined,\n): ZodType | undefined\nexport function mergeSchemas(a: ZodType | undefined, b: ZodType | undefined) {\n if (a && b) {\n if (a === b) return a\n return z.intersection(a as any, b as any)\n }\n return (a ?? b) as ZodType | undefined\n}\n\nexport function getZodShape(schema: ZodObject) {\n const shapeOrGetter = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n if (!shapeOrGetter) return {}\n return typeof shapeOrGetter === 'function'\n ? shapeOrGetter.call(schema)\n : shapeOrGetter\n}\n\nexport function collectNestedFieldSuggestions(\n shape: Record<string, ZodType> | undefined,\n prefix: string[] = [],\n): string[] {\n if (!shape) return []\n const suggestions: string[] = []\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodObject) {\n const nestedShape = getZodShape(value as ZodObject)\n const nestedSuggestions = collectNestedFieldSuggestions(nestedShape, [\n ...prefix,\n key,\n ])\n suggestions.push(\n ...(nestedSuggestions.length\n ? nestedSuggestions\n : [[...prefix, key].join('_')]),\n )\n } else if (prefix.length > 0) {\n suggestions.push([...prefix, key].join('_'))\n }\n }\n return suggestions\n}\n\n// Use the output generic of ZodType instead of z.output<S>\nexport type ToRouteSchema<S> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg = MethodCfg> = Prettify<\n Omit<\n Cfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n > & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\n outputMetaSchema: ToRouteSchema<Cfg['outputMetaSchema']>\n queryExtensionSchema: ToRouteSchema<Cfg['queryExtensionSchema']>\n }\n>\n\n/** Per-method configuration merged with inherited node config. */\nexport type MethodCfg = {\n /** Zod schema describing the request body. */\n bodySchema?: ZodType\n /** Zod schema describing the query string. */\n querySchema?: ZodType\n /** Zod schema describing path params (internal only, set through resource segments). */\n paramsSchema?: ZodType\n /** Zod schema describing the response payload. */\n outputSchema?: ZodType\n /** Multipart upload definitions for the route. */\n bodyFiles?: FileField[]\n /** Marks the route as an infinite feed (enables cursor helpers). */\n feed?: boolean\n /** feed handlers */\n outputMetaSchema?: ZodType\n queryExtensionSchema?: ZodType\n\n /** Optional human-readable description for docs/debugging. */\n description?: string\n /**\n * Short one-line summary for docs list views.\n * Shown in navigation / tables instead of the full description.\n */\n summary?: string\n /**\n * Group name used for navigation sections in docs UIs.\n * e.g. \"Users\", \"Billing\", \"Auth\".\n */\n docsGroup?: string\n /**\n * Tags that can be used to filter / facet in interactive docs.\n * e.g. [\"users\", \"admin\", \"internal\"].\n */\n tags?: string[]\n /**\n * Mark the route as deprecated in docs.\n * Renderers can badge this and/or hide by default.\n */\n deprecated?: boolean\n /**\n * Optional stability information for the route.\n * Renderers can surface this prominently.\n */\n stability?: 'experimental' | 'beta' | 'stable' | 'deprecated'\n /**\n * Hide this route from public docs while keeping it usable in code.\n */\n docsHidden?: boolean\n /**\n * Arbitrary extra metadata for docs renderers.\n * Can be used for auth requirements, rate limits, feature flags, etc.\n */\n docsMeta?: Record<string, unknown>\n}\n\n/** Immutable representation of a single HTTP route in the tree. */\nexport type Leaf<\n M extends HttpMethod,\n P extends string,\n C extends MethodCfg,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n\n/** Convenience union covering all generated leaves. */\nexport type AnyLeaf = Leaf<HttpMethod, string, MethodCfg>\n\n/** Merge two object types while keeping nice IntelliSense output. */\nexport type Merge<A, B> = Prettify<Omit<A, keyof B> & B>\n\n/** Append a new element to a readonly tuple type. */\nexport type Append<T extends readonly unknown[], X> = [...T, X]\n\n/** Concatenate two readonly tuple types. */\nexport type MergeArray<\n A extends readonly unknown[],\n B extends readonly unknown[],\n> = [...A, ...B]\n\ntype TrimTrailingSlash<S extends string> = S extends `${infer R}/`\n ? TrimTrailingSlash<R>\n : S\ntype TrimLeadingSlash<S extends string> = S extends `/${infer R}`\n ? TrimLeadingSlash<R>\n : S\n\ntype NormalizedBase<Base extends string> = TrimTrailingSlash<Base>\ntype NormalizedChild<Child extends string> = TrimLeadingSlash<Child>\n\nexport type JoinPath<Base extends string, Child extends string> =\n NormalizedBase<Base> extends ''\n ? Child\n : NormalizedChild<Child> extends ''\n ? NormalizedBase<Base>\n : `${NormalizedBase<Base>}/${NormalizedChild<Child>}`\nexport type IntersectZod<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n> = B extends ZodType\n ? A extends ZodType\n ? z.ZodIntersection<A, B>\n : B\n : A extends ZodType\n ? A\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> =\n Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ExistingOut & ParentOut>\n : Existing\n : Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ParentOut>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> & {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n }\n>\n\n// Tuple-mapped helper avoids recursive instantiation while re-basing nested leaves.\ntype RebasedLeaf<\n P extends string,\n Param extends ZodType | undefined,\n L extends LeafLowProfile,\n> = LeafLowProfile<\n L['method'],\n JoinPath<P, L['path']>,\n AugmentedCfg<L['cfg'], Param>\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n> = {\n [K in keyof R]: R[K] extends LeafLowProfile\n ? RebasedLeaf<P, Param, R[K]>\n : never\n}\n\ntype NodeQueryExtension<Node> = Node extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\n\ntype NodeOutputMeta<Node> = Node extends { outputMetaSchema?: infer OM }\n ? OM extends ZodType\n ? OM\n : undefined\n : undefined\n\ntype EffectiveQueryExtensionSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeQueryExtension<Node>\n\ntype EffectiveOutputMetaSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeOutputMeta<Node>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\ntype ParamValue<Params, Key extends string> =\n Params extends Record<Key, infer V> ? V : undefined\ntype MapKeySegments<\n Segments extends readonly string[],\n Params,\n> = Segments extends [infer A, ...infer Rest]\n ? A extends string\n ? A extends `:${infer Key}`\n ? [\n [ParamValue<Params, Key>],\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : [\n A,\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : []\n : []\ntype CacheKeyForLeaf<L extends AnyLeafLowProfile> = readonly [\n L['method'],\n ...MapKeySegments<SplitPath<L['path']>, ExtractParamsFromPath<L['path']>>,\n InferQuery<L> extends never ? {} : InferQuery<L>,\n]\nexport function buildCacheKey<L extends AnyLeafLowProfile>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}): CacheKeyForLeaf<L> {\n const segments = args.leaf.path.split('/').filter(Boolean) as SplitPath<\n L['path']\n >\n const keyParts: unknown[] = [args.leaf.method]\n for (const segment of segments) {\n if (segment.startsWith(':')) {\n const paramName = segment.slice(1)\n const value =\n args.params && paramName in args.params\n ? (args.params as Record<string, unknown>)[paramName]\n : undefined\n keyParts.push([value])\n continue\n }\n keyParts.push(segment)\n }\n keyParts.push(args.query ?? {})\n return keyParts as unknown as CacheKeyForLeaf<L>\n}\n\n/** Definition-time method config (for clarity). */\nexport type MethodCfgDef = MethodCfg\n\n/** Low-profile method config where schemas carry a phantom __out like SocketSchema. */\nexport type MethodCfgLowProfile = Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n// keep the overload as you have it\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\n const Node extends NodeCfg | undefined = undefined,\n const O extends ZodType | undefined = undefined,\n const P extends ZodType | undefined = undefined,\n const Q extends ZodType | undefined = undefined,\n const B extends ZodType | undefined = undefined,\n const FO extends ZodType | undefined = undefined,\n const FQ extends ZodType | undefined = undefined,\n const Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n node?: Node\n cfg: Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed: Feed\n bodySchema: RouteSchemaOrUndefined<B>\n querySchema: FeedAwareQueryRoute<Feed, Q, FQ, Node>\n paramsSchema: RouteSchemaOrUndefined<P>\n outputSchema: OutputRouteSchema<O, FO, Node>\n outputMetaSchema: RouteSchemaOrUndefined<\n EffectiveOutputMetaSchema<FO, Node>\n >\n queryExtensionSchema: RouteSchemaOrUndefined<\n EffectiveQueryExtensionSchema<FQ, Node>\n >\n }\n >\n>\n\n// implementation: NO z.infer here\nexport function buildLowProfileLeaf(leaf: any): any {\n const nodeCfg = (leaf.node ?? {}) as NodeCfg\n const mergedCfg = { ...nodeCfg, ...leaf.cfg }\n const effectiveQuerySchema =\n mergedCfg.feed === true\n ? mergeSchemas(mergedCfg.querySchema, mergedCfg.queryExtensionSchema)\n : mergedCfg.querySchema\n const effectiveOutputSchema = mergedCfg.outputSchema\n ? z.object({\n out: mergedCfg.outputSchema,\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n : z.object({\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n\n // ensure query schema is not nested\n if (mergedCfg.feed === true && effectiveQuerySchema instanceof ZodObject) {\n const shape = getZodShape(effectiveQuerySchema as ZodObject)\n const nestedFieldSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedFieldSuggestions.length > 0) {\n console.warn(\n `[routesV3.builder] Warning: feed query schema for ${leaf.method.toUpperCase()} ${leaf.path} contains nested objects. Consider using flat keys instead: ${nestedFieldSuggestions.join(\n ', ',\n )}`,\n )\n }\n }\n return {\n method: leaf.method,\n path: leaf.path,\n cfg: {\n ...mergedCfg,\n bodySchema: mergedCfg.bodySchema as RouteSchema<any> | undefined,\n querySchema: effectiveQuerySchema as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as\n | RouteSchema<any>\n | undefined,\n outputMetaSchema: mergedCfg.outputMetaSchema as\n | RouteSchema<any>\n | undefined,\n queryExtensionSchema: mergedCfg.queryExtensionSchema as\n | RouteSchema<any>\n | undefined,\n },\n }\n}\n\nexport const keyOf = (\n method: HttpMethod,\n path: string,\n encodeSafe?: boolean,\n) => {\n const key = `${method.toUpperCase()} ${path}` as const\n return encodeSafe ? encodeURIComponent(key) : key\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer POut>\n ? POut\n : L['cfg']['paramsSchema'] extends ZodType<infer POut>\n ? POut\n : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer QOut>\n ? QOut\n : L['cfg']['querySchema'] extends ZodType<infer QOut>\n ? QOut\n : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer BOut>\n ? BOut\n : L['cfg']['bodySchema'] extends ZodType<infer BOut>\n ? BOut\n : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\ntype InferMetaFromCfg<L extends AnyLeafLowProfile> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : string | undefined\n\ntype ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends\n | [never]\n | [unknown]\n ? InferMetaFromCfg<L>\n : M\n\ntype ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {\n meta: infer M\n}\n ? (undefined extends ResolvedMeta<L, M>\n ? { meta?: ResolvedMeta<L, M> }\n : { meta: ResolvedMeta<L, M> }) &\n Omit<O, 'meta'>\n : O\n\nexport type InferOutput<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O>\n ? ApplyMetaFallback<L, O>\n : L['cfg']['outputSchema'] extends ZodType<infer O>\n ? ApplyMetaFallback<L, O>\n : Fallback\n\n/** Render a type as if it were a simple object literal. */\nexport type Prettify<T> = { [K in keyof T]: T[K] }\n","import { AnyLeafLowProfile, HttpMethod, Prettify } from './routesV3.core'\n\n/** Build the key type for a leaf — distributive so method/path stay paired. */\nexport type KeyOf<L extends AnyLeafLowProfile> = L extends AnyLeafLowProfile\n ? `${Uppercase<L['method']>} ${L['path']}`\n : never\n\n// From a tuple of leaves, get the union of keys (pairwise, no cartesian blow-up)\ntype KeysOf<Leaves extends readonly AnyLeafLowProfile[]> = KeyOf<Leaves[number]>\n\n// Parse method & path out of a key\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n// Given Leaves and a Key, pick the exact leaf that matches method+path\ntype LeafForKey<\n Leaves extends readonly AnyLeafLowProfile[],\n K extends string,\n> = Extract<\n Leaves[number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\ntype FilterRoute<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? First extends { path: `${string}${F}${string}` }\n ? FilterRoute<Rest, F, [...Acc, First]>\n : FilterRoute<Rest, F, Acc>\n : Acc\n\ntype UpperCase<S extends string> = S extends `${infer First}${infer Rest}`\n ? `${Uppercase<First>}${UpperCase<Rest>}`\n : S\n\ntype Routes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = FilterRoute<T, F>\ntype ByKey<\n T extends readonly AnyLeafLowProfile[],\n Acc extends Record<string, AnyLeafLowProfile> = {},\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? ByKey<\n Rest,\n Acc & { [K in `${UpperCase<First['method']>} ${First['path']}`]: First }\n >\n : Acc\n\n/**\n * Convenience helper for extracting a subset of routes by path fragment.\n * @param T Tuple of leaves produced by the DSL.\n * @param F String fragment to match against the route path.\n */\nexport type SubsetRoutes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = {\n byKey: ByKey<Routes<T, F>>\n all: Routes<T, F>\n}\n\n// In the same module as finalize\n\nexport interface FinalizedRegistry<L extends readonly AnyLeafLowProfile[]> {\n all: L\n byKey: { [K in KeysOf<L>]: Prettify<LeafForKey<L, K>> }\n log(logger: { system: (...args: unknown[]) => void }): void\n}\n\n// Optionally keep this alias if you like the name\nexport type Registry<L extends readonly AnyLeafLowProfile[]> =\n FinalizedRegistry<L>\n\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n): FinalizedRegistry<L> {\n type Keys = KeysOf<L>\n type MapByKey = { [K in Keys]: Prettify<LeafForKey<L, K>> }\n\n const byKey = Object.fromEntries(\n leaves.map((l) => [`${l.method.toUpperCase()} ${l.path}`, l] as const),\n ) as unknown as MapByKey\n\n const log = (logger: { system: (...args: unknown[]) => void }) => {\n logger.system('Finalized routes:')\n ;(Object.keys(byKey) as Keys[]).forEach((k) => {\n const leaf = byKey[k]\n logger.system(`- ${k}`)\n })\n }\n\n return { all: leaves, byKey, log }\n}\n","// socket.index.ts (shared client/server)\n\nimport { z } from 'zod'\n\nexport type SocketSchema<Output = unknown> = z.ZodType & {\n __out: Output\n}\n\nexport type SocketSchemaOutput<Schema extends z.ZodTypeAny> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport type SocketEvent<Out = unknown> = {\n message: z.ZodTypeAny\n /** phantom field, only for typing; not meant to be used at runtime */\n __out: Out\n}\n\nexport type EventMap = Record<string, SocketEvent<any>>\n\n/**\n * System event names – shared so server and client\n * don't drift on naming.\n */\nexport type SysEventName =\n | 'sys:connect'\n | 'sys:disconnect'\n | 'sys:reconnect'\n | 'sys:connect_error'\n | 'sys:ping'\n | 'sys:pong'\n | 'sys:room_join'\n | 'sys:room_leave'\nexport function defineSocketEvents<\n const C extends SocketConnectionConfig,\n const Schemas extends Record<\n string,\n {\n message: z.ZodTypeAny\n }\n >,\n>(\n config: C,\n events: Schemas,\n): {\n config: {\n [K in keyof C]: SocketSchema<z.output<C[K]>>\n }\n events: {\n [K in keyof Schemas]: SocketEvent<z.output<Schemas[K]['message']>>\n }\n}\n\nexport function defineSocketEvents(config: any, events: any) {\n return { config, events }\n}\n\nexport type Payload<T extends EventMap, K extends keyof T> =\n T[K] extends SocketEvent<infer Out> ? Out : never\nexport type SocketConnectionConfig = {\n joinMetaMessage: z.ZodTypeAny\n leaveMetaMessage: z.ZodTypeAny\n pingPayload: z.ZodTypeAny\n pongPayload: z.ZodTypeAny\n}\n\nexport type SocketConnectionConfigOutput = {\n joinMetaMessage: SocketSchema<any>\n leaveMetaMessage: SocketSchema<any>\n pingPayload: SocketSchema<any>\n pongPayload: SocketSchema<any>\n}\n"],"mappings":"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","names":["import_zod"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/routesV3.builder.ts","../src/core/routesV3.core.ts","../src/core/routesV3.finalize.ts","../src/sockets/socket.index.ts"],"sourcesContent":["import { z, ZodObject, ZodType } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n buildLowProfileLeaf,\n FeedQueryField,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n mergeSchemas,\n MethodCfg,\n NodeCfg,\n OutputField,\n Prettify,\n} from './routesV3.core'\n\ntype ParamZod<Name extends string, S extends ZodType> = ZodObject<{\n [K in Name]: S\n}>\ntype BaseMethodCfg<C extends MethodCfg> = Merge<\n Omit<MethodCfg, 'querySchema' | 'outputSchema' | 'feed'>,\n Omit<C, 'querySchema' | 'outputSchema' | 'feed'>\n>\n\ntype FeedField<C extends MethodCfg> = C['feed'] extends true\n ? { feed: true }\n : { feed?: boolean }\n\ntype NonFeedQueryField<C extends MethodCfg> = C['querySchema'] extends ZodType\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodType\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n : FeedField<C> & NonFeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n\ntype WithNodeDefaults<C extends MethodCfg, I extends NodeCfg> = Merge<\n C,\n {\n queryExtensionSchema: C['queryExtensionSchema'] extends ZodType\n ? C['queryExtensionSchema']\n : NodeQueryExtension<I>\n outputMetaSchema: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : NodeOutputMeta<I>\n }\n>\n\n// Avoids the previous MethodCfg merge step so TS doesn't have to repeatedly\n// expand the entire MethodCfg intersection for every method call.\ntype EffectiveCfgWithDefaults<C extends MethodCfg, PS> = Prettify<\n BaseMethodCfg<C> & EffectiveFeedFields<C, PS>\n>\n\ntype EffectiveCfg<C extends MethodCfg, PS, I extends NodeCfg> =\n WithNodeDefaults<C, I> extends infer WithDefaults extends MethodCfg\n ? EffectiveCfgWithDefaults<WithDefaults, PS>\n : never\n\ntype NodeWithoutSchemas<I extends NodeCfg> = Omit<\n I,\n 'queryExtensionSchema' | 'outputMetaSchema'\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<\n M,\n Base,\n Merge<NodeWithoutSchemas<I>, LowProfileCfg<EffectiveCfg<C, PS, I>>>\n>\n\ntype StripParamName<Name extends string> = Name extends `:${infer P}` ? P : Name\ntype NormalizeBaseLiteral<\n Base extends string,\n HasParam extends boolean,\n> = HasParam extends true\n ? Base extends `:${string}`\n ? Base\n : Base extends ''\n ? ''\n : `:${Base}`\n : Base\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType ? ParamZod<StripParamName<Base>, Param> : undefined\ntype ResourceBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = NormalizeBaseLiteral<Base, Param extends ZodType ? true : false>\ntype NodeQueryExtension<I extends NodeCfg> = I extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\ntype NodeOutputMeta<I extends NodeCfg> = I extends {\n outputMetaSchema?: infer OE\n}\n ? OE extends ZodType\n ? OE\n : undefined\n : undefined\n\ntype SubResourceCollections = readonly [\n ReadonlyArray<AnyLeafLowProfile>,\n ...ReadonlyArray<AnyLeafLowProfile>[],\n]\n\n// Bundling the branch generics keeps MethodFns<State, Used> from re-instantiating\n// four independent parameters for every chained call, which speeds up inference.\ntype BranchState<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n> = {\n base: Base\n leaves: Acc\n node: I\n params: PS\n}\n\ntype AnyBranchState = BranchState<\n string,\n readonly AnyLeafLowProfile[],\n NodeCfg,\n ZodType | undefined\n>\n\nexport type MergeAugmentedCollections<\n Base extends string,\n Param extends ZodType | undefined,\n Collections extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = Collections extends readonly [infer First, ...infer Rest]\n ? First extends ReadonlyArray<AnyLeafLowProfile>\n ? Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? MergeAugmentedCollections<\n Base,\n Param,\n Rest,\n MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n >\n : MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n : MergeAugmentedCollections<\n Base,\n Param,\n Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? Rest\n : [],\n Acc\n >\n : Acc\n\ntype MethodFns<\n State extends AnyBranchState,\n Used extends HttpMethod | 'sub',\n> = {\n /**\n * Register a GET leaf at the current path.\n */\n get: 'get' extends Used\n ? never\n : <C extends MethodCfg>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<'get', State['base'], State['node'], C, State['params']>\n >,\n State['node'],\n State['params'],\n Used | 'get'\n >\n\n /**\n * Register a POST leaf at the current path.\n */\n post: 'post' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'post',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'post'\n >\n\n /**\n * Register a PUT leaf at the current path.\n */\n put: 'put' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'put',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'put'\n >\n\n /**\n * Register a PATCH leaf at the current path.\n */\n patch: 'patch' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'patch',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'patch'\n >\n\n /**\n * Register a DELETE leaf at the current path.\n */\n delete: 'delete' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'delete',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'delete'\n >\n}\n\n/** Builder surface used by `resource(...)` to accumulate leaves. */\nexport interface Branch<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n Used extends HttpMethod | 'sub' = never,\n> extends MethodFns<BranchState<Base, Acc, I, PS>, Used> {\n /**\n * Mount one or more sub-resources that were built via `resource(...)`.\n * Each resource carries its own base path (e.g. `users`, `:userId`, `posts`)\n * so this branch simply prefixes its current `Base` and merges param schemas.\n */\n sub: 'sub' extends Used\n ? never\n : <\n const Collections extends SubResourceCollections,\n NextAcc extends readonly AnyLeafLowProfile[] = MergeArray<\n Acc,\n MergeAugmentedCollections<Base, PS, Collections>\n >,\n >(\n ...collections: Collections\n ) => Branch<Base, NextAcc, I, PS, Used | 'sub'>\n\n /**\n * Finish the branch and return the collected leaves.\n * @returns Readonly tuple of accumulated leaves.\n */\n done(): Readonly<Acc>\n}\n\n/**\n * Start building a resource at the given base path.\n * @param base Root path for the resource (e.g. `/v1`).\n * @param inherited Optional node configuration applied to all descendants.\n * @returns Root `Branch` instance used to compose the route tree.\n */\nexport function resource<\n Base extends string = '',\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base?: Base,\n inherited?: I,\n idSchema?: Param,\n): Branch<\n ResourceBase<Base, Param>,\n readonly [],\n I,\n ParamSchemaForBase<Base, Param>\n> {\n const rawBase = (base ?? '') as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as ResourceBase<Base, Param>\n const rootInherited: I =\n inherited === undefined ? ({} as I) : ({ ...inherited } as I)\n const rootParams = createParamSchema(rawBase, idSchema) as\n | ParamSchemaForBase<Base, Param>\n | undefined\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodType | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeafLowProfile[] = []\n const currentBase: Base2 = base2\n const inheritedCfg: I2 = inherited2\n let currentParamsSchema: PS2 = mergedParamsSchema as PS2\n\n function add<M extends HttpMethod, C extends MethodCfg>(method: M, cfg: C) {\n const effectiveParamsSchema = (cfg.paramsSchema ??\n currentParamsSchema) as PS2 | undefined\n const fullCfg = (\n effectiveParamsSchema\n ? { ...cfg, paramsSchema: effectiveParamsSchema }\n : { ...cfg }\n ) as MethodCfg\n\n const leaf = buildLowProfileLeaf({\n method,\n path: currentBase as Base2,\n node: inheritedCfg,\n cfg: fullCfg,\n })\n\n stack.push(leaf as AnyLeafLowProfile)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount one or more subtrees built elsewhere.\n * Usage:\n * resource('/api').sub(\n * resource('users').get(...).done(),\n * resource('projects').get(...).done()\n * )\n */\n sub(...collections: readonly AnyLeafLowProfile[][]) {\n if (collections.length === 0) {\n throw new Error('sub() expects at least one resource')\n }\n\n for (const leaves of collections) {\n for (const leafLow of leaves) {\n const leaf = leafLow as unknown as AnyLeaf\n const leafCfg = leaf.cfg as MethodCfg\n const leafParams = leafCfg.paramsSchema as ZodType | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...inheritedCfg,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: joinPaths(currentBase, leaf.path),\n cfg: newCfg,\n }\n\n stack.push(newLeaf as AnyLeafLowProfile)\n }\n }\n\n return api\n },\n\n // methods (inject current params schema if missing)\n get<C extends MethodCfg>(cfg: C) {\n return add('get', cfg)\n },\n post<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('post', { ...cfg, feed: false })\n },\n put<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('put', { ...cfg, feed: false })\n },\n patch<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('patch', { ...cfg, feed: false })\n },\n delete<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('delete', { ...cfg, feed: false })\n },\n\n done() {\n return stack as readonly AnyLeafLowProfile[]\n },\n }\n\n return api as Branch<Base2, readonly [], I2, PS2>\n }\n\n // Root branch starts with no params schema (PS = undefined)\n return makeBranch(normalizedBase, rootInherited, rootParams)\n}\n\n/**\n * Merge two readonly tuples (preserves literal tuple information).\n * @param arr1 First tuple.\n * @param arr2 Second tuple.\n * @returns New tuple containing values from both inputs.\n */\nexport const mergeArrays = <T extends readonly any[], S extends readonly any[]>(\n arr1: T,\n arr2: S,\n) => {\n return [...arr1, ...arr2] as [...T, ...S]\n}\n\nfunction normalizeBaseSegment(base: string, hasParam: boolean) {\n const value = base ?? ''\n if (!hasParam) return value\n if (!value) {\n throw new Error(\n 'resource() requires a segment name when defining an id schema',\n )\n }\n if (value.includes('/')) {\n const segments = value.split('/').filter(Boolean)\n if (segments.length === 0) {\n throw new Error(\n 'resource() received an invalid segment for param injection',\n )\n }\n const lastIndex = segments.length - 1\n const last = segments[lastIndex]\n segments[lastIndex] = last.startsWith(':') ? last : `:${last}`\n return `${value.startsWith('/') ? '/' : ''}${segments.join('/')}`\n }\n return value.startsWith(':') ? value : `:${value}`\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const segments = nameSegment.split('/').filter(Boolean)\n const rawName =\n segments.length > 0 ? segments[segments.length - 1] : nameSegment\n const normalized = rawName.startsWith(':') ? rawName.slice(1) : rawName\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n return z.object({ [normalized]: schema } as Record<string, ZodType>)\n}\n\nfunction joinPaths(parent: string, child: string) {\n if (!parent) return child\n if (!child) return parent\n const trimmedParent = parent.endsWith('/')\n ? parent.replace(/\\/+$/, '')\n : parent\n const trimmedChild = child.startsWith('/') ? child.replace(/^\\/+/, '') : child\n if (!trimmedChild) return trimmedParent\n return `${trimmedParent}/${trimmedChild}`\n}\n","import { z, ZodObject, ZodSafeParseResult, ZodType } from 'zod'\n\n/** Supported HTTP verbs for the routes DSL. */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** Declarative description of a multipart upload field. */\nexport type FileField = {\n /** Form field name used for uploads. */\n name: string\n /** Maximum number of files accepted for this field. */\n maxCount: number\n}\n\n/** Configuration that applies to an entire branch of the route tree. */\nexport interface NodeCfg {\n /**\n * Feed-specific query schema applied to all descendants unless they override it.\n */\n queryExtensionSchema?: ZodType\n /**\n * Feed meta schema applied to all descendants unless they override it.\n */\n outputMetaSchema?: ZodType\n}\n\nexport type RouteSchema<Output = unknown, Input = Output> = {\n __out: Output\n __in?: Input\n}\n\ntype RouteSchemaOrUndefined<S extends ZodType | undefined> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : undefined\n\ntype FeedAwareQueryRoute<\n Feed extends boolean,\n Query extends ZodType | undefined,\n Extension extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Feed extends true\n ? ToRouteSchema<\n FeedQueryField<{\n querySchema: Query\n queryExtensionSchema: EffectiveQueryExtensionSchema<Extension, Node>\n }>['querySchema']\n >\n : RouteSchemaOrUndefined<Query>\n\ntype OutputRouteSchema<\n O extends ZodType | undefined,\n Meta extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = ToRouteSchema<\n OutputField<{\n outputSchema: O\n outputMetaSchema: EffectiveOutputMetaSchema<Meta, Node>\n }>['outputSchema']\n>\n\nexport type FeedQueryField<C extends MethodCfg> = {\n querySchema: IntersectZod<\n C['querySchema'] extends ZodObject ? C['querySchema'] : undefined,\n C['queryExtensionSchema']\n >\n}\n\nexport type OutputField<C extends MethodCfg> = C['outputSchema'] extends ZodType\n ? {\n outputSchema: ZodObject<{\n out: C['outputSchema']\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n : {\n outputSchema: ZodObject<{\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n\nexport type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {\n __out: infer Out\n}\n ? Out\n : unknown\nexport type RouteSchemaInput<Schema extends RouteSchema> = Schema extends {\n __in?: infer In\n}\n ? In\n : unknown\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return (schema as any as ZodType).parse(data) as RouteSchemaOutput<T>\n}\n\nexport const lowProfileSafeParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): ZodSafeParseResult<RouteSchemaOutput<T>> => {\n return (schema as any as ZodType).safeParse(data) as ZodSafeParseResult<\n RouteSchemaOutput<T>\n >\n}\n\nexport const routeSchemaParse = <T>(\n routeSchema: RouteSchema<T>,\n): ZodType<T> => {\n return routeSchema as any as ZodType<T>\n}\n\n/**\n * Runtime helper that mirrors the typed merge used by the builder.\n * @param a Previously merged params schema inherited from parent segments.\n * @param b Newly introduced params schema.\n * @returns Intersection of schemas when both exist, otherwise whichever is defined.\n */\nexport function mergeSchemas<A extends ZodType, B extends ZodType>(\n a: A,\n b: B,\n): ZodType\nexport function mergeSchemas<A extends ZodType>(a: A, b: undefined): A\nexport function mergeSchemas<B extends ZodType>(a: undefined, b: B): B\nexport function mergeSchemas(\n a: ZodType | undefined,\n b: ZodType | undefined,\n): ZodType | undefined\nexport function mergeSchemas(a: ZodType | undefined, b: ZodType | undefined) {\n if (a && b) {\n if (a === b) return a\n return z.intersection(a as any, b as any)\n }\n return (a ?? b) as ZodType | undefined\n}\n\nexport function getZodShape(schema: ZodObject) {\n const shapeOrGetter = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n if (!shapeOrGetter) return {}\n return typeof shapeOrGetter === 'function'\n ? shapeOrGetter.call(schema)\n : shapeOrGetter\n}\n\nexport function collectNestedFieldSuggestions(\n shape: Record<string, ZodType> | undefined,\n prefix: string[] = [],\n): string[] {\n if (!shape) return []\n const suggestions: string[] = []\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodObject) {\n const nestedShape = getZodShape(value as ZodObject)\n const nestedSuggestions = collectNestedFieldSuggestions(nestedShape, [\n ...prefix,\n key,\n ])\n suggestions.push(\n ...(nestedSuggestions.length\n ? nestedSuggestions\n : [[...prefix, key].join('_')]),\n )\n } else if (prefix.length > 0) {\n suggestions.push([...prefix, key].join('_'))\n }\n }\n return suggestions\n}\n\n// Use the output generic of ZodType instead of z.output<S>\nexport type ToRouteSchema<S> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg = MethodCfg> = Prettify<\n Omit<\n Cfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n > & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\n outputMetaSchema: ToRouteSchema<Cfg['outputMetaSchema']>\n queryExtensionSchema: ToRouteSchema<Cfg['queryExtensionSchema']>\n }\n>\n\n/** Per-method configuration merged with inherited node config. */\nexport type MethodCfg = {\n /** Zod schema describing the request body. */\n bodySchema?: ZodType\n /** Zod schema describing the query string. */\n querySchema?: ZodType\n /** Zod schema describing path params (internal only, set through resource segments). */\n paramsSchema?: ZodType\n /** Zod schema describing the response payload. */\n outputSchema?: ZodType\n /** Multipart upload definitions for the route. */\n bodyFiles?: FileField[]\n /** Marks the route as an infinite feed (enables cursor helpers). */\n feed?: boolean\n /** feed handlers */\n outputMetaSchema?: ZodType\n queryExtensionSchema?: ZodType\n\n /** Optional human-readable description for docs/debugging. */\n description?: string\n /**\n * Short one-line summary for docs list views.\n * Shown in navigation / tables instead of the full description.\n */\n summary?: string\n /**\n * Group name used for navigation sections in docs UIs.\n * e.g. \"Users\", \"Billing\", \"Auth\".\n */\n docsGroup?: string\n /**\n * Tags that can be used to filter / facet in interactive docs.\n * e.g. [\"users\", \"admin\", \"internal\"].\n */\n tags?: string[]\n /**\n * Mark the route as deprecated in docs.\n * Renderers can badge this and/or hide by default.\n */\n deprecated?: boolean\n /**\n * Optional stability information for the route.\n * Renderers can surface this prominently.\n */\n stability?: 'experimental' | 'beta' | 'stable' | 'deprecated'\n /**\n * Hide this route from public docs while keeping it usable in code.\n */\n docsHidden?: boolean\n /**\n * Arbitrary extra metadata for docs renderers.\n * Can be used for auth requirements, rate limits, feature flags, etc.\n */\n docsMeta?: Record<string, unknown>\n}\n\n/** Immutable representation of a single HTTP route in the tree. */\nexport type Leaf<\n M extends HttpMethod,\n P extends string,\n C extends MethodCfg,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n\n/** Convenience union covering all generated leaves. */\nexport type AnyLeaf = Leaf<HttpMethod, string, MethodCfg>\n\n/** Merge two object types while keeping nice IntelliSense output. */\nexport type Merge<A, B> = Prettify<Omit<A, keyof B> & B>\n\n/** Append a new element to a readonly tuple type. */\nexport type Append<T extends readonly unknown[], X> = [...T, X]\n\n/** Concatenate two readonly tuple types. */\nexport type MergeArray<\n A extends readonly unknown[],\n B extends readonly unknown[],\n> = [...A, ...B]\n\ntype TrimTrailingSlash<S extends string> = S extends `${infer R}/`\n ? TrimTrailingSlash<R>\n : S\ntype TrimLeadingSlash<S extends string> = S extends `/${infer R}`\n ? TrimLeadingSlash<R>\n : S\n\ntype NormalizedBase<Base extends string> = TrimTrailingSlash<Base>\ntype NormalizedChild<Child extends string> = TrimLeadingSlash<Child>\n\nexport type JoinPath<Base extends string, Child extends string> =\n NormalizedBase<Base> extends ''\n ? Child\n : NormalizedChild<Child> extends ''\n ? NormalizedBase<Base>\n : `${NormalizedBase<Base>}/${NormalizedChild<Child>}`\nexport type IntersectZod<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n> = B extends ZodType\n ? A extends ZodType\n ? z.ZodIntersection<A, B>\n : B\n : A extends ZodType\n ? A\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> =\n Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ExistingOut & ParentOut>\n : Existing\n : Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ParentOut>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> & {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n }\n>\n\n// Tuple-mapped helper avoids recursive instantiation while re-basing nested leaves.\ntype RebasedLeaf<\n P extends string,\n Param extends ZodType | undefined,\n L extends LeafLowProfile,\n> = LeafLowProfile<\n L['method'],\n JoinPath<P, L['path']>,\n AugmentedCfg<L['cfg'], Param>\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n> = {\n [K in keyof R]: R[K] extends LeafLowProfile\n ? RebasedLeaf<P, Param, R[K]>\n : never\n}\n\ntype NodeQueryExtension<Node> = Node extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\n\ntype NodeOutputMeta<Node> = Node extends { outputMetaSchema?: infer OM }\n ? OM extends ZodType\n ? OM\n : undefined\n : undefined\n\ntype EffectiveQueryExtensionSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeQueryExtension<Node>\n\ntype EffectiveOutputMetaSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeOutputMeta<Node>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\ntype ParamValue<Params, Key extends string> =\n Params extends Record<Key, infer V> ? V : undefined\ntype MapKeySegments<\n Segments extends readonly string[],\n Params,\n> = Segments extends [infer A, ...infer Rest]\n ? A extends string\n ? A extends `:${infer Key}`\n ? [\n [ParamValue<Params, Key>],\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : [\n A,\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : []\n : []\ntype CacheKeyForLeaf<L extends AnyLeafLowProfile> = readonly [\n L['method'],\n ...MapKeySegments<SplitPath<L['path']>, ExtractParamsFromPath<L['path']>>,\n InferQuery<L> extends never ? {} : InferQuery<L>,\n]\nexport function buildCacheKey<L extends AnyLeafLowProfile>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}): CacheKeyForLeaf<L> {\n const segments = args.leaf.path.split('/').filter(Boolean) as SplitPath<\n L['path']\n >\n const keyParts: unknown[] = [args.leaf.method]\n for (const segment of segments) {\n if (segment.startsWith(':')) {\n const paramName = segment.slice(1)\n const value =\n args.params && paramName in args.params\n ? (args.params as Record<string, unknown>)[paramName]\n : undefined\n keyParts.push([value])\n continue\n }\n keyParts.push(segment)\n }\n keyParts.push(args.query ?? {})\n return keyParts as unknown as CacheKeyForLeaf<L>\n}\n\n/** Definition-time method config (for clarity). */\nexport type MethodCfgDef = MethodCfg\n\n/** Low-profile method config where schemas carry a phantom __out like SocketSchema. */\nexport type MethodCfgLowProfile = Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n// keep the overload as you have it\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\n const Node extends NodeCfg | undefined = undefined,\n const O extends ZodType | undefined = undefined,\n const P extends ZodType | undefined = undefined,\n const Q extends ZodType | undefined = undefined,\n const B extends ZodType | undefined = undefined,\n const FO extends ZodType | undefined = undefined,\n const FQ extends ZodType | undefined = undefined,\n const Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n node?: Node\n cfg: Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed: Feed\n bodySchema: RouteSchemaOrUndefined<B>\n querySchema: FeedAwareQueryRoute<Feed, Q, FQ, Node>\n paramsSchema: RouteSchemaOrUndefined<P>\n outputSchema: OutputRouteSchema<O, FO, Node>\n outputMetaSchema: RouteSchemaOrUndefined<\n EffectiveOutputMetaSchema<FO, Node>\n >\n queryExtensionSchema: RouteSchemaOrUndefined<\n EffectiveQueryExtensionSchema<FQ, Node>\n >\n }\n >\n>\n\n// implementation: NO z.infer here\nexport function buildLowProfileLeaf(leaf: any): any {\n const nodeCfg = (leaf.node ?? {}) as NodeCfg\n const mergedCfg = { ...nodeCfg, ...leaf.cfg }\n const effectiveQuerySchema =\n mergedCfg.feed === true\n ? mergeSchemas(mergedCfg.querySchema, mergedCfg.queryExtensionSchema)\n : mergedCfg.querySchema\n const effectiveOutputSchema = mergedCfg.outputSchema\n ? z.object({\n out: mergedCfg.outputSchema,\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n : z.object({\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n\n // ensure query schema is not nested\n if (mergedCfg.feed === true && effectiveQuerySchema instanceof ZodObject) {\n const shape = getZodShape(effectiveQuerySchema as ZodObject)\n const nestedFieldSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedFieldSuggestions.length > 0) {\n console.warn(\n `[routesV3.builder] Warning: feed query schema for ${leaf.method.toUpperCase()} ${leaf.path} contains nested objects. Consider using flat keys instead: ${nestedFieldSuggestions.join(\n ', ',\n )}`,\n )\n }\n }\n return {\n method: leaf.method,\n path: leaf.path,\n cfg: {\n ...mergedCfg,\n bodySchema: mergedCfg.bodySchema as RouteSchema<any> | undefined,\n querySchema: effectiveQuerySchema as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as\n | RouteSchema<any>\n | undefined,\n outputMetaSchema: mergedCfg.outputMetaSchema as\n | RouteSchema<any>\n | undefined,\n queryExtensionSchema: mergedCfg.queryExtensionSchema as\n | RouteSchema<any>\n | undefined,\n },\n }\n}\n\nexport const keyOf = (\n method: HttpMethod,\n path: string,\n encodeSafe?: boolean,\n) => {\n const key = `${method.toUpperCase()} ${path}` as const\n return encodeSafe ? encodeURIComponent(key) : key\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<any, infer PIn>\n ? PIn\n : L['cfg']['paramsSchema'] extends ZodType<any, infer PIn>\n ? PIn\n : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<any, infer QIn>\n ? QIn\n : L['cfg']['querySchema'] extends ZodType<any, infer QIn>\n ? QIn\n : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<any, infer BIn>\n ? BIn\n : L['cfg']['bodySchema'] extends ZodType<any, infer BIn>\n ? BIn\n : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\ntype InferMetaFromCfg<L extends AnyLeafLowProfile> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : string | undefined\n\ntype ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends\n | [never]\n | [unknown]\n ? InferMetaFromCfg<L>\n : M\n\ntype ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {\n meta: infer M\n}\n ? (undefined extends ResolvedMeta<L, M>\n ? { meta?: ResolvedMeta<L, M> }\n : { meta: ResolvedMeta<L, M> }) &\n Omit<O, 'meta'>\n : O\n\nexport type InferOutput<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O>\n ? ApplyMetaFallback<L, O>\n : L['cfg']['outputSchema'] extends ZodType<infer O>\n ? ApplyMetaFallback<L, O>\n : Fallback\n\nexport type InferFeedOutputMeta<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : Fallback\n\nexport type InferFeedQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['queryExtensionSchema'] extends RouteSchema<any, infer QIn>\n ? QIn\n : L['cfg']['queryExtensionSchema'] extends ZodType<any, infer QIn>\n ? QIn\n : Fallback\n\n/** Render a type as if it were a simple object literal. */\nexport type Prettify<T> = { [K in keyof T]: T[K] }\n","import { AnyLeafLowProfile, HttpMethod, Prettify } from './routesV3.core'\n\n/** Build the key type for a leaf — distributive so method/path stay paired. */\nexport type KeyOf<L extends AnyLeafLowProfile> = L extends AnyLeafLowProfile\n ? `${Uppercase<L['method']>} ${L['path']}`\n : never\n\n// From a tuple of leaves, get the union of keys (pairwise, no cartesian blow-up)\ntype KeysOf<Leaves extends readonly AnyLeafLowProfile[]> = KeyOf<Leaves[number]>\n\n// Parse method & path out of a key\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n// Given Leaves and a Key, pick the exact leaf that matches method+path\ntype LeafForKey<\n Leaves extends readonly AnyLeafLowProfile[],\n K extends string,\n> = Extract<\n Leaves[number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\ntype FilterRoute<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? First extends { path: `${string}${F}${string}` }\n ? FilterRoute<Rest, F, [...Acc, First]>\n : FilterRoute<Rest, F, Acc>\n : Acc\n\ntype UpperCase<S extends string> = S extends `${infer First}${infer Rest}`\n ? `${Uppercase<First>}${UpperCase<Rest>}`\n : S\n\ntype Routes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = FilterRoute<T, F>\ntype ByKey<\n T extends readonly AnyLeafLowProfile[],\n Acc extends Record<string, AnyLeafLowProfile> = {},\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? ByKey<\n Rest,\n Acc & { [K in `${UpperCase<First['method']>} ${First['path']}`]: First }\n >\n : Acc\n\n/**\n * Convenience helper for extracting a subset of routes by path fragment.\n * @param T Tuple of leaves produced by the DSL.\n * @param F String fragment to match against the route path.\n */\nexport type SubsetRoutes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = {\n byKey: ByKey<Routes<T, F>>\n all: Routes<T, F>\n}\n\n// In the same module as finalize\n\nexport interface FinalizedRegistry<L extends readonly AnyLeafLowProfile[]> {\n all: L\n byKey: { [K in KeysOf<L>]: Prettify<LeafForKey<L, K>> }\n log(logger: { system: (...args: unknown[]) => void }): void\n}\n\n// Optionally keep this alias if you like the name\nexport type Registry<L extends readonly AnyLeafLowProfile[]> =\n FinalizedRegistry<L>\n\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n): FinalizedRegistry<L> {\n type Keys = KeysOf<L>\n type MapByKey = { [K in Keys]: Prettify<LeafForKey<L, K>> }\n\n const byKey = Object.fromEntries(\n leaves.map((l) => [`${l.method.toUpperCase()} ${l.path}`, l] as const),\n ) as unknown as MapByKey\n\n const log = (logger: { system: (...args: unknown[]) => void }) => {\n logger.system('Finalized routes:')\n ;(Object.keys(byKey) as Keys[]).forEach((k) => {\n const leaf = byKey[k]\n logger.system(`- ${k}`)\n })\n }\n\n return { all: leaves, byKey, log }\n}\n","// socket.index.ts (shared client/server)\n\nimport { z } from 'zod'\n\nexport type SocketSchema<Output = unknown> = z.ZodType & {\n __out: Output\n}\n\nexport type SocketSchemaOutput<Schema extends z.ZodTypeAny> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport type SocketEvent<Out = unknown> = {\n message: z.ZodTypeAny\n /** phantom field, only for typing; not meant to be used at runtime */\n __out: Out\n}\n\nexport type EventMap = Record<string, SocketEvent<any>>\n\n/**\n * System event names – shared so server and client\n * don't drift on naming.\n */\nexport type SysEventName =\n | 'sys:connect'\n | 'sys:disconnect'\n | 'sys:reconnect'\n | 'sys:connect_error'\n | 'sys:ping'\n | 'sys:pong'\n | 'sys:room_join'\n | 'sys:room_leave'\nexport function defineSocketEvents<\n const C extends SocketConnectionConfig,\n const Schemas extends Record<\n string,\n {\n message: z.ZodTypeAny\n }\n >,\n>(\n config: C,\n events: Schemas,\n): {\n config: {\n [K in keyof C]: SocketSchema<z.output<C[K]>>\n }\n events: {\n [K in keyof Schemas]: SocketEvent<z.output<Schemas[K]['message']>>\n }\n}\n\nexport function defineSocketEvents(config: any, events: any) {\n return { config, events }\n}\n\nexport type Payload<T extends EventMap, K extends keyof T> =\n T[K] extends SocketEvent<infer Out> ? Out : never\nexport type SocketConnectionConfig = {\n joinMetaMessage: z.ZodTypeAny\n leaveMetaMessage: z.ZodTypeAny\n pingPayload: z.ZodTypeAny\n pongPayload: z.ZodTypeAny\n}\n\nexport type SocketConnectionConfigOutput = {\n joinMetaMessage: SocketSchema<any>\n leaveMetaMessage: SocketSchema<any>\n pingPayload: SocketSchema<any>\n pongPayload: SocketSchema<any>\n}\n"],"mappings":"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","names":["z","z"]}
1
+ {"version":3,"sources":["../src/core/routesV3.builder.ts","../src/core/routesV3.core.ts","../src/core/routesV3.finalize.ts","../src/sockets/socket.index.ts"],"sourcesContent":["import { z, ZodObject, ZodType } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n buildLowProfileLeaf,\n FeedQueryField,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n mergeSchemas,\n MethodCfg,\n NodeCfg,\n OutputField,\n Prettify,\n} from './routesV3.core'\n\ntype ParamZod<Name extends string, S extends ZodType> = ZodObject<{\n [K in Name]: S\n}>\ntype BaseMethodCfg<C extends MethodCfg> = Merge<\n Omit<MethodCfg, 'querySchema' | 'outputSchema' | 'feed'>,\n Omit<C, 'querySchema' | 'outputSchema' | 'feed'>\n>\n\ntype FeedField<C extends MethodCfg> = C['feed'] extends true\n ? { feed: true }\n : { feed?: boolean }\n\ntype NonFeedQueryField<C extends MethodCfg> = C['querySchema'] extends ZodType\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodType\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n : FeedField<C> & NonFeedQueryField<C> & OutputField<C> & ParamsField<C, PS>\n\ntype WithNodeDefaults<C extends MethodCfg, I extends NodeCfg> = Merge<\n C,\n {\n queryExtensionSchema: C['queryExtensionSchema'] extends ZodType\n ? C['queryExtensionSchema']\n : NodeQueryExtension<I>\n outputMetaSchema: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : NodeOutputMeta<I>\n }\n>\n\n// Avoids the previous MethodCfg merge step so TS doesn't have to repeatedly\n// expand the entire MethodCfg intersection for every method call.\ntype EffectiveCfgWithDefaults<C extends MethodCfg, PS> = Prettify<\n BaseMethodCfg<C> & EffectiveFeedFields<C, PS>\n>\n\ntype EffectiveCfg<C extends MethodCfg, PS, I extends NodeCfg> =\n WithNodeDefaults<C, I> extends infer WithDefaults extends MethodCfg\n ? EffectiveCfgWithDefaults<WithDefaults, PS>\n : never\n\ntype NodeWithoutSchemas<I extends NodeCfg> = Omit<\n I,\n 'queryExtensionSchema' | 'outputMetaSchema'\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<\n M,\n Base,\n Merge<NodeWithoutSchemas<I>, LowProfileCfg<EffectiveCfg<C, PS, I>>>\n>\n\ntype StripParamName<Name extends string> = Name extends `:${infer P}` ? P : Name\ntype NormalizeBaseLiteral<\n Base extends string,\n HasParam extends boolean,\n> = HasParam extends true\n ? Base extends `:${string}`\n ? Base\n : Base extends ''\n ? ''\n : `:${Base}`\n : Base\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType ? ParamZod<StripParamName<Base>, Param> : undefined\ntype ResourceBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = NormalizeBaseLiteral<Base, Param extends ZodType ? true : false>\ntype NodeQueryExtension<I extends NodeCfg> = I extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\ntype NodeOutputMeta<I extends NodeCfg> = I extends {\n outputMetaSchema?: infer OE\n}\n ? OE extends ZodType\n ? OE\n : undefined\n : undefined\n\ntype SubResourceCollections = readonly [\n ReadonlyArray<AnyLeafLowProfile>,\n ...ReadonlyArray<AnyLeafLowProfile>[],\n]\n\n// Bundling the branch generics keeps MethodFns<State, Used> from re-instantiating\n// four independent parameters for every chained call, which speeds up inference.\ntype BranchState<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n> = {\n base: Base\n leaves: Acc\n node: I\n params: PS\n}\n\ntype AnyBranchState = BranchState<\n string,\n readonly AnyLeafLowProfile[],\n NodeCfg,\n ZodType | undefined\n>\n\nexport type MergeAugmentedCollections<\n Base extends string,\n Param extends ZodType | undefined,\n Collections extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = Collections extends readonly [infer First, ...infer Rest]\n ? First extends ReadonlyArray<AnyLeafLowProfile>\n ? Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? MergeAugmentedCollections<\n Base,\n Param,\n Rest,\n MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n >\n : MergeArray<Acc, AugmentLeaves<Base, Param, First>>\n : MergeAugmentedCollections<\n Base,\n Param,\n Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>\n ? Rest\n : [],\n Acc\n >\n : Acc\n\ntype MethodFns<\n State extends AnyBranchState,\n Used extends HttpMethod | 'sub',\n> = {\n /**\n * Register a GET leaf at the current path.\n */\n get: 'get' extends Used\n ? never\n : <C extends MethodCfg>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<'get', State['base'], State['node'], C, State['params']>\n >,\n State['node'],\n State['params'],\n Used | 'get'\n >\n\n /**\n * Register a POST leaf at the current path.\n */\n post: 'post' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'post',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'post'\n >\n\n /**\n * Register a PUT leaf at the current path.\n */\n put: 'put' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'put',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'put'\n >\n\n /**\n * Register a PATCH leaf at the current path.\n */\n patch: 'patch' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'patch',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'patch'\n >\n\n /**\n * Register a DELETE leaf at the current path.\n */\n delete: 'delete' extends Used\n ? never\n : <C extends Omit<MethodCfg, 'feed'>>(\n cfg: C,\n ) => Branch<\n State['base'],\n Append<\n State['leaves'],\n BuiltLeaf<\n 'delete',\n State['base'],\n State['node'],\n Merge<C, { feed: false }>,\n State['params']\n >\n >,\n State['node'],\n State['params'],\n Used | 'delete'\n >\n}\n\n/** Builder surface used by `resource(...)` to accumulate leaves. */\nexport interface Branch<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodType | undefined,\n Used extends HttpMethod | 'sub' = never,\n> extends MethodFns<BranchState<Base, Acc, I, PS>, Used> {\n /**\n * Mount one or more sub-resources that were built via `resource(...)`.\n * Each resource carries its own base path (e.g. `users`, `:userId`, `posts`)\n * so this branch simply prefixes its current `Base` and merges param schemas.\n */\n sub: 'sub' extends Used\n ? never\n : <\n const Collections extends SubResourceCollections,\n NextAcc extends readonly AnyLeafLowProfile[] = MergeArray<\n Acc,\n MergeAugmentedCollections<Base, PS, Collections>\n >,\n >(\n ...collections: Collections\n ) => Branch<Base, NextAcc, I, PS, Used | 'sub'>\n\n /**\n * Finish the branch and return the collected leaves.\n * @returns Readonly tuple of accumulated leaves.\n */\n done(): Readonly<Acc>\n}\n\n/**\n * Start building a resource at the given base path.\n * @param base Root path for the resource (e.g. `/v1`).\n * @param inherited Optional node configuration applied to all descendants.\n * @returns Root `Branch` instance used to compose the route tree.\n */\nexport function resource<\n Base extends string = '',\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base?: Base,\n inherited?: I,\n idSchema?: Param,\n): Branch<\n ResourceBase<Base, Param>,\n readonly [],\n I,\n ParamSchemaForBase<Base, Param>\n> {\n const rawBase = (base ?? '') as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as ResourceBase<Base, Param>\n const rootInherited: I =\n inherited === undefined ? ({} as I) : ({ ...inherited } as I)\n const rootParams = createParamSchema(rawBase, idSchema) as\n | ParamSchemaForBase<Base, Param>\n | undefined\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodType | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeafLowProfile[] = []\n const currentBase: Base2 = base2\n const inheritedCfg: I2 = inherited2\n let currentParamsSchema: PS2 = mergedParamsSchema as PS2\n\n function add<M extends HttpMethod, C extends MethodCfg>(method: M, cfg: C) {\n const effectiveParamsSchema = (cfg.paramsSchema ??\n currentParamsSchema) as PS2 | undefined\n const fullCfg = (\n effectiveParamsSchema\n ? { ...cfg, paramsSchema: effectiveParamsSchema }\n : { ...cfg }\n ) as MethodCfg\n\n const leaf = buildLowProfileLeaf({\n method,\n path: currentBase as Base2,\n node: inheritedCfg,\n cfg: fullCfg,\n })\n\n stack.push(leaf as AnyLeafLowProfile)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount one or more subtrees built elsewhere.\n * Usage:\n * resource('/api').sub(\n * resource('users').get(...).done(),\n * resource('projects').get(...).done()\n * )\n */\n sub(...collections: readonly AnyLeafLowProfile[][]) {\n if (collections.length === 0) {\n throw new Error('sub() expects at least one resource')\n }\n\n for (const leaves of collections) {\n for (const leafLow of leaves) {\n const leaf = leafLow as unknown as AnyLeaf\n const leafCfg = leaf.cfg as MethodCfg\n const leafParams = leafCfg.paramsSchema as ZodType | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...inheritedCfg,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: joinPaths(currentBase, leaf.path),\n cfg: newCfg,\n }\n\n stack.push(newLeaf as AnyLeafLowProfile)\n }\n }\n\n return api\n },\n\n // methods (inject current params schema if missing)\n get<C extends MethodCfg>(cfg: C) {\n return add('get', cfg)\n },\n post<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('post', { ...cfg, feed: false })\n },\n put<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('put', { ...cfg, feed: false })\n },\n patch<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('patch', { ...cfg, feed: false })\n },\n delete<C extends Omit<MethodCfg, 'feed'>>(cfg: C) {\n return add('delete', { ...cfg, feed: false })\n },\n\n done() {\n return stack as readonly AnyLeafLowProfile[]\n },\n }\n\n return api as Branch<Base2, readonly [], I2, PS2>\n }\n\n // Root branch starts with no params schema (PS = undefined)\n return makeBranch(normalizedBase, rootInherited, rootParams)\n}\n\n/**\n * Merge two readonly tuples (preserves literal tuple information).\n * @param arr1 First tuple.\n * @param arr2 Second tuple.\n * @returns New tuple containing values from both inputs.\n */\nexport const mergeArrays = <T extends readonly any[], S extends readonly any[]>(\n arr1: T,\n arr2: S,\n) => {\n return [...arr1, ...arr2] as [...T, ...S]\n}\n\nfunction normalizeBaseSegment(base: string, hasParam: boolean) {\n const value = base ?? ''\n if (!hasParam) return value\n if (!value) {\n throw new Error(\n 'resource() requires a segment name when defining an id schema',\n )\n }\n if (value.includes('/')) {\n const segments = value.split('/').filter(Boolean)\n if (segments.length === 0) {\n throw new Error(\n 'resource() received an invalid segment for param injection',\n )\n }\n const lastIndex = segments.length - 1\n const last = segments[lastIndex]\n segments[lastIndex] = last.startsWith(':') ? last : `:${last}`\n return `${value.startsWith('/') ? '/' : ''}${segments.join('/')}`\n }\n return value.startsWith(':') ? value : `:${value}`\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const segments = nameSegment.split('/').filter(Boolean)\n const rawName =\n segments.length > 0 ? segments[segments.length - 1] : nameSegment\n const normalized = rawName.startsWith(':') ? rawName.slice(1) : rawName\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n return z.object({ [normalized]: schema } as Record<string, ZodType>)\n}\n\nfunction joinPaths(parent: string, child: string) {\n if (!parent) return child\n if (!child) return parent\n const trimmedParent = parent.endsWith('/')\n ? parent.replace(/\\/+$/, '')\n : parent\n const trimmedChild = child.startsWith('/') ? child.replace(/^\\/+/, '') : child\n if (!trimmedChild) return trimmedParent\n return `${trimmedParent}/${trimmedChild}`\n}\n","import { z, ZodObject, ZodSafeParseResult, ZodType } from 'zod'\n\n/** Supported HTTP verbs for the routes DSL. */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** Declarative description of a multipart upload field. */\nexport type FileField = {\n /** Form field name used for uploads. */\n name: string\n /** Maximum number of files accepted for this field. */\n maxCount: number\n}\n\n/** Configuration that applies to an entire branch of the route tree. */\nexport interface NodeCfg {\n /**\n * Feed-specific query schema applied to all descendants unless they override it.\n */\n queryExtensionSchema?: ZodType\n /**\n * Feed meta schema applied to all descendants unless they override it.\n */\n outputMetaSchema?: ZodType\n}\n\nexport type RouteSchema<Output = unknown, Input = Output> = {\n __out: Output\n __in?: Input\n}\n\ntype RouteSchemaOrUndefined<S extends ZodType | undefined> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : undefined\n\ntype FeedAwareQueryRoute<\n Feed extends boolean,\n Query extends ZodType | undefined,\n Extension extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Feed extends true\n ? ToRouteSchema<\n FeedQueryField<{\n querySchema: Query\n queryExtensionSchema: EffectiveQueryExtensionSchema<Extension, Node>\n }>['querySchema']\n >\n : RouteSchemaOrUndefined<Query>\n\ntype OutputRouteSchema<\n O extends ZodType | undefined,\n Meta extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = ToRouteSchema<\n OutputField<{\n outputSchema: O\n outputMetaSchema: EffectiveOutputMetaSchema<Meta, Node>\n }>['outputSchema']\n>\n\nexport type FeedQueryField<C extends MethodCfg> = {\n querySchema: IntersectZod<\n C['querySchema'] extends ZodObject ? C['querySchema'] : undefined,\n C['queryExtensionSchema']\n >\n}\n\nexport type OutputField<C extends MethodCfg> = C['outputSchema'] extends ZodType\n ? {\n outputSchema: ZodObject<{\n out: C['outputSchema']\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n : {\n outputSchema: ZodObject<{\n meta: C['outputMetaSchema'] extends ZodType\n ? C['outputMetaSchema']\n : z.ZodOptional<z.ZodString>\n }>\n }\n\nexport type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {\n __out: infer Out\n}\n ? Out\n : unknown\nexport type RouteSchemaInput<Schema extends RouteSchema> = Schema extends {\n __in?: infer In\n}\n ? In\n : unknown\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return (schema as any as ZodType).parse(data) as RouteSchemaOutput<T>\n}\n\nexport const lowProfileSafeParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): ZodSafeParseResult<RouteSchemaOutput<T>> => {\n return (schema as any as ZodType).safeParse(data) as ZodSafeParseResult<\n RouteSchemaOutput<T>\n >\n}\n\nexport const routeSchemaParse = <T>(\n routeSchema: RouteSchema<T>,\n): ZodType<T> => {\n return routeSchema as any as ZodType<T>\n}\n\n/**\n * Runtime helper that mirrors the typed merge used by the builder.\n * @param a Previously merged params schema inherited from parent segments.\n * @param b Newly introduced params schema.\n * @returns Intersection of schemas when both exist, otherwise whichever is defined.\n */\nexport function mergeSchemas<A extends ZodType, B extends ZodType>(\n a: A,\n b: B,\n): ZodType\nexport function mergeSchemas<A extends ZodType>(a: A, b: undefined): A\nexport function mergeSchemas<B extends ZodType>(a: undefined, b: B): B\nexport function mergeSchemas(\n a: ZodType | undefined,\n b: ZodType | undefined,\n): ZodType | undefined\nexport function mergeSchemas(a: ZodType | undefined, b: ZodType | undefined) {\n if (a && b) {\n if (a === b) return a\n return z.intersection(a as any, b as any)\n }\n return (a ?? b) as ZodType | undefined\n}\n\nexport function getZodShape(schema: ZodObject) {\n const shapeOrGetter = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n if (!shapeOrGetter) return {}\n return typeof shapeOrGetter === 'function'\n ? shapeOrGetter.call(schema)\n : shapeOrGetter\n}\n\nexport function collectNestedFieldSuggestions(\n shape: Record<string, ZodType> | undefined,\n prefix: string[] = [],\n): string[] {\n if (!shape) return []\n const suggestions: string[] = []\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodObject) {\n const nestedShape = getZodShape(value as ZodObject)\n const nestedSuggestions = collectNestedFieldSuggestions(nestedShape, [\n ...prefix,\n key,\n ])\n suggestions.push(\n ...(nestedSuggestions.length\n ? nestedSuggestions\n : [[...prefix, key].join('_')]),\n )\n } else if (prefix.length > 0) {\n suggestions.push([...prefix, key].join('_'))\n }\n }\n return suggestions\n}\n\n// Use the output generic of ZodType instead of z.output<S>\nexport type ToRouteSchema<S> =\n S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg = MethodCfg> = Prettify<\n Omit<\n Cfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n > & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\n outputMetaSchema: ToRouteSchema<Cfg['outputMetaSchema']>\n queryExtensionSchema: ToRouteSchema<Cfg['queryExtensionSchema']>\n }\n>\n\n/** Per-method configuration merged with inherited node config. */\nexport type MethodCfg = {\n /** Zod schema describing the request body. */\n bodySchema?: ZodType\n /** Zod schema describing the query string. */\n querySchema?: ZodType\n /** Zod schema describing path params (internal only, set through resource segments). */\n paramsSchema?: ZodType\n /** Zod schema describing the response payload. */\n outputSchema?: ZodType\n /** Multipart upload definitions for the route. */\n bodyFiles?: FileField[]\n /** Marks the route as an infinite feed (enables cursor helpers). */\n feed?: boolean\n /** feed handlers */\n outputMetaSchema?: ZodType\n queryExtensionSchema?: ZodType\n\n /** Optional human-readable description for docs/debugging. */\n description?: string\n /**\n * Short one-line summary for docs list views.\n * Shown in navigation / tables instead of the full description.\n */\n summary?: string\n /**\n * Group name used for navigation sections in docs UIs.\n * e.g. \"Users\", \"Billing\", \"Auth\".\n */\n docsGroup?: string\n /**\n * Tags that can be used to filter / facet in interactive docs.\n * e.g. [\"users\", \"admin\", \"internal\"].\n */\n tags?: string[]\n /**\n * Mark the route as deprecated in docs.\n * Renderers can badge this and/or hide by default.\n */\n deprecated?: boolean\n /**\n * Optional stability information for the route.\n * Renderers can surface this prominently.\n */\n stability?: 'experimental' | 'beta' | 'stable' | 'deprecated'\n /**\n * Hide this route from public docs while keeping it usable in code.\n */\n docsHidden?: boolean\n /**\n * Arbitrary extra metadata for docs renderers.\n * Can be used for auth requirements, rate limits, feature flags, etc.\n */\n docsMeta?: Record<string, unknown>\n}\n\n/** Immutable representation of a single HTTP route in the tree. */\nexport type Leaf<\n M extends HttpMethod,\n P extends string,\n C extends MethodCfg,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n\n/** Convenience union covering all generated leaves. */\nexport type AnyLeaf = Leaf<HttpMethod, string, MethodCfg>\n\n/** Merge two object types while keeping nice IntelliSense output. */\nexport type Merge<A, B> = Prettify<Omit<A, keyof B> & B>\n\n/** Append a new element to a readonly tuple type. */\nexport type Append<T extends readonly unknown[], X> = [...T, X]\n\n/** Concatenate two readonly tuple types. */\nexport type MergeArray<\n A extends readonly unknown[],\n B extends readonly unknown[],\n> = [...A, ...B]\n\ntype TrimTrailingSlash<S extends string> = S extends `${infer R}/`\n ? TrimTrailingSlash<R>\n : S\ntype TrimLeadingSlash<S extends string> = S extends `/${infer R}`\n ? TrimLeadingSlash<R>\n : S\n\ntype NormalizedBase<Base extends string> = TrimTrailingSlash<Base>\ntype NormalizedChild<Child extends string> = TrimLeadingSlash<Child>\n\nexport type JoinPath<Base extends string, Child extends string> =\n NormalizedBase<Base> extends ''\n ? Child\n : NormalizedChild<Child> extends ''\n ? NormalizedBase<Base>\n : `${NormalizedBase<Base>}/${NormalizedChild<Child>}`\nexport type IntersectZod<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n> = B extends ZodType\n ? A extends ZodType\n ? z.ZodIntersection<A, B>\n : B\n : A extends ZodType\n ? A\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> =\n Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ExistingOut & ParentOut>\n : Existing\n : Parent extends ZodType<infer ParentOut>\n ? RouteSchema<ParentOut>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> & {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n }\n>\n\n// Tuple-mapped helper avoids recursive instantiation while re-basing nested leaves.\ntype RebasedLeaf<\n P extends string,\n Param extends ZodType | undefined,\n L extends LeafLowProfile,\n> = LeafLowProfile<\n L['method'],\n JoinPath<P, L['path']>,\n AugmentedCfg<L['cfg'], Param>\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n> = {\n [K in keyof R]: R[K] extends LeafLowProfile\n ? RebasedLeaf<P, Param, R[K]>\n : never\n}\n\ntype NodeQueryExtension<Node> = Node extends {\n queryExtensionSchema?: infer QE\n}\n ? QE extends ZodType\n ? QE\n : undefined\n : undefined\n\ntype NodeOutputMeta<Node> = Node extends { outputMetaSchema?: infer OM }\n ? OM extends ZodType\n ? OM\n : undefined\n : undefined\n\ntype EffectiveQueryExtensionSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeQueryExtension<Node>\n\ntype EffectiveOutputMetaSchema<\n Method extends ZodType | undefined,\n Node extends NodeCfg | undefined,\n> = Method extends ZodType ? Method : NodeOutputMeta<Node>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\ntype ParamValue<Params, Key extends string> =\n Params extends Record<Key, infer V> ? V : undefined\ntype MapKeySegments<\n Segments extends readonly string[],\n Params,\n> = Segments extends [infer A, ...infer Rest]\n ? A extends string\n ? A extends `:${infer Key}`\n ? [\n [ParamValue<Params, Key>],\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : [\n A,\n ...MapKeySegments<Rest extends readonly string[] ? Rest : [], Params>,\n ]\n : []\n : []\ntype CacheKeyForLeaf<L extends AnyLeafLowProfile> = readonly [\n L['method'],\n ...MapKeySegments<SplitPath<L['path']>, ExtractParamsFromPath<L['path']>>,\n InferQuery<L> extends never ? {} : InferQuery<L>,\n]\nexport function buildCacheKey<L extends AnyLeafLowProfile>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}): CacheKeyForLeaf<L> {\n const segments = args.leaf.path.split('/').filter(Boolean) as SplitPath<\n L['path']\n >\n const keyParts: unknown[] = [args.leaf.method]\n for (const segment of segments) {\n if (segment.startsWith(':')) {\n const paramName = segment.slice(1)\n const value =\n args.params && paramName in args.params\n ? (args.params as Record<string, unknown>)[paramName]\n : undefined\n keyParts.push([value])\n continue\n }\n keyParts.push(segment)\n }\n keyParts.push(args.query ?? {})\n return keyParts as unknown as CacheKeyForLeaf<L>\n}\n\n/** Definition-time method config (for clarity). */\nexport type MethodCfgDef = MethodCfg\n\n/** Low-profile method config where schemas carry a phantom __out like SocketSchema. */\nexport type MethodCfgLowProfile = Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n// keep the overload as you have it\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\n const Node extends NodeCfg | undefined = undefined,\n const O extends ZodType | undefined = undefined,\n const P extends ZodType | undefined = undefined,\n const Q extends ZodType | undefined = undefined,\n const B extends ZodType | undefined = undefined,\n const FO extends ZodType | undefined = undefined,\n const FQ extends ZodType | undefined = undefined,\n const Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n node?: Node\n cfg: Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n | 'bodySchema'\n | 'querySchema'\n | 'paramsSchema'\n | 'outputSchema'\n | 'feed'\n | 'outputMetaSchema'\n | 'queryExtensionSchema'\n > & {\n feed: Feed\n bodySchema: RouteSchemaOrUndefined<B>\n querySchema: FeedAwareQueryRoute<Feed, Q, FQ, Node>\n paramsSchema: RouteSchemaOrUndefined<P>\n outputSchema: OutputRouteSchema<O, FO, Node>\n outputMetaSchema: RouteSchemaOrUndefined<\n EffectiveOutputMetaSchema<FO, Node>\n >\n queryExtensionSchema: RouteSchemaOrUndefined<\n EffectiveQueryExtensionSchema<FQ, Node>\n >\n }\n >\n>\n\n// implementation: NO z.infer here\nexport function buildLowProfileLeaf(leaf: any): any {\n const nodeCfg = (leaf.node ?? {}) as NodeCfg\n const mergedCfg = { ...nodeCfg, ...leaf.cfg }\n const effectiveQuerySchema =\n mergedCfg.feed === true\n ? mergeSchemas(mergedCfg.querySchema, mergedCfg.queryExtensionSchema)\n : mergedCfg.querySchema\n const effectiveOutputSchema = mergedCfg.outputSchema\n ? z.object({\n out: mergedCfg.outputSchema,\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n : z.object({\n meta: mergedCfg.outputMetaSchema ?? z.string().optional(),\n })\n\n // ensure query schema is not nested\n if (mergedCfg.feed === true && effectiveQuerySchema instanceof ZodObject) {\n const shape = getZodShape(effectiveQuerySchema as ZodObject)\n const nestedFieldSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedFieldSuggestions.length > 0) {\n console.warn(\n `[routesV3.builder] Warning: feed query schema for ${leaf.method.toUpperCase()} ${leaf.path} contains nested objects. Consider using flat keys instead: ${nestedFieldSuggestions.join(\n ', ',\n )}`,\n )\n }\n }\n return {\n method: leaf.method,\n path: leaf.path,\n cfg: {\n ...mergedCfg,\n bodySchema: mergedCfg.bodySchema as RouteSchema<any> | undefined,\n querySchema: effectiveQuerySchema as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as\n | RouteSchema<any>\n | undefined,\n outputMetaSchema: mergedCfg.outputMetaSchema as\n | RouteSchema<any>\n | undefined,\n queryExtensionSchema: mergedCfg.queryExtensionSchema as\n | RouteSchema<any>\n | undefined,\n },\n }\n}\n\nexport const keyOf = (\n method: HttpMethod,\n path: string,\n encodeSafe?: boolean,\n) => {\n const key = `${method.toUpperCase()} ${path}` as const\n return encodeSafe ? encodeURIComponent(key) : key\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer POut>\n ? POut\n : L['cfg']['paramsSchema'] extends ZodType<infer POut>\n ? POut\n : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer QOut>\n ? QOut\n : L['cfg']['querySchema'] extends ZodType<infer QOut>\n ? QOut\n : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer BOut>\n ? BOut\n : L['cfg']['bodySchema'] extends ZodType<infer BOut>\n ? BOut\n : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\ntype InferMetaFromCfg<L extends AnyLeafLowProfile> =\n L['cfg']['outputMetaSchema'] extends RouteSchema<infer O>\n ? O\n : L['cfg']['outputMetaSchema'] extends ZodType<infer O>\n ? O\n : string | undefined\n\ntype ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends\n | [never]\n | [unknown]\n ? InferMetaFromCfg<L>\n : M\n\ntype ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {\n meta: infer M\n}\n ? (undefined extends ResolvedMeta<L, M>\n ? { meta?: ResolvedMeta<L, M> }\n : { meta: ResolvedMeta<L, M> }) &\n Omit<O, 'meta'>\n : O\n\nexport type InferOutput<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O>\n ? ApplyMetaFallback<L, O>\n : L['cfg']['outputSchema'] extends ZodType<infer O>\n ? ApplyMetaFallback<L, O>\n : Fallback\n\n/** Render a type as if it were a simple object literal. */\nexport type Prettify<T> = { [K in keyof T]: T[K] }\n","import { AnyLeafLowProfile, HttpMethod, Prettify } from './routesV3.core'\n\n/** Build the key type for a leaf — distributive so method/path stay paired. */\nexport type KeyOf<L extends AnyLeafLowProfile> = L extends AnyLeafLowProfile\n ? `${Uppercase<L['method']>} ${L['path']}`\n : never\n\n// From a tuple of leaves, get the union of keys (pairwise, no cartesian blow-up)\ntype KeysOf<Leaves extends readonly AnyLeafLowProfile[]> = KeyOf<Leaves[number]>\n\n// Parse method & path out of a key\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n// Given Leaves and a Key, pick the exact leaf that matches method+path\ntype LeafForKey<\n Leaves extends readonly AnyLeafLowProfile[],\n K extends string,\n> = Extract<\n Leaves[number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\ntype FilterRoute<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n Acc extends readonly AnyLeafLowProfile[] = [],\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? First extends { path: `${string}${F}${string}` }\n ? FilterRoute<Rest, F, [...Acc, First]>\n : FilterRoute<Rest, F, Acc>\n : Acc\n\ntype UpperCase<S extends string> = S extends `${infer First}${infer Rest}`\n ? `${Uppercase<First>}${UpperCase<Rest>}`\n : S\n\ntype Routes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = FilterRoute<T, F>\ntype ByKey<\n T extends readonly AnyLeafLowProfile[],\n Acc extends Record<string, AnyLeafLowProfile> = {},\n> = T extends readonly [\n infer First extends AnyLeafLowProfile,\n ...infer Rest extends AnyLeafLowProfile[],\n]\n ? ByKey<\n Rest,\n Acc & { [K in `${UpperCase<First['method']>} ${First['path']}`]: First }\n >\n : Acc\n\n/**\n * Convenience helper for extracting a subset of routes by path fragment.\n * @param T Tuple of leaves produced by the DSL.\n * @param F String fragment to match against the route path.\n */\nexport type SubsetRoutes<\n T extends readonly AnyLeafLowProfile[],\n F extends string,\n> = {\n byKey: ByKey<Routes<T, F>>\n all: Routes<T, F>\n}\n\n// In the same module as finalize\n\nexport interface FinalizedRegistry<L extends readonly AnyLeafLowProfile[]> {\n all: L\n byKey: { [K in KeysOf<L>]: Prettify<LeafForKey<L, K>> }\n log(logger: { system: (...args: unknown[]) => void }): void\n}\n\n// Optionally keep this alias if you like the name\nexport type Registry<L extends readonly AnyLeafLowProfile[]> =\n FinalizedRegistry<L>\n\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n): FinalizedRegistry<L> {\n type Keys = KeysOf<L>\n type MapByKey = { [K in Keys]: Prettify<LeafForKey<L, K>> }\n\n const byKey = Object.fromEntries(\n leaves.map((l) => [`${l.method.toUpperCase()} ${l.path}`, l] as const),\n ) as unknown as MapByKey\n\n const log = (logger: { system: (...args: unknown[]) => void }) => {\n logger.system('Finalized routes:')\n ;(Object.keys(byKey) as Keys[]).forEach((k) => {\n const leaf = byKey[k]\n logger.system(`- ${k}`)\n })\n }\n\n return { all: leaves, byKey, log }\n}\n","// socket.index.ts (shared client/server)\n\nimport { z } from 'zod'\n\nexport type SocketSchema<Output = unknown> = z.ZodType & {\n __out: Output\n}\n\nexport type SocketSchemaOutput<Schema extends z.ZodTypeAny> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport type SocketEvent<Out = unknown> = {\n message: z.ZodTypeAny\n /** phantom field, only for typing; not meant to be used at runtime */\n __out: Out\n}\n\nexport type EventMap = Record<string, SocketEvent<any>>\n\n/**\n * System event names – shared so server and client\n * don't drift on naming.\n */\nexport type SysEventName =\n | 'sys:connect'\n | 'sys:disconnect'\n | 'sys:reconnect'\n | 'sys:connect_error'\n | 'sys:ping'\n | 'sys:pong'\n | 'sys:room_join'\n | 'sys:room_leave'\nexport function defineSocketEvents<\n const C extends SocketConnectionConfig,\n const Schemas extends Record<\n string,\n {\n message: z.ZodTypeAny\n }\n >,\n>(\n config: C,\n events: Schemas,\n): {\n config: {\n [K in keyof C]: SocketSchema<z.output<C[K]>>\n }\n events: {\n [K in keyof Schemas]: SocketEvent<z.output<Schemas[K]['message']>>\n }\n}\n\nexport function defineSocketEvents(config: any, events: any) {\n return { config, events }\n}\n\nexport type Payload<T extends EventMap, K extends keyof T> =\n T[K] extends SocketEvent<infer Out> ? Out : never\nexport type SocketConnectionConfig = {\n joinMetaMessage: z.ZodTypeAny\n leaveMetaMessage: z.ZodTypeAny\n pingPayload: z.ZodTypeAny\n pongPayload: z.ZodTypeAny\n}\n\nexport type SocketConnectionConfigOutput = {\n joinMetaMessage: SocketSchema<any>\n leaveMetaMessage: SocketSchema<any>\n pingPayload: SocketSchema<any>\n pongPayload: SocketSchema<any>\n}\n"],"mappings":";AAAA,SAAS,KAAAA,UAA6B;;;ACAtC,SAAS,GAAG,iBAA8C;AA4FnD,IAAM,kBAAkB,CAC7B,QACA,SACyB;AACzB,SAAQ,OAA0B,MAAM,IAAI;AAC9C;AAEO,IAAM,sBAAsB,CACjC,QACA,SAC6C;AAC7C,SAAQ,OAA0B,UAAU,IAAI;AAGlD;AAEO,IAAM,mBAAmB,CAC9B,gBACe;AACf,SAAO;AACT;AAkBO,SAAS,aAAa,GAAwB,GAAwB;AAC3E,MAAI,KAAK,GAAG;AACV,QAAI,MAAM,EAAG,QAAO;AACpB,WAAO,EAAE,aAAa,GAAU,CAAQ;AAAA,EAC1C;AACA,SAAQ,KAAK;AACf;AAEO,SAAS,YAAY,QAAmB;AAC7C,QAAM,gBAAiB,OAAe,QACjC,OAAe,QACf,OAAe,MAAM,QAAQ;AAClC,MAAI,CAAC,cAAe,QAAO,CAAC;AAC5B,SAAO,OAAO,kBAAkB,aAC5B,cAAc,KAAK,MAAM,IACzB;AACN;AAEO,SAAS,8BACd,OACA,SAAmB,CAAC,GACV;AACV,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,cAAwB,CAAC;AAC/B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,iBAAiB,EAAE,WAAW;AAChC,YAAM,cAAc,YAAY,KAAkB;AAClD,YAAM,oBAAoB,8BAA8B,aAAa;AAAA,QACnE,GAAG;AAAA,QACH;AAAA,MACF,CAAC;AACD,kBAAY;AAAA,QACV,GAAI,kBAAkB,SAClB,oBACA,CAAC,CAAC,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,MACjC;AAAA,IACF,WAAW,OAAO,SAAS,GAAG;AAC5B,kBAAY,KAAK,CAAC,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AACT;AA8NO,SAAS,YACd,MACA,QACA;AACA,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,KAAK,QAAQ,qBAAqB,CAAC,GAAG,MAAM;AACjD,UAAM,IAAK,OAAe,CAAC;AAC3B,QAAI,MAAM,UAAa,MAAM,KAAM,OAAM,IAAI,MAAM,kBAAkB,CAAC,EAAE;AACxE,WAAO,OAAO,CAAC;AAAA,EACjB,CAAC;AACH;AAsCO,SAAS,cAA2C,MAIpC;AACrB,QAAM,WAAW,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAGzD,QAAM,WAAsB,CAAC,KAAK,KAAK,MAAM;AAC7C,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,YAAM,YAAY,QAAQ,MAAM,CAAC;AACjC,YAAM,QACJ,KAAK,UAAU,aAAa,KAAK,SAC5B,KAAK,OAAmC,SAAS,IAClD;AACN,eAAS,KAAK,CAAC,KAAK,CAAC;AACrB;AAAA,IACF;AACA,aAAS,KAAK,OAAO;AAAA,EACvB;AACA,WAAS,KAAK,KAAK,SAAS,CAAC,CAAC;AAC9B,SAAO;AACT;AA4FO,SAAS,oBAAoB,MAAgB;AAClD,QAAM,UAAW,KAAK,QAAQ,CAAC;AAC/B,QAAM,YAAY,EAAE,GAAG,SAAS,GAAG,KAAK,IAAI;AAC5C,QAAM,uBACJ,UAAU,SAAS,OACf,aAAa,UAAU,aAAa,UAAU,oBAAoB,IAClE,UAAU;AAChB,QAAM,wBAAwB,UAAU,eACpC,EAAE,OAAO;AAAA,IACP,KAAK,UAAU;AAAA,IACf,MAAM,UAAU,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1D,CAAC,IACD,EAAE,OAAO;AAAA,IACP,MAAM,UAAU,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1D,CAAC;AAGL,MAAI,UAAU,SAAS,QAAQ,gCAAgC,WAAW;AACxE,UAAM,QAAQ,YAAY,oBAAiC;AAC3D,UAAM,yBAAyB,8BAA8B,KAAK;AAClE,QAAI,uBAAuB,SAAS,GAAG;AACrC,cAAQ;AAAA,QACN,qDAAqD,KAAK,OAAO,YAAY,CAAC,IAAI,KAAK,IAAI,+DAA+D,uBAAuB;AAAA,UAC/K;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,KAAK;AAAA,MACH,GAAG;AAAA,MACH,YAAY,UAAU;AAAA,MACtB,aAAa;AAAA,MACb,cAAc,UAAU;AAAA,MACxB,cAAc;AAAA,MAGd,kBAAkB,UAAU;AAAA,MAG5B,sBAAsB,UAAU;AAAA,IAGlC;AAAA,EACF;AACF;AAEO,IAAM,QAAQ,CACnB,QACA,MACA,eACG;AACH,QAAM,MAAM,GAAG,OAAO,YAAY,CAAC,IAAI,IAAI;AAC3C,SAAO,aAAa,mBAAmB,GAAG,IAAI;AAChD;;;AD9RO,SAAS,SAKd,MACA,WACA,UAMA;AACA,QAAM,UAAW,QAAQ;AACzB,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,QAAQ,QAAQ;AAAA,EAClB;AACA,QAAM,gBACJ,cAAc,SAAa,CAAC,IAAW,EAAE,GAAG,UAAU;AACxD,QAAM,aAAa,kBAAkB,SAAS,QAAQ;AAItD,WAAS,WAIP,OAAc,YAAgB,oBAA0B;AACxD,UAAM,QAA6B,CAAC;AACpC,UAAM,cAAqB;AAC3B,UAAM,eAAmB;AACzB,QAAI,sBAA2B;AAE/B,aAAS,IAA+C,QAAW,KAAQ;AACzE,YAAM,wBAAyB,IAAI,gBACjC;AACF,YAAM,UACJ,wBACI,EAAE,GAAG,KAAK,cAAc,sBAAsB,IAC9C,EAAE,GAAG,IAAI;AAGf,YAAM,OAAO,oBAAoB;AAAA,QAC/B;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK;AAAA,MACP,CAAC;AAED,YAAM,KAAK,IAAyB;AAEpC,aAAO;AAAA,IACT;AAEA,UAAM,MAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASf,OAAO,aAA6C;AAClD,YAAI,YAAY,WAAW,GAAG;AAC5B,gBAAM,IAAI,MAAM,qCAAqC;AAAA,QACvD;AAEA,mBAAW,UAAU,aAAa;AAChC,qBAAW,WAAW,QAAQ;AAC5B,kBAAM,OAAO;AACb,kBAAM,UAAU,KAAK;AACrB,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,kBAAkB;AAAA,cACtB;AAAA,cACA;AAAA,YACF;AAEA,kBAAM,SAAoB;AAAA,cACxB,GAAG;AAAA,cACH,GAAG;AAAA,YACL;AAEA,gBAAI,iBAAiB;AACnB,qBAAO,eAAe;AAAA,YACxB,WAAW,kBAAkB,QAAQ;AACnC,qBAAO,OAAO;AAAA,YAChB;AAEA,kBAAM,UAAmB;AAAA,cACvB,QAAQ,KAAK;AAAA,cACb,MAAM,UAAU,aAAa,KAAK,IAAI;AAAA,cACtC,KAAK;AAAA,YACP;AAEA,kBAAM,KAAK,OAA4B;AAAA,UACzC;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,IAAyB,KAAQ;AAC/B,eAAO,IAAI,OAAO,GAAG;AAAA,MACvB;AAAA,MACA,KAAwC,KAAQ;AAC9C,eAAO,IAAI,QAAQ,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC;AAAA,MAC5C;AAAA,MACA,IAAuC,KAAQ;AAC7C,eAAO,IAAI,OAAO,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC;AAAA,MAC3C;AAAA,MACA,MAAyC,KAAQ;AAC/C,eAAO,IAAI,SAAS,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC;AAAA,MAC7C;AAAA,MACA,OAA0C,KAAQ;AAChD,eAAO,IAAI,UAAU,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC;AAAA,MAC9C;AAAA,MAEA,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAGA,SAAO,WAAW,gBAAgB,eAAe,UAAU;AAC7D;AAQO,IAAM,cAAc,CACzB,MACA,SACG;AACH,SAAO,CAAC,GAAG,MAAM,GAAG,IAAI;AAC1B;AAEA,SAAS,qBAAqB,MAAc,UAAmB;AAC7D,QAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,GAAG,GAAG;AACvB,UAAM,WAAW,MAAM,MAAM,GAAG,EAAE,OAAO,OAAO;AAChD,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,SAAS,SAAS;AACpC,UAAM,OAAO,SAAS,SAAS;AAC/B,aAAS,SAAS,IAAI,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAC5D,WAAO,GAAG,MAAM,WAAW,GAAG,IAAI,MAAM,EAAE,GAAG,SAAS,KAAK,GAAG,CAAC;AAAA,EACjE;AACA,SAAO,MAAM,WAAW,GAAG,IAAI,QAAQ,IAAI,KAAK;AAClD;AAEA,SAAS,kBAAkB,aAAqB,QAAkB;AAChE,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,YAAY,MAAM,GAAG,EAAE,OAAO,OAAO;AACtD,QAAM,UACJ,SAAS,SAAS,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AACxD,QAAM,aAAa,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;AAChE,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAOC,GAAE,OAAO,EAAE,CAAC,UAAU,GAAG,OAAO,CAA4B;AACrE;AAEA,SAAS,UAAU,QAAgB,OAAe;AAChD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,gBAAgB,OAAO,SAAS,GAAG,IACrC,OAAO,QAAQ,QAAQ,EAAE,IACzB;AACJ,QAAM,eAAe,MAAM,WAAW,GAAG,IAAI,MAAM,QAAQ,QAAQ,EAAE,IAAI;AACzE,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,GAAG,aAAa,IAAI,YAAY;AACzC;;;AE/aO,SAAS,SACd,QACsB;AAItB,QAAM,QAAQ,OAAO;AAAA,IACnB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAU;AAAA,EACvE;AAEA,QAAM,MAAM,CAAC,WAAqD;AAChE,WAAO,OAAO,mBAAmB;AAChC,IAAC,OAAO,KAAK,KAAK,EAAa,QAAQ,CAAC,MAAM;AAC7C,YAAM,OAAO,MAAM,CAAC;AACpB,aAAO,OAAO,KAAK,CAAC,EAAE;AAAA,IACxB,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,KAAK,QAAQ,OAAO,IAAI;AACnC;;;AClDO,SAAS,mBAAmB,QAAa,QAAa;AAC3D,SAAO,EAAE,QAAQ,OAAO;AAC1B;","names":["z","z"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-contract",
3
3
  "description": "TypeScript contract definitions for RRRoutes",
4
- "version": "2.4.21",
4
+ "version": "2.4.22",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",