@emeryld/rrroutes-contract 2.6.1 → 2.6.3

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.
@@ -35,10 +35,12 @@ type OutputRouteSchema<O extends ZodType | undefined, Meta extends ZodType | und
35
35
  export type FeedQueryField<C extends MethodCfg> = {
36
36
  querySchema: IntersectZod<C['querySchema'], C['queryExtensionSchema']>;
37
37
  };
38
+ type DefaultMetaSchema = z.ZodOptional<z.ZodString>;
39
+ type NormalizeMetaSchema<S> = S extends ZodType ? [S] extends [ZodType] ? [ZodType] extends [S] ? DefaultMetaSchema : S : S : DefaultMetaSchema;
38
40
  export type OutputField<C extends MethodCfg> = {
39
41
  outputSchema: ZodObject<{
40
42
  out: C['outputSchema'] extends ZodType ? C['outputSchema'] : z.ZodOptional<z.ZodUndefined>;
41
- meta: C['outputMetaSchema'] extends ZodType ? C['outputMetaSchema'] : z.ZodOptional<z.ZodString>;
43
+ meta: NormalizeMetaSchema<C['outputMetaSchema']>;
42
44
  }>;
43
45
  };
44
46
  export type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {
@@ -160,7 +162,7 @@ type NodeOutputMeta<Node> = Node extends {
160
162
  outputMetaSchema?: infer OM;
161
163
  } ? OM extends ZodType ? OM : undefined : undefined;
162
164
  type EffectiveQueryExtensionSchema<Method extends ZodType | undefined, Node extends NodeCfg | undefined> = Method extends ZodType ? Method : NodeQueryExtension<Node>;
163
- type EffectiveOutputMetaSchema<Method extends ZodType | undefined, Node extends NodeCfg | undefined> = Method extends ZodType ? Method : NodeOutputMeta<Node>;
165
+ type EffectiveOutputMetaSchema<Method extends ZodType | undefined, Node extends NodeCfg | undefined> = NormalizeMetaSchema<Method extends ZodType ? Method : NodeOutputMeta<Node>>;
164
166
  type SegmentParams<S extends string> = S extends `:${infer P}` ? P : S extends `*${infer P}` ? P : never;
165
167
  type Split<S extends string> = S extends '' ? [] : S extends `${infer A}/${infer B}` ? [A, ...Split<B>] : [S];
166
168
  type ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>;
@@ -224,9 +226,13 @@ export type MethodCfgLowProfile = Omit<MethodCfg, 'bodySchema' | 'querySchema' |
224
226
  };
225
227
  export type AnyLeafLowProfile = LeafLowProfile<HttpMethod, string, MethodCfgLowProfile>;
226
228
  /** Any leaf whose inferred output includes `out` and where that `out` is compatible with `TOut`. */
227
- export type AnyLeafLowProfileWithOut<TOut, L extends AnyLeafLowProfile = AnyLeafLowProfile> = L extends AnyLeafLowProfile ? InferOutput<L> extends {
228
- out: infer O;
229
- } ? O extends TOut ? L : never : never : never;
229
+ export type AnyLeafLowProfileWithOut<TOut> = LeafLowProfile<HttpMethod, string, Prettify<Omit<MethodCfgLowProfile, 'outputSchema'> & {
230
+ outputSchema: RouteSchema<{
231
+ out: TOut;
232
+ meta?: unknown;
233
+ }>;
234
+ }>>;
235
+ export type LeafHasOut<T extends AnyLeafLowProfile, TOut> = T extends AnyLeafLowProfileWithOut<TOut> ? T : never;
230
236
  export declare function buildLowProfileLeaf<const M extends HttpMethod, const Path extends string, const Node extends NodeCfg | undefined = undefined, const O extends ZodType | undefined = undefined, const P extends ZodType | undefined = undefined, const Q extends ZodType | undefined = undefined, const B extends ZodType | undefined = undefined, const FO extends ZodType | undefined = undefined, const FQ extends ZodType | undefined = undefined, const BF extends FileField[] = [], const Feed extends boolean = false>(leaf: {
231
237
  method: M;
232
238
  path: Path;
@@ -265,7 +271,7 @@ export type InferParams<L extends AnyLeafLowProfile, Fallback = never> = L['cfg'
265
271
  /** Infer query shape from a Zod schema when present. */
266
272
  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;
267
273
  /** Infer request body shape from a Zod schema when present. */
268
- 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;
274
+ export type InferBody<L extends AnyLeafLowProfile> = L['cfg']['bodySchema'] extends RouteSchema<infer BOut> ? BOut : never;
269
275
  export type ReactNativeFile = {
270
276
  uri: string;
271
277
  name: string;
@@ -276,18 +282,8 @@ type BodyFilesInputFromDefs<Defs extends readonly FileField[]> = Prettify<{
276
282
  [F in Defs[number] as `file_${F['name']}`]?: UploadFieldValue<F>;
277
283
  }>;
278
284
  /** Infer request body input shape, augmented with multipart file fields when declared. */
279
- export type InferBodyInput<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['bodyFiles'] extends readonly FileField[] ? Prettify<Omit<InferBody<L, Fallback> extends never ? {} : InferBody<L, Fallback>, keyof BodyFilesInputFromDefs<L['cfg']['bodyFiles']>> & BodyFilesInputFromDefs<L['cfg']['bodyFiles']>> : InferBody<L, Fallback>;
280
- /** Infer handler output shape from a Zod schema. Defaults to unknown. */
281
- type InferMetaFromCfg<L extends AnyLeafLowProfile> = L['cfg']['outputMetaSchema'] extends RouteSchema<infer O> ? O : L['cfg']['outputMetaSchema'] extends ZodType<infer O> ? O : string | undefined;
282
- type ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends [never] | [unknown] ? InferMetaFromCfg<L> : M;
283
- type ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {
284
- meta: infer M;
285
- } ? (undefined extends ResolvedMeta<L, M> ? {
286
- meta?: ResolvedMeta<L, M>;
287
- } : {
288
- meta: ResolvedMeta<L, M>;
289
- }) & Omit<O, 'meta'> : O;
290
- export type InferOutput<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['outputSchema'] extends RouteSchema<infer O> ? ApplyMetaFallback<L, O> : Fallback;
285
+ export type InferBodyInput<L extends AnyLeafLowProfile> = L['cfg']['bodyFiles'] extends readonly FileField[] ? (InferBody<L> extends never ? {} : InferBody<L>) & BodyFilesInputFromDefs<L['cfg']['bodyFiles']> : InferBody<L>;
286
+ export type InferOutput<L extends AnyLeafLowProfile> = L['cfg']['outputSchema']['__out'];
291
287
  /** Render a type as if it were a simple object literal. */
292
288
  export type Prettify<T> = {
293
289
  [K in keyof T]: T[K];
package/dist/index.cjs CHANGED
@@ -129,9 +129,10 @@ function buildLowProfileLeaf(leaf) {
129
129
  mergedCfg.querySchema,
130
130
  mergedCfg.queryExtensionSchema
131
131
  );
132
+ const effectiveOutputMetaSchema = mergedCfg.outputMetaSchema ?? import_zod.z.string().optional();
132
133
  const effectiveOutputSchema = import_zod.z.object({
133
134
  out: mergedCfg.outputSchema ?? import_zod.z.undefined().optional(),
134
- meta: mergedCfg.outputMetaSchema ?? import_zod.z.string().optional()
135
+ meta: effectiveOutputMetaSchema
135
136
  });
136
137
  if (mergedCfg.feed === true && effectiveQuerySchema instanceof import_zod.ZodObject) {
137
138
  const shape = getZodShape(effectiveQuerySchema);
@@ -153,7 +154,7 @@ function buildLowProfileLeaf(leaf) {
153
154
  querySchema: effectiveQuerySchema,
154
155
  paramsSchema: mergedCfg.paramsSchema,
155
156
  outputSchema: effectiveOutputSchema,
156
- outputMetaSchema: mergedCfg.outputMetaSchema,
157
+ outputMetaSchema: effectiveOutputMetaSchema,
157
158
  queryExtensionSchema: mergedCfg.queryExtensionSchema
158
159
  }
159
160
  };
@@ -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 FirstSegment<Path extends string> = Path extends `${infer Head}/${string}`\n ? Head\n : Path\ntype StripParamName<Name extends string> =\n FirstSegment<Name> extends `:${infer P}`\n ? P\n : FirstSegment<Name> extends `*${infer P}`\n ? P\n : FirstSegment<Name>\nexport type DynamicBaseSegment = `:${string}` | `*${string}`\nexport type StaticBaseSegment = `/${string}` | ''\ntype StripLeadingSlash<Path extends string> = Path extends `/${infer Rest}`\n ? StripLeadingSlash<Rest>\n : Path\ntype TailAfterFirstSegment<Path extends string> =\n StripLeadingSlash<Path> extends `${string}/${infer Rest}` ? Rest : ''\ntype HasDynamicSegment<Path extends string> =\n Path extends `${infer Head}/${infer Rest}`\n ? Head extends DynamicBaseSegment\n ? true\n : HasDynamicSegment<Rest>\n : Path extends DynamicBaseSegment\n ? true\n : false\n\nexport type NoParamAfterFirstSegment<Path extends string> =\n HasDynamicSegment<TailAfterFirstSegment<Path>> extends true ? never : Path\n\n/**\n * Normalize a static resource base and preserve the `NoParamAfterFirstSegment`\n * type contract for composed/generic template-literal paths.\n */\nexport function staticBase<Path extends StaticBaseSegment>(\n base: Path,\n): NoParamAfterFirstSegment<Path> {\n assertNoDynamicSegmentAfterFirst(base)\n return base as NoParamAfterFirstSegment<Path>\n}\n\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType\n ? Base extends DynamicBaseSegment\n ? Base extends `*${string}`\n ? ParamZod<StripParamName<Base>, z.ZodArray<Param>>\n : ParamZod<StripParamName<Base>, Param>\n : undefined\n : undefined\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 StaticBaseSegment,\n I extends NodeCfg = {},\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined>\nexport function resource<\n Base extends DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType = ZodType,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited: I | undefined,\n idSchema: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>>\nexport function resource<\n Base extends StaticBaseSegment | DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n idSchema?: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>> {\n const rawBase = base as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as Base\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 dynamicLayerMap = new Map<string, string>()\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 assertDynamicLayerUniqueness(leaf.path, dynamicLayerMap)\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,\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 assertDynamicLayerUniqueness(newLeaf.path, dynamicLayerMap)\n stack.push(newLeaf as unknown 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 assertNoDynamicSegmentAfterFirst(base)\n\n if (base.startsWith('/')) {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith(':')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith('*')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base === '') {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n throw new Error('resource() base must start with \"/\", \":\", or \"*\"')\n}\n\nfunction assertNoDynamicSegmentAfterFirst(base: string) {\n const segments = base.split('/').filter(Boolean)\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i]\n if (segment && (segment[0] === ':' || segment[0] === '*')) {\n throw new Error(\n 'resource() base cannot define dynamic params after the first segment',\n )\n }\n }\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const firstSegment = nameSegment.split('/').filter(Boolean)[0] ?? nameSegment\n if (!firstSegment.startsWith(':') && !firstSegment.startsWith('*')) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n const isWildcard = firstSegment.startsWith('*')\n const normalized = firstSegment.slice(1)\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n const paramSchema = isWildcard ? z.array(schema) : schema\n return z.object({ [normalized]: paramSchema } 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\nfunction assertDynamicLayerUniqueness(\n path: string,\n dynamicLayerMap: Map<string, string>,\n) {\n const segments = path.split('/').filter(Boolean)\n if (segments.length === 0) return\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n if (!segment || (segment[0] !== ':' && segment[0] !== '*')) continue\n\n const parentKey = segments.slice(0, i).join('/')\n const existing = dynamicLayerMap.get(parentKey)\n if (existing && existing !== segment) {\n const parentLabel = parentKey ? `/${parentKey}` : '/'\n throw new Error(\n `[routesV3.builder] Multiple dynamic segments under ${parentLabel}: ${existing} and ${segment}`,\n )\n }\n if (!existing) {\n dynamicLayerMap.set(parentKey, segment)\n }\n }\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 = unknown> = {\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<C['querySchema'], C['queryExtensionSchema']>\n}\n\nexport type OutputField<C extends MethodCfg> = {\n outputSchema: ZodObject<{\n out: C['outputSchema'] extends ZodType\n ? C['outputSchema']\n : z.ZodOptional<z.ZodUndefined>\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<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n>(a: A, b: B): IntersectZod<A, B> {\n if (a && b) {\n return z.intersection(a, b) as any\n }\n return (a ?? b) as any\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}`\n ? P\n : S extends `*${infer P}`\n ? P\n : 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\ntype SegmentParamRecord<S extends string> = S extends `:${infer P}`\n ? Record<P, string | number>\n : S extends `*${infer P}`\n ? Record<P, (string | number)[]>\n : {}\n\ntype ParamsFromSegments<Segments extends readonly string[]> = Segments extends [\n infer Head,\n ...infer Rest,\n]\n ? Head extends string\n ? Rest extends readonly string[]\n ? SegmentParamRecord<Head> & ParamsFromSegments<Rest>\n : SegmentParamRecord<Head>\n : {}\n : {}\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 : ParamsFromSegments<Split<Path>>\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 const withParams = 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 return withParams.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 if (!Array.isArray(v)) {\n throw new Error(`Param *${k} must be an array`)\n }\n return v.map((item) => String(item)).join('/')\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 : A extends `*${infer Key}`\n ? [\n ParamValue<Params, Key>,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\n ]\n : [\n A,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\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 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 if (value !== undefined && value !== null && !Array.isArray(value)) {\n throw new Error(`Param *${paramName} must be an array`)\n }\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 | 'bodyFiles'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n bodyFiles?: FileField[]\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n/** Any leaf whose inferred output includes `out` and where that `out` is compatible with `TOut`. */\nexport type AnyLeafLowProfileWithOut<\n TOut,\n L extends AnyLeafLowProfile = AnyLeafLowProfile,\n> = L extends AnyLeafLowProfile\n ? InferOutput<L> extends { out: infer O }\n ? O extends TOut\n ? L\n : never\n : never\n : never\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 BF extends FileField[] = [],\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 | 'bodyFiles'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n bodyFiles?: BF\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 | 'bodyFiles'\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 bodyFiles: BF\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 = mergeSchemas(\n mergedCfg.querySchema,\n mergedCfg.queryExtensionSchema,\n )\n const effectiveOutputSchema = z.object({\n out: mergedCfg.outputSchema ?? z.undefined().optional(),\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 any as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as RouteSchema<any>,\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\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\nexport type ReactNativeFile = {\n uri: string // e.g. file:///...\n name: string // e.g. avatar.jpg\n type: string // e.g. image/jpeg\n}\ntype UploadFieldValue<F extends FileField> = F['maxCount'] extends 1\n ? Blob | File | ReactNativeFile\n : (Blob | File | ReactNativeFile)[] | FileList\n\ntype BodyFilesInputFromDefs<Defs extends readonly FileField[]> = Prettify<{\n [F in Defs[number] as `file_${F['name']}`]?: UploadFieldValue<F>\n}>\n\n/** Infer request body input shape, augmented with multipart file fields when declared. */\nexport type InferBodyInput<\n L extends AnyLeafLowProfile,\n Fallback = never,\n> = L['cfg']['bodyFiles'] extends readonly FileField[]\n ? Prettify<\n Omit<\n InferBody<L, Fallback> extends never ? {} : InferBody<L, Fallback>,\n keyof BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n > &\n BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n >\n : InferBody<L, 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 : 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 FirstSegment<Path extends string> = Path extends `${infer Head}/${string}`\n ? Head\n : Path\ntype StripParamName<Name extends string> =\n FirstSegment<Name> extends `:${infer P}`\n ? P\n : FirstSegment<Name> extends `*${infer P}`\n ? P\n : FirstSegment<Name>\nexport type DynamicBaseSegment = `:${string}` | `*${string}`\nexport type StaticBaseSegment = `/${string}` | ''\ntype StripLeadingSlash<Path extends string> = Path extends `/${infer Rest}`\n ? StripLeadingSlash<Rest>\n : Path\ntype TailAfterFirstSegment<Path extends string> =\n StripLeadingSlash<Path> extends `${string}/${infer Rest}` ? Rest : ''\ntype HasDynamicSegment<Path extends string> =\n Path extends `${infer Head}/${infer Rest}`\n ? Head extends DynamicBaseSegment\n ? true\n : HasDynamicSegment<Rest>\n : Path extends DynamicBaseSegment\n ? true\n : false\n\nexport type NoParamAfterFirstSegment<Path extends string> =\n HasDynamicSegment<TailAfterFirstSegment<Path>> extends true ? never : Path\n\n/**\n * Normalize a static resource base and preserve the `NoParamAfterFirstSegment`\n * type contract for composed/generic template-literal paths.\n */\nexport function staticBase<Path extends StaticBaseSegment>(\n base: Path,\n): NoParamAfterFirstSegment<Path> {\n assertNoDynamicSegmentAfterFirst(base)\n return base as NoParamAfterFirstSegment<Path>\n}\n\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType\n ? Base extends DynamicBaseSegment\n ? Base extends `*${string}`\n ? ParamZod<StripParamName<Base>, z.ZodArray<Param>>\n : ParamZod<StripParamName<Base>, Param>\n : undefined\n : undefined\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 StaticBaseSegment,\n I extends NodeCfg = {},\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined>\nexport function resource<\n Base extends DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType = ZodType,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited: I | undefined,\n idSchema: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>>\nexport function resource<\n Base extends StaticBaseSegment | DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n idSchema?: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>> {\n const rawBase = base as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as Base\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 dynamicLayerMap = new Map<string, string>()\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 assertDynamicLayerUniqueness(leaf.path, dynamicLayerMap)\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,\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 assertDynamicLayerUniqueness(newLeaf.path, dynamicLayerMap)\n stack.push(newLeaf as unknown 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 assertNoDynamicSegmentAfterFirst(base)\n\n if (base.startsWith('/')) {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith(':')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith('*')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base === '') {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n throw new Error('resource() base must start with \"/\", \":\", or \"*\"')\n}\n\nfunction assertNoDynamicSegmentAfterFirst(base: string) {\n const segments = base.split('/').filter(Boolean)\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i]\n if (segment && (segment[0] === ':' || segment[0] === '*')) {\n throw new Error(\n 'resource() base cannot define dynamic params after the first segment',\n )\n }\n }\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const firstSegment = nameSegment.split('/').filter(Boolean)[0] ?? nameSegment\n if (!firstSegment.startsWith(':') && !firstSegment.startsWith('*')) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n const isWildcard = firstSegment.startsWith('*')\n const normalized = firstSegment.slice(1)\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n const paramSchema = isWildcard ? z.array(schema) : schema\n return z.object({ [normalized]: paramSchema } 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\nfunction assertDynamicLayerUniqueness(\n path: string,\n dynamicLayerMap: Map<string, string>,\n) {\n const segments = path.split('/').filter(Boolean)\n if (segments.length === 0) return\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n if (!segment || (segment[0] !== ':' && segment[0] !== '*')) continue\n\n const parentKey = segments.slice(0, i).join('/')\n const existing = dynamicLayerMap.get(parentKey)\n if (existing && existing !== segment) {\n const parentLabel = parentKey ? `/${parentKey}` : '/'\n throw new Error(\n `[routesV3.builder] Multiple dynamic segments under ${parentLabel}: ${existing} and ${segment}`,\n )\n }\n if (!existing) {\n dynamicLayerMap.set(parentKey, segment)\n }\n }\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 = unknown> = {\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<C['querySchema'], C['queryExtensionSchema']>\n}\n\ntype DefaultMetaSchema = z.ZodOptional<z.ZodString>\n\ntype NormalizeMetaSchema<S> = S extends ZodType\n ? [S] extends [ZodType]\n ? [ZodType] extends [S]\n ? DefaultMetaSchema\n : S\n : S\n : DefaultMetaSchema\n\nexport type OutputField<C extends MethodCfg> = {\n outputSchema: ZodObject<{\n out: C['outputSchema'] extends ZodType\n ? C['outputSchema']\n : z.ZodOptional<z.ZodUndefined>\n meta: NormalizeMetaSchema<C['outputMetaSchema']>\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<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n>(a: A, b: B): IntersectZod<A, B> {\n if (a && b) {\n return z.intersection(a, b) as any\n }\n return (a ?? b) as any\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> = NormalizeMetaSchema<Method extends ZodType ? Method : NodeOutputMeta<Node>>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}`\n ? P\n : S extends `*${infer P}`\n ? P\n : 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\ntype SegmentParamRecord<S extends string> = S extends `:${infer P}`\n ? Record<P, string | number>\n : S extends `*${infer P}`\n ? Record<P, (string | number)[]>\n : {}\n\ntype ParamsFromSegments<Segments extends readonly string[]> = Segments extends [\n infer Head,\n ...infer Rest,\n]\n ? Head extends string\n ? Rest extends readonly string[]\n ? SegmentParamRecord<Head> & ParamsFromSegments<Rest>\n : SegmentParamRecord<Head>\n : {}\n : {}\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 : ParamsFromSegments<Split<Path>>\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 const withParams = 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 return withParams.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 if (!Array.isArray(v)) {\n throw new Error(`Param *${k} must be an array`)\n }\n return v.map((item) => String(item)).join('/')\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 : A extends `*${infer Key}`\n ? [\n ParamValue<Params, Key>,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\n ]\n : [\n A,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\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 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 if (value !== undefined && value !== null && !Array.isArray(value)) {\n throw new Error(`Param *${paramName} must be an array`)\n }\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 | 'bodyFiles'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n bodyFiles?: FileField[]\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n/** Any leaf whose inferred output includes `out` and where that `out` is compatible with `TOut`. */\nexport type AnyLeafLowProfileWithOut<TOut> = LeafLowProfile<\n HttpMethod,\n string,\n Prettify<\n Omit<MethodCfgLowProfile, 'outputSchema'> & {\n outputSchema: RouteSchema<{\n out: TOut\n meta?: unknown\n }>\n }\n >\n>\n\nexport type LeafHasOut<T extends AnyLeafLowProfile, TOut> =\n T extends AnyLeafLowProfileWithOut<TOut> ? T : never\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 BF extends FileField[] = [],\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 | 'bodyFiles'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n bodyFiles?: BF\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 | 'bodyFiles'\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 bodyFiles: BF\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 = mergeSchemas(\n mergedCfg.querySchema,\n mergedCfg.queryExtensionSchema,\n )\n const effectiveOutputMetaSchema =\n mergedCfg.outputMetaSchema ?? z.string().optional()\n const effectiveOutputSchema = z.object({\n out: mergedCfg.outputSchema ?? z.undefined().optional(),\n meta: effectiveOutputMetaSchema,\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 any as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as RouteSchema<any>,\n outputMetaSchema: effectiveOutputMetaSchema as RouteSchema<any>,\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\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> =\n L['cfg']['bodySchema'] extends RouteSchema<infer BOut> ? BOut : never\n\nexport type ReactNativeFile = {\n uri: string // e.g. file:///...\n name: string // e.g. avatar.jpg\n type: string // e.g. image/jpeg\n}\ntype UploadFieldValue<F extends FileField> = F['maxCount'] extends 1\n ? Blob | File | ReactNativeFile\n : (Blob | File | ReactNativeFile)[] | FileList\n\ntype BodyFilesInputFromDefs<Defs extends readonly FileField[]> = Prettify<{\n [F in Defs[number] as `file_${F['name']}`]?: UploadFieldValue<F>\n}>\n\n/** Infer request body input shape, augmented with multipart file fields when declared. */\nexport type InferBodyInput<L extends AnyLeafLowProfile> =\n L['cfg']['bodyFiles'] extends readonly FileField[]\n ? (InferBody<L> extends never ? {} : InferBody<L>) &\n BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n : InferBody<L>\n\nexport type InferOutput<L extends AnyLeafLowProfile> =\n L['cfg']['outputSchema']['__out']\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"]}
package/dist/index.mjs CHANGED
@@ -89,9 +89,10 @@ function buildLowProfileLeaf(leaf) {
89
89
  mergedCfg.querySchema,
90
90
  mergedCfg.queryExtensionSchema
91
91
  );
92
+ const effectiveOutputMetaSchema = mergedCfg.outputMetaSchema ?? z.string().optional();
92
93
  const effectiveOutputSchema = z.object({
93
94
  out: mergedCfg.outputSchema ?? z.undefined().optional(),
94
- meta: mergedCfg.outputMetaSchema ?? z.string().optional()
95
+ meta: effectiveOutputMetaSchema
95
96
  });
96
97
  if (mergedCfg.feed === true && effectiveQuerySchema instanceof ZodObject) {
97
98
  const shape = getZodShape(effectiveQuerySchema);
@@ -113,7 +114,7 @@ function buildLowProfileLeaf(leaf) {
113
114
  querySchema: effectiveQuerySchema,
114
115
  paramsSchema: mergedCfg.paramsSchema,
115
116
  outputSchema: effectiveOutputSchema,
116
- outputMetaSchema: mergedCfg.outputMetaSchema,
117
+ outputMetaSchema: effectiveOutputMetaSchema,
117
118
  queryExtensionSchema: mergedCfg.queryExtensionSchema
118
119
  }
119
120
  };
@@ -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 FirstSegment<Path extends string> = Path extends `${infer Head}/${string}`\n ? Head\n : Path\ntype StripParamName<Name extends string> =\n FirstSegment<Name> extends `:${infer P}`\n ? P\n : FirstSegment<Name> extends `*${infer P}`\n ? P\n : FirstSegment<Name>\nexport type DynamicBaseSegment = `:${string}` | `*${string}`\nexport type StaticBaseSegment = `/${string}` | ''\ntype StripLeadingSlash<Path extends string> = Path extends `/${infer Rest}`\n ? StripLeadingSlash<Rest>\n : Path\ntype TailAfterFirstSegment<Path extends string> =\n StripLeadingSlash<Path> extends `${string}/${infer Rest}` ? Rest : ''\ntype HasDynamicSegment<Path extends string> =\n Path extends `${infer Head}/${infer Rest}`\n ? Head extends DynamicBaseSegment\n ? true\n : HasDynamicSegment<Rest>\n : Path extends DynamicBaseSegment\n ? true\n : false\n\nexport type NoParamAfterFirstSegment<Path extends string> =\n HasDynamicSegment<TailAfterFirstSegment<Path>> extends true ? never : Path\n\n/**\n * Normalize a static resource base and preserve the `NoParamAfterFirstSegment`\n * type contract for composed/generic template-literal paths.\n */\nexport function staticBase<Path extends StaticBaseSegment>(\n base: Path,\n): NoParamAfterFirstSegment<Path> {\n assertNoDynamicSegmentAfterFirst(base)\n return base as NoParamAfterFirstSegment<Path>\n}\n\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType\n ? Base extends DynamicBaseSegment\n ? Base extends `*${string}`\n ? ParamZod<StripParamName<Base>, z.ZodArray<Param>>\n : ParamZod<StripParamName<Base>, Param>\n : undefined\n : undefined\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 StaticBaseSegment,\n I extends NodeCfg = {},\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined>\nexport function resource<\n Base extends DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType = ZodType,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited: I | undefined,\n idSchema: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>>\nexport function resource<\n Base extends StaticBaseSegment | DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n idSchema?: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>> {\n const rawBase = base as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as Base\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 dynamicLayerMap = new Map<string, string>()\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 assertDynamicLayerUniqueness(leaf.path, dynamicLayerMap)\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,\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 assertDynamicLayerUniqueness(newLeaf.path, dynamicLayerMap)\n stack.push(newLeaf as unknown 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 assertNoDynamicSegmentAfterFirst(base)\n\n if (base.startsWith('/')) {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith(':')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith('*')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base === '') {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n throw new Error('resource() base must start with \"/\", \":\", or \"*\"')\n}\n\nfunction assertNoDynamicSegmentAfterFirst(base: string) {\n const segments = base.split('/').filter(Boolean)\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i]\n if (segment && (segment[0] === ':' || segment[0] === '*')) {\n throw new Error(\n 'resource() base cannot define dynamic params after the first segment',\n )\n }\n }\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const firstSegment = nameSegment.split('/').filter(Boolean)[0] ?? nameSegment\n if (!firstSegment.startsWith(':') && !firstSegment.startsWith('*')) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n const isWildcard = firstSegment.startsWith('*')\n const normalized = firstSegment.slice(1)\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n const paramSchema = isWildcard ? z.array(schema) : schema\n return z.object({ [normalized]: paramSchema } 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\nfunction assertDynamicLayerUniqueness(\n path: string,\n dynamicLayerMap: Map<string, string>,\n) {\n const segments = path.split('/').filter(Boolean)\n if (segments.length === 0) return\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n if (!segment || (segment[0] !== ':' && segment[0] !== '*')) continue\n\n const parentKey = segments.slice(0, i).join('/')\n const existing = dynamicLayerMap.get(parentKey)\n if (existing && existing !== segment) {\n const parentLabel = parentKey ? `/${parentKey}` : '/'\n throw new Error(\n `[routesV3.builder] Multiple dynamic segments under ${parentLabel}: ${existing} and ${segment}`,\n )\n }\n if (!existing) {\n dynamicLayerMap.set(parentKey, segment)\n }\n }\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 = unknown> = {\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<C['querySchema'], C['queryExtensionSchema']>\n}\n\nexport type OutputField<C extends MethodCfg> = {\n outputSchema: ZodObject<{\n out: C['outputSchema'] extends ZodType\n ? C['outputSchema']\n : z.ZodOptional<z.ZodUndefined>\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<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n>(a: A, b: B): IntersectZod<A, B> {\n if (a && b) {\n return z.intersection(a, b) as any\n }\n return (a ?? b) as any\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}`\n ? P\n : S extends `*${infer P}`\n ? P\n : 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\ntype SegmentParamRecord<S extends string> = S extends `:${infer P}`\n ? Record<P, string | number>\n : S extends `*${infer P}`\n ? Record<P, (string | number)[]>\n : {}\n\ntype ParamsFromSegments<Segments extends readonly string[]> = Segments extends [\n infer Head,\n ...infer Rest,\n]\n ? Head extends string\n ? Rest extends readonly string[]\n ? SegmentParamRecord<Head> & ParamsFromSegments<Rest>\n : SegmentParamRecord<Head>\n : {}\n : {}\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 : ParamsFromSegments<Split<Path>>\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 const withParams = 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 return withParams.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 if (!Array.isArray(v)) {\n throw new Error(`Param *${k} must be an array`)\n }\n return v.map((item) => String(item)).join('/')\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 : A extends `*${infer Key}`\n ? [\n ParamValue<Params, Key>,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\n ]\n : [\n A,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\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 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 if (value !== undefined && value !== null && !Array.isArray(value)) {\n throw new Error(`Param *${paramName} must be an array`)\n }\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 | 'bodyFiles'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n bodyFiles?: FileField[]\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n/** Any leaf whose inferred output includes `out` and where that `out` is compatible with `TOut`. */\nexport type AnyLeafLowProfileWithOut<\n TOut,\n L extends AnyLeafLowProfile = AnyLeafLowProfile,\n> = L extends AnyLeafLowProfile\n ? InferOutput<L> extends { out: infer O }\n ? O extends TOut\n ? L\n : never\n : never\n : never\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 BF extends FileField[] = [],\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 | 'bodyFiles'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n bodyFiles?: BF\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 | 'bodyFiles'\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 bodyFiles: BF\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 = mergeSchemas(\n mergedCfg.querySchema,\n mergedCfg.queryExtensionSchema,\n )\n const effectiveOutputSchema = z.object({\n out: mergedCfg.outputSchema ?? z.undefined().optional(),\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 any as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as RouteSchema<any>,\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\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\nexport type ReactNativeFile = {\n uri: string // e.g. file:///...\n name: string // e.g. avatar.jpg\n type: string // e.g. image/jpeg\n}\ntype UploadFieldValue<F extends FileField> = F['maxCount'] extends 1\n ? Blob | File | ReactNativeFile\n : (Blob | File | ReactNativeFile)[] | FileList\n\ntype BodyFilesInputFromDefs<Defs extends readonly FileField[]> = Prettify<{\n [F in Defs[number] as `file_${F['name']}`]?: UploadFieldValue<F>\n}>\n\n/** Infer request body input shape, augmented with multipart file fields when declared. */\nexport type InferBodyInput<\n L extends AnyLeafLowProfile,\n Fallback = never,\n> = L['cfg']['bodyFiles'] extends readonly FileField[]\n ? Prettify<\n Omit<\n InferBody<L, Fallback> extends never ? {} : InferBody<L, Fallback>,\n keyof BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n > &\n BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n >\n : InferBody<L, 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 : 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 FirstSegment<Path extends string> = Path extends `${infer Head}/${string}`\n ? Head\n : Path\ntype StripParamName<Name extends string> =\n FirstSegment<Name> extends `:${infer P}`\n ? P\n : FirstSegment<Name> extends `*${infer P}`\n ? P\n : FirstSegment<Name>\nexport type DynamicBaseSegment = `:${string}` | `*${string}`\nexport type StaticBaseSegment = `/${string}` | ''\ntype StripLeadingSlash<Path extends string> = Path extends `/${infer Rest}`\n ? StripLeadingSlash<Rest>\n : Path\ntype TailAfterFirstSegment<Path extends string> =\n StripLeadingSlash<Path> extends `${string}/${infer Rest}` ? Rest : ''\ntype HasDynamicSegment<Path extends string> =\n Path extends `${infer Head}/${infer Rest}`\n ? Head extends DynamicBaseSegment\n ? true\n : HasDynamicSegment<Rest>\n : Path extends DynamicBaseSegment\n ? true\n : false\n\nexport type NoParamAfterFirstSegment<Path extends string> =\n HasDynamicSegment<TailAfterFirstSegment<Path>> extends true ? never : Path\n\n/**\n * Normalize a static resource base and preserve the `NoParamAfterFirstSegment`\n * type contract for composed/generic template-literal paths.\n */\nexport function staticBase<Path extends StaticBaseSegment>(\n base: Path,\n): NoParamAfterFirstSegment<Path> {\n assertNoDynamicSegmentAfterFirst(base)\n return base as NoParamAfterFirstSegment<Path>\n}\n\ntype ParamSchemaForBase<\n Base extends string,\n Param extends ZodType | undefined,\n> = Param extends ZodType\n ? Base extends DynamicBaseSegment\n ? Base extends `*${string}`\n ? ParamZod<StripParamName<Base>, z.ZodArray<Param>>\n : ParamZod<StripParamName<Base>, Param>\n : undefined\n : undefined\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 StaticBaseSegment,\n I extends NodeCfg = {},\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined>\nexport function resource<\n Base extends DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType = ZodType,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited: I | undefined,\n idSchema: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>>\nexport function resource<\n Base extends StaticBaseSegment | DynamicBaseSegment,\n I extends NodeCfg = {},\n Param extends ZodType | undefined = undefined,\n>(\n base: NoParamAfterFirstSegment<Base>,\n inherited?: I,\n idSchema?: Param,\n): Branch<Base, readonly [], I, ParamSchemaForBase<Base, Param>> {\n const rawBase = base as Base\n const normalizedBase = normalizeBaseSegment(\n rawBase,\n Boolean(idSchema),\n ) as Base\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 dynamicLayerMap = new Map<string, string>()\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 assertDynamicLayerUniqueness(leaf.path, dynamicLayerMap)\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,\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 assertDynamicLayerUniqueness(newLeaf.path, dynamicLayerMap)\n stack.push(newLeaf as unknown 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 assertNoDynamicSegmentAfterFirst(base)\n\n if (base.startsWith('/')) {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith(':')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base.startsWith('*')) {\n if (!hasParam) {\n throw new Error(\n 'resource() requires idSchema for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n if (base === '') {\n if (hasParam) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n return base\n }\n throw new Error('resource() base must start with \"/\", \":\", or \"*\"')\n}\n\nfunction assertNoDynamicSegmentAfterFirst(base: string) {\n const segments = base.split('/').filter(Boolean)\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i]\n if (segment && (segment[0] === ':' || segment[0] === '*')) {\n throw new Error(\n 'resource() base cannot define dynamic params after the first segment',\n )\n }\n }\n}\n\nfunction createParamSchema(nameSegment: string, schema?: ZodType) {\n if (!schema) return undefined\n const firstSegment = nameSegment.split('/').filter(Boolean)[0] ?? nameSegment\n if (!firstSegment.startsWith(':') && !firstSegment.startsWith('*')) {\n throw new Error(\n 'resource() idSchema is only allowed for dynamic base segments (\":param\" or \"*param\")',\n )\n }\n const isWildcard = firstSegment.startsWith('*')\n const normalized = firstSegment.slice(1)\n if (!normalized) {\n throw new Error('resource() requires a non-empty name for id schema')\n }\n const paramSchema = isWildcard ? z.array(schema) : schema\n return z.object({ [normalized]: paramSchema } 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\nfunction assertDynamicLayerUniqueness(\n path: string,\n dynamicLayerMap: Map<string, string>,\n) {\n const segments = path.split('/').filter(Boolean)\n if (segments.length === 0) return\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n if (!segment || (segment[0] !== ':' && segment[0] !== '*')) continue\n\n const parentKey = segments.slice(0, i).join('/')\n const existing = dynamicLayerMap.get(parentKey)\n if (existing && existing !== segment) {\n const parentLabel = parentKey ? `/${parentKey}` : '/'\n throw new Error(\n `[routesV3.builder] Multiple dynamic segments under ${parentLabel}: ${existing} and ${segment}`,\n )\n }\n if (!existing) {\n dynamicLayerMap.set(parentKey, segment)\n }\n }\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 = unknown> = {\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<C['querySchema'], C['queryExtensionSchema']>\n}\n\ntype DefaultMetaSchema = z.ZodOptional<z.ZodString>\n\ntype NormalizeMetaSchema<S> = S extends ZodType\n ? [S] extends [ZodType]\n ? [ZodType] extends [S]\n ? DefaultMetaSchema\n : S\n : S\n : DefaultMetaSchema\n\nexport type OutputField<C extends MethodCfg> = {\n outputSchema: ZodObject<{\n out: C['outputSchema'] extends ZodType\n ? C['outputSchema']\n : z.ZodOptional<z.ZodUndefined>\n meta: NormalizeMetaSchema<C['outputMetaSchema']>\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<\n A extends ZodType | undefined,\n B extends ZodType | undefined,\n>(a: A, b: B): IntersectZod<A, B> {\n if (a && b) {\n return z.intersection(a, b) as any\n }\n return (a ?? b) as any\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> = NormalizeMetaSchema<Method extends ZodType ? Method : NodeOutputMeta<Node>>\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}`\n ? P\n : S extends `*${infer P}`\n ? P\n : 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\ntype SegmentParamRecord<S extends string> = S extends `:${infer P}`\n ? Record<P, string | number>\n : S extends `*${infer P}`\n ? Record<P, (string | number)[]>\n : {}\n\ntype ParamsFromSegments<Segments extends readonly string[]> = Segments extends [\n infer Head,\n ...infer Rest,\n]\n ? Head extends string\n ? Rest extends readonly string[]\n ? SegmentParamRecord<Head> & ParamsFromSegments<Rest>\n : SegmentParamRecord<Head>\n : {}\n : {}\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 : ParamsFromSegments<Split<Path>>\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 const withParams = 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 return withParams.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 if (!Array.isArray(v)) {\n throw new Error(`Param *${k} must be an array`)\n }\n return v.map((item) => String(item)).join('/')\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 : A extends `*${infer Key}`\n ? [\n ParamValue<Params, Key>,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\n ]\n : [\n A,\n ...MapKeySegments<\n Rest extends readonly string[] ? Rest : [],\n Params\n >,\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 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 if (value !== undefined && value !== null && !Array.isArray(value)) {\n throw new Error(`Param *${paramName} must be an array`)\n }\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 | 'bodyFiles'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema: RouteSchema\n outputMetaSchema?: RouteSchema\n queryExtensionSchema?: RouteSchema\n bodyFiles?: FileField[]\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\n/** Any leaf whose inferred output includes `out` and where that `out` is compatible with `TOut`. */\nexport type AnyLeafLowProfileWithOut<TOut> = LeafLowProfile<\n HttpMethod,\n string,\n Prettify<\n Omit<MethodCfgLowProfile, 'outputSchema'> & {\n outputSchema: RouteSchema<{\n out: TOut\n meta?: unknown\n }>\n }\n >\n>\n\nexport type LeafHasOut<T extends AnyLeafLowProfile, TOut> =\n T extends AnyLeafLowProfileWithOut<TOut> ? T : never\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 BF extends FileField[] = [],\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 | 'bodyFiles'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n outputMetaSchema?: FO\n queryExtensionSchema?: FQ\n bodyFiles?: BF\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 | 'bodyFiles'\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 bodyFiles: BF\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 = mergeSchemas(\n mergedCfg.querySchema,\n mergedCfg.queryExtensionSchema,\n )\n const effectiveOutputMetaSchema =\n mergedCfg.outputMetaSchema ?? z.string().optional()\n const effectiveOutputSchema = z.object({\n out: mergedCfg.outputSchema ?? z.undefined().optional(),\n meta: effectiveOutputMetaSchema,\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 any as RouteSchema<any> | undefined,\n paramsSchema: mergedCfg.paramsSchema as RouteSchema<any> | undefined,\n outputSchema: effectiveOutputSchema as any as RouteSchema<any>,\n outputMetaSchema: effectiveOutputMetaSchema as RouteSchema<any>,\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\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> =\n L['cfg']['bodySchema'] extends RouteSchema<infer BOut> ? BOut : never\n\nexport type ReactNativeFile = {\n uri: string // e.g. file:///...\n name: string // e.g. avatar.jpg\n type: string // e.g. image/jpeg\n}\ntype UploadFieldValue<F extends FileField> = F['maxCount'] extends 1\n ? Blob | File | ReactNativeFile\n : (Blob | File | ReactNativeFile)[] | FileList\n\ntype BodyFilesInputFromDefs<Defs extends readonly FileField[]> = Prettify<{\n [F in Defs[number] as `file_${F['name']}`]?: UploadFieldValue<F>\n}>\n\n/** Infer request body input shape, augmented with multipart file fields when declared. */\nexport type InferBodyInput<L extends AnyLeafLowProfile> =\n L['cfg']['bodyFiles'] extends readonly FileField[]\n ? (InferBody<L> extends never ? {} : InferBody<L>) &\n BodyFilesInputFromDefs<L['cfg']['bodyFiles']>\n : InferBody<L>\n\nexport type InferOutput<L extends AnyLeafLowProfile> =\n L['cfg']['outputSchema']['__out']\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"]}
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.6.1",
4
+ "version": "2.6.3",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",