@emeryld/rrroutes-contract 2.4.0 → 2.4.2
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.
- package/dist/core/routesV3.core.d.ts +3 -10
- package/dist/core/routesV3.finalize.d.ts +17 -18
- package/dist/index.cjs +41 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +41 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { z, ZodType } from 'zod';
|
|
2
|
-
export declare const paramsOverrideSymbol: unique symbol;
|
|
3
|
-
export type ParamsOverrideSymbol = typeof paramsOverrideSymbol;
|
|
4
2
|
/** Supported HTTP verbs for the routes DSL. */
|
|
5
3
|
export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
6
4
|
/** Declarative description of a multipart upload field. */
|
|
@@ -35,7 +33,7 @@ export type MethodCfg = {
|
|
|
35
33
|
bodySchema?: ZodType;
|
|
36
34
|
/** Zod schema describing the query string. */
|
|
37
35
|
querySchema?: ZodType;
|
|
38
|
-
/** Zod schema describing path params (
|
|
36
|
+
/** Zod schema describing path params (Internal only, set through sub and routeParameter). */
|
|
39
37
|
paramsSchema?: ZodType;
|
|
40
38
|
/** Zod schema describing the response payload. */
|
|
41
39
|
outputSchema?: ZodType;
|
|
@@ -79,8 +77,6 @@ export type MethodCfg = {
|
|
|
79
77
|
* Can be used for auth requirements, rate limits, feature flags, etc.
|
|
80
78
|
*/
|
|
81
79
|
docsMeta?: Record<string, unknown>;
|
|
82
|
-
/** @internal flag used to track whether paramsSchema was explicitly provided. */
|
|
83
|
-
[paramsOverrideSymbol]?: true;
|
|
84
80
|
};
|
|
85
81
|
/** Immutable representation of a single HTTP route in the tree. */
|
|
86
82
|
export type Leaf<M extends HttpMethod, P extends string, C extends MethodCfg> = {
|
|
@@ -102,12 +98,9 @@ export type MergeArray<A extends readonly unknown[], B extends readonly unknown[
|
|
|
102
98
|
export type IntersectZod<A extends ZodType | undefined, B extends ZodType | undefined> = B extends ZodType ? A extends ZodType ? z.ZodIntersection<A, B> : B : A extends ZodType ? A : undefined;
|
|
103
99
|
type RouteSchemaFromZod<T extends ZodType | undefined> = T extends ZodType ? RouteSchema<z.output<T>> : undefined;
|
|
104
100
|
type MergeRouteSchemas<Existing extends RouteSchema | undefined, Parent extends ZodType | undefined> = Existing extends RouteSchema<infer ExistingOut> ? Parent extends ZodType ? RouteSchema<ExistingOut & z.output<Parent>> : Existing : Parent extends ZodType ? RouteSchemaFromZod<Parent> : undefined;
|
|
105
|
-
type AugmentedCfg<Cfg extends MethodCfgLowProfile, Param extends ZodType | undefined> = Prettify<Omit<Cfg, 'paramsSchema'> &
|
|
106
|
-
paramsSchema: Cfg['paramsSchema'];
|
|
107
|
-
[paramsOverrideSymbol]: true;
|
|
108
|
-
} : {
|
|
101
|
+
type AugmentedCfg<Cfg extends MethodCfgLowProfile, Param extends ZodType | undefined> = Prettify<Omit<Cfg, 'paramsSchema'> & {
|
|
109
102
|
paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>;
|
|
110
|
-
}
|
|
103
|
+
}>;
|
|
111
104
|
export type AugmentLeaves<P extends string, Param extends ZodType | undefined, R extends readonly LeafLowProfile[], Acc extends readonly LeafLowProfile[] = []> = R extends readonly [infer First, ...infer Rest] ? First extends LeafLowProfile ? AugmentLeaves<P, Param, Rest extends readonly LeafLowProfile[] ? Rest : [], Append<Acc, LeafLowProfile<First['method'], `${P}${First['path']}`, AugmentedCfg<First['cfg'], Param>>>> : never : Acc;
|
|
112
105
|
type SegmentParams<S extends string> = S extends `:${infer P}` ? P : never;
|
|
113
106
|
type Split<S extends string> = S extends '' ? [] : S extends `${infer A}/${infer B}` ? [A, ...Split<B>] : [S];
|
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
import { AnyLeafLowProfile, HttpMethod } from './routesV3.core';
|
|
1
|
+
import { AnyLeafLowProfile, HttpMethod, Prettify } from './routesV3.core';
|
|
2
2
|
/** Build the key type for a leaf — distributive so method/path stay paired. */
|
|
3
3
|
export type KeyOf<L extends AnyLeafLowProfile> = L extends AnyLeafLowProfile ? `${Uppercase<L['method']>} ${L['path']}` : never;
|
|
4
|
+
type KeysOf<Leaves extends readonly AnyLeafLowProfile[]> = KeyOf<Leaves[number]>;
|
|
4
5
|
type MethodFromKey<K extends string> = K extends `${infer M} ${string}` ? Lowercase<M> : never;
|
|
5
6
|
type PathFromKey<K extends string> = K extends `${string} ${infer P}` ? P : never;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export declare function finalize<const L extends readonly AnyLeafLowProfile[]>(leaves: L): {
|
|
12
|
-
all: L;
|
|
13
|
-
byKey: { [K in KeyOf<L[number]>]: Extract<L[number], {
|
|
14
|
-
method: MethodFromKey<K> & HttpMethod;
|
|
15
|
-
path: PathFromKey<K>;
|
|
16
|
-
}> extends infer T ? { [K_1 in keyof T]: T[K_1]; } : never; };
|
|
17
|
-
log: (logger: {
|
|
18
|
-
system: (...args: unknown[]) => void;
|
|
19
|
-
}) => void;
|
|
20
|
-
};
|
|
21
|
-
/** Nominal type alias for a finalized registry. */
|
|
22
|
-
export type Registry<R extends ReturnType<typeof finalize>> = R;
|
|
7
|
+
type LeafForKey<Leaves extends readonly AnyLeafLowProfile[], K extends string> = Extract<Leaves[number], {
|
|
8
|
+
method: MethodFromKey<K> & HttpMethod;
|
|
9
|
+
path: PathFromKey<K>;
|
|
10
|
+
}>;
|
|
23
11
|
type FilterRoute<T extends readonly AnyLeafLowProfile[], F extends string, Acc extends readonly AnyLeafLowProfile[] = []> = T extends readonly [
|
|
24
12
|
infer First extends AnyLeafLowProfile,
|
|
25
13
|
...infer Rest extends AnyLeafLowProfile[]
|
|
@@ -43,4 +31,15 @@ export type SubsetRoutes<T extends readonly AnyLeafLowProfile[], F extends strin
|
|
|
43
31
|
byKey: ByKey<Routes<T, F>>;
|
|
44
32
|
all: Routes<T, F>;
|
|
45
33
|
};
|
|
34
|
+
export interface FinalizedRegistry<L extends readonly AnyLeafLowProfile[]> {
|
|
35
|
+
all: L;
|
|
36
|
+
byKey: {
|
|
37
|
+
[K in KeysOf<L>]: Prettify<LeafForKey<L, K>>;
|
|
38
|
+
};
|
|
39
|
+
log(logger: {
|
|
40
|
+
system: (...args: unknown[]) => void;
|
|
41
|
+
}): void;
|
|
42
|
+
}
|
|
43
|
+
export type Registry<L extends readonly AnyLeafLowProfile[]> = FinalizedRegistry<L>;
|
|
44
|
+
export declare function finalize<const L extends readonly AnyLeafLowProfile[]>(leaves: L): FinalizedRegistry<L>;
|
|
46
45
|
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -27,54 +27,12 @@ __export(index_exports, {
|
|
|
27
27
|
finalize: () => finalize,
|
|
28
28
|
lowProfileParse: () => lowProfileParse,
|
|
29
29
|
mergeArrays: () => mergeArrays,
|
|
30
|
-
paramsOverrideSymbol: () => paramsOverrideSymbol,
|
|
31
30
|
resource: () => resource
|
|
32
31
|
});
|
|
33
32
|
module.exports = __toCommonJS(index_exports);
|
|
34
33
|
|
|
35
34
|
// src/core/routesV3.builder.ts
|
|
36
35
|
var import_zod = require("zod");
|
|
37
|
-
|
|
38
|
-
// src/core/routesV3.core.ts
|
|
39
|
-
var paramsOverrideSymbol = Symbol(
|
|
40
|
-
"rrroutes.paramsOverride"
|
|
41
|
-
);
|
|
42
|
-
var lowProfileParse = (schema, data) => {
|
|
43
|
-
return schema.parse(data);
|
|
44
|
-
};
|
|
45
|
-
function compilePath(path, params) {
|
|
46
|
-
if (!params) return path;
|
|
47
|
-
return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {
|
|
48
|
-
const v = params[k];
|
|
49
|
-
if (v === void 0 || v === null) throw new Error(`Missing param :${k}`);
|
|
50
|
-
return String(v);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function buildCacheKey(args) {
|
|
54
|
-
let p = args.leaf.path;
|
|
55
|
-
if (args.params) {
|
|
56
|
-
p = compilePath(p, args.params);
|
|
57
|
-
}
|
|
58
|
-
return [
|
|
59
|
-
args.leaf.method,
|
|
60
|
-
...p.split("/").filter(Boolean),
|
|
61
|
-
args.query ?? {}
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
function buildLowProfileLeaf(leaf) {
|
|
65
|
-
return {
|
|
66
|
-
...leaf,
|
|
67
|
-
cfg: {
|
|
68
|
-
...leaf.cfg,
|
|
69
|
-
bodySchema: leaf.cfg.bodySchema,
|
|
70
|
-
querySchema: leaf.cfg.querySchema,
|
|
71
|
-
paramsSchema: leaf.cfg.paramsSchema,
|
|
72
|
-
outputSchema: leaf.cfg.outputSchema
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/core/routesV3.builder.ts
|
|
78
36
|
var paginationQueryShape = {
|
|
79
37
|
pagination_cursor: import_zod.z.string().optional(),
|
|
80
38
|
pagination_limit: import_zod.z.coerce.number().min(1).max(100).default(20)
|
|
@@ -179,11 +137,6 @@ function resource(base, inherited) {
|
|
|
179
137
|
...effectiveQuerySchema ? { querySchema: effectiveQuerySchema } : {},
|
|
180
138
|
...effectiveOutputSchema ? { outputSchema: effectiveOutputSchema } : {}
|
|
181
139
|
};
|
|
182
|
-
if (cfg.paramsSchema) {
|
|
183
|
-
fullCfg[paramsOverrideSymbol] = true;
|
|
184
|
-
} else if (fullCfg[paramsOverrideSymbol]) {
|
|
185
|
-
delete fullCfg[paramsOverrideSymbol];
|
|
186
|
-
}
|
|
187
140
|
const leaf = {
|
|
188
141
|
method,
|
|
189
142
|
path: currentBase,
|
|
@@ -221,8 +174,10 @@ function resource(base, inherited) {
|
|
|
221
174
|
const leaf = leafLow;
|
|
222
175
|
const leafCfg = leaf.cfg;
|
|
223
176
|
const leafParams = leafCfg.paramsSchema;
|
|
224
|
-
const
|
|
225
|
-
|
|
177
|
+
const effectiveParams = mergeSchemas(
|
|
178
|
+
currentParamsSchema,
|
|
179
|
+
leafParams
|
|
180
|
+
);
|
|
226
181
|
const newCfg = {
|
|
227
182
|
...childInherited,
|
|
228
183
|
...leafCfg
|
|
@@ -232,11 +187,6 @@ function resource(base, inherited) {
|
|
|
232
187
|
} else if ("paramsSchema" in newCfg) {
|
|
233
188
|
delete newCfg.paramsSchema;
|
|
234
189
|
}
|
|
235
|
-
if (isOverride) {
|
|
236
|
-
newCfg[paramsOverrideSymbol] = true;
|
|
237
|
-
} else if (newCfg[paramsOverrideSymbol]) {
|
|
238
|
-
delete newCfg[paramsOverrideSymbol];
|
|
239
|
-
}
|
|
240
190
|
const newLeaf = {
|
|
241
191
|
method: leaf.method,
|
|
242
192
|
path: `${baseForChildren}${leaf.path}`,
|
|
@@ -263,8 +213,7 @@ function resource(base, inherited) {
|
|
|
263
213
|
const leaf = leafLow;
|
|
264
214
|
const leafCfg = leaf.cfg;
|
|
265
215
|
const leafParams = leafCfg.paramsSchema;
|
|
266
|
-
const
|
|
267
|
-
const effectiveParams = isOverride ? leafParams : mergeSchemas(mergedParams, leafParams);
|
|
216
|
+
const effectiveParams = mergeSchemas(mergedParams, leafParams);
|
|
268
217
|
const newCfg = {
|
|
269
218
|
...inheritedCfg,
|
|
270
219
|
...leafCfg
|
|
@@ -274,11 +223,6 @@ function resource(base, inherited) {
|
|
|
274
223
|
} else if ("paramsSchema" in newCfg) {
|
|
275
224
|
delete newCfg.paramsSchema;
|
|
276
225
|
}
|
|
277
|
-
if (isOverride) {
|
|
278
|
-
newCfg[paramsOverrideSymbol] = true;
|
|
279
|
-
} else if (newCfg[paramsOverrideSymbol]) {
|
|
280
|
-
delete newCfg[paramsOverrideSymbol];
|
|
281
|
-
}
|
|
282
226
|
const newLeaf = {
|
|
283
227
|
method: leaf.method,
|
|
284
228
|
path: `${baseForChildren}${leaf.path}`,
|
|
@@ -316,6 +260,42 @@ var mergeArrays = (arr1, arr2) => {
|
|
|
316
260
|
return [...arr1, ...arr2];
|
|
317
261
|
};
|
|
318
262
|
|
|
263
|
+
// src/core/routesV3.core.ts
|
|
264
|
+
var lowProfileParse = (schema, data) => {
|
|
265
|
+
return schema.parse(data);
|
|
266
|
+
};
|
|
267
|
+
function compilePath(path, params) {
|
|
268
|
+
if (!params) return path;
|
|
269
|
+
return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {
|
|
270
|
+
const v = params[k];
|
|
271
|
+
if (v === void 0 || v === null) throw new Error(`Missing param :${k}`);
|
|
272
|
+
return String(v);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function buildCacheKey(args) {
|
|
276
|
+
let p = args.leaf.path;
|
|
277
|
+
if (args.params) {
|
|
278
|
+
p = compilePath(p, args.params);
|
|
279
|
+
}
|
|
280
|
+
return [
|
|
281
|
+
args.leaf.method,
|
|
282
|
+
...p.split("/").filter(Boolean),
|
|
283
|
+
args.query ?? {}
|
|
284
|
+
];
|
|
285
|
+
}
|
|
286
|
+
function buildLowProfileLeaf(leaf) {
|
|
287
|
+
return {
|
|
288
|
+
...leaf,
|
|
289
|
+
cfg: {
|
|
290
|
+
...leaf.cfg,
|
|
291
|
+
bodySchema: leaf.cfg.bodySchema,
|
|
292
|
+
querySchema: leaf.cfg.querySchema,
|
|
293
|
+
paramsSchema: leaf.cfg.paramsSchema,
|
|
294
|
+
outputSchema: leaf.cfg.outputSchema
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
319
299
|
// src/core/routesV3.finalize.ts
|
|
320
300
|
function finalize(leaves) {
|
|
321
301
|
const byKey = Object.fromEntries(
|
|
@@ -344,7 +324,6 @@ function defineSocketEvents(config, events) {
|
|
|
344
324
|
finalize,
|
|
345
325
|
lowProfileParse,
|
|
346
326
|
mergeArrays,
|
|
347
|
-
paramsOverrideSymbol,
|
|
348
327
|
resource
|
|
349
328
|
});
|
|
350
329
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n MethodCfg,\n NodeCfg,\n Prettify,\n paramsOverrideSymbol,\n} from './routesV3.core'\n\nconst paginationQueryShape = {\n pagination_cursor: z.string().optional(),\n pagination_limit: z.coerce.number().min(1).max(100).default(20),\n}\n\nconst defaultFeedQuerySchema = z.object(paginationQueryShape)\ntype PaginationShape = typeof paginationQueryShape\n\ntype ZodTypeAny = z.ZodTypeAny\ntype ParamZod<Name extends string, S extends ZodTypeAny> = z.ZodObject<{\n [K in Name]: S\n}>\ntype ZodArrayAny = z.ZodArray<ZodTypeAny>\ntype ZodObjectAny = z.ZodObject<any>\ntype AnyZodObject = z.ZodObject<any>\ntype MergedParamsResult<\n PS,\n Name extends string,\n P extends ZodTypeAny,\n> = PS extends ZodTypeAny\n ? z.ZodIntersection<PS, ParamZod<Name, P>>\n : ParamZod<Name, P>\n\nfunction getZodShape(schema: ZodObjectAny) {\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\nfunction collectNestedFieldSuggestions(\n shape: Record<string, ZodTypeAny> | 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 ZodObjectAny)\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\nconst defaultFeedOutputSchema = z.object({\n items: z.array(z.unknown()),\n nextCursor: z.string().optional(),\n})\n\nfunction augmentFeedQuerySchema<Q extends ZodTypeAny | undefined>(schema: Q) {\n if (schema && !(schema instanceof z.ZodObject)) {\n console.warn(\n 'Feed queries must be a ZodObject; default pagination applied.',\n )\n return defaultFeedQuerySchema\n }\n\n const base = (schema as ZodObjectAny) ?? z.object({})\n const shape = getZodShape(base)\n const nestedSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedSuggestions.length) {\n console.warn(\n `Feed query schemas should avoid nested objects; consider flattening fields like: ${nestedSuggestions.join(\n ', ',\n )}`,\n )\n }\n return base.extend(paginationQueryShape)\n}\n\nfunction augmentFeedOutputSchema<O extends ZodTypeAny | undefined>(schema: O) {\n if (!schema) return defaultFeedOutputSchema\n if (schema instanceof z.ZodArray) {\n return z.object({\n items: schema,\n nextCursor: z.string().optional(),\n })\n }\n if (schema instanceof z.ZodObject) {\n const shape = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n const hasItems = Boolean(shape?.items)\n if (hasItems) {\n return schema.extend({ nextCursor: z.string().optional() })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\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 */\nfunction mergeSchemas<A extends ZodTypeAny, B extends ZodTypeAny>(\n a: A,\n b: B,\n): ZodTypeAny\nfunction mergeSchemas<A extends ZodTypeAny>(a: A, b: undefined): A\nfunction mergeSchemas<B extends ZodTypeAny>(a: undefined, b: B): B\nfunction mergeSchemas(\n a: ZodTypeAny | undefined,\n b: ZodTypeAny | undefined,\n): ZodTypeAny | undefined\nfunction mergeSchemas(a: ZodTypeAny | undefined, b: ZodTypeAny | undefined) {\n if (a && b) return z.intersection(a as any, b as any)\n return (a ?? b) as ZodTypeAny | undefined\n}\n\ntype FeedOutputSchema<C extends MethodCfg> =\n C['outputSchema'] extends ZodArrayAny\n ? z.ZodObject<{\n items: C['outputSchema']\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : C['outputSchema'] extends ZodTypeAny\n ? z.ZodObject<{\n items: z.ZodArray<C['outputSchema']>\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : typeof defaultFeedOutputSchema\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 AddPaginationToQuery<Q extends AnyZodObject | undefined> =\n Q extends z.ZodObject<infer Shape>\n ? z.ZodObject<Shape & PaginationShape>\n : z.ZodObject<PaginationShape>\n\ntype FeedQueryField<C extends MethodCfg> = {\n querySchema: AddPaginationToQuery<\n C['querySchema'] extends AnyZodObject ? C['querySchema'] : undefined\n >\n}\n\ntype NonFeedQueryField<C extends MethodCfg> =\n C['querySchema'] extends ZodTypeAny\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype FeedOutputField<C extends MethodCfg> = {\n outputSchema: FeedOutputSchema<C>\n}\n\ntype NonFeedOutputField<C extends MethodCfg> =\n C['outputSchema'] extends ZodTypeAny\n ? { outputSchema: C['outputSchema'] }\n : { outputSchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodTypeAny\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & FeedOutputField<C> & ParamsField<C, PS>\n : FeedField<C> &\n NonFeedQueryField<C> &\n NonFeedOutputField<C> &\n ParamsField<C, PS>\n\ntype EffectiveCfg<C extends MethodCfg, PS> = Prettify<\n Merge<MethodCfg, BaseMethodCfg<C> & EffectiveFeedFields<C, PS>>\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<M, Base, Merge<I, LowProfileCfg<EffectiveCfg<C, PS>>>>\n\ntype MethodFns<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodTypeAny | undefined,\n Used extends HttpMethod,\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 Base,\n Append<Acc, Prettify<BuiltLeaf<'get', Base, I, C, PS>>>,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'post', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'put', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'patch', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'delete', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 ZodTypeAny | undefined,\n Used extends HttpMethod = never,\n> extends MethodFns<Base, Acc, I, PS, Used> {\n /**\n * Mount a static subtree under `name`.\n * The `leaves` are built externally via `resource(...)` and will be\n * rebased so that their paths become `${Base}/${name}${leaf.path}` and their\n * paramsSchemas are merged with the parameters already accumulated on this branch.\n */\n sub<Name extends string, R extends readonly AnyLeafLowProfile[]>(\n name: Name,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n I,\n PS,\n Used\n >\n\n /**\n * Mount a static subtree under `name` and merge extra node-level config.\n */\n sub<\n Name extends string,\n J extends NodeCfg,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n cfg: J,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n Merge<I, J>,\n PS,\n Used\n >\n\n /**\n * Introduce a `:param` segment and mount a pre-built subtree beneath it.\n * The subtree paths are rebased to `${Base}/:${Name}${leaf.path}` and\n * their paramsSchemas are intersected with the accumulated params plus this new param.\n */\n routeParameter<\n Name extends string,\n P extends ZodTypeAny,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n paramsSchema: P,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<\n Acc,\n AugmentLeaves<`${Base}/:${Name}`, MergedParamsResult<PS, Name, P>, R>\n >,\n I,\n PS,\n Used\n >\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<Base extends string = '', I extends NodeCfg = {}>(\n base?: Base,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined> {\n const rootBase = (base ?? '') as Base\n const rootInherited: NodeCfg = { ...(inherited as NodeCfg) }\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodTypeAny | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeaf[] = []\n let currentBase: string = base2\n let inheritedCfg: NodeCfg = { ...(inherited2 as NodeCfg) }\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 effectiveQuerySchema =\n cfg.feed === true\n ? augmentFeedQuerySchema(cfg.querySchema)\n : cfg.querySchema\n const effectiveOutputSchema =\n cfg.feed === true\n ? augmentFeedOutputSchema(cfg.outputSchema)\n : cfg.outputSchema\n\n const fullCfg = (\n effectiveParamsSchema\n ? {\n ...inheritedCfg,\n ...cfg,\n paramsSchema: effectiveParamsSchema,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n : {\n ...inheritedCfg,\n ...cfg,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n ) as any\n\n if (cfg.paramsSchema) {\n fullCfg[paramsOverrideSymbol] = true\n } else if (fullCfg[paramsOverrideSymbol]) {\n delete fullCfg[paramsOverrideSymbol]\n }\n\n const leaf = {\n method,\n path: currentBase as Base2,\n cfg: fullCfg,\n } as const\n\n stack.push(leaf as unknown as AnyLeaf)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount a subtree built elsewhere.\n *\n * Usage:\n * const users = resource('').get(...).done()\n * resource('/api').sub('users', users).done()\n */\n sub<Name extends string>(\n name: Name,\n cfgOrLeaves?: NodeCfg | readonly AnyLeafLowProfile[],\n maybeLeaves?: readonly AnyLeafLowProfile[],\n ) {\n let cfg: NodeCfg | undefined\n let leaves: readonly AnyLeafLowProfile[] | undefined\n\n if (Array.isArray(cfgOrLeaves)) {\n leaves = cfgOrLeaves\n } else {\n cfg = cfgOrLeaves as NodeCfg | undefined\n leaves = maybeLeaves\n }\n\n if (!leaves) {\n throw new Error('sub() expects a leaves array as the last argument')\n }\n\n const childInherited: NodeCfg = {\n ...inheritedCfg,\n ...(cfg ?? {}),\n }\n\n const baseForChildren = `${currentBase}/${name}`\n\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 ZodTypeAny | undefined\n const isOverride = Boolean((leafCfg as any)[paramsOverrideSymbol])\n\n const effectiveParams = isOverride\n ? leafParams\n : mergeSchemas(currentParamsSchema as any, leafParams)\n\n const newCfg: MethodCfg = {\n ...childInherited,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n if (isOverride) {\n newCfg[paramsOverrideSymbol] = true\n } else if (newCfg[paramsOverrideSymbol]) {\n delete newCfg[paramsOverrideSymbol]\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\n }\n\n return api\n },\n\n /**\n * Introduce a :param segment and mount a subtree under it.\n *\n * The subtree is built independently (e.g. resource('').get(...).done())\n * and its paths become `${currentBase}/:${name}${leaf.path}`.\n * Params schemas are intersected with the accumulated params plus the new param.\n */\n routeParameter<Name extends string, P extends ZodTypeAny>(\n name: Name,\n paramsSchema: P,\n leaves: readonly AnyLeafLowProfile[],\n ) {\n const paramObj: ParamZod<Name, P> = z.object({\n [name]: paramsSchema,\n } as Record<Name, P>)\n\n const mergedParams = (\n currentParamsSchema\n ? mergeSchemas(currentParamsSchema as any, paramObj)\n : paramObj\n ) as PS2\n\n const baseForChildren = `${currentBase}/:${name}`\n\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 ZodTypeAny | undefined\n const isOverride = Boolean((leafCfg as any)[paramsOverrideSymbol])\n\n const effectiveParams = isOverride\n ? leafParams\n : mergeSchemas(mergedParams as any, leafParams)\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 if (isOverride) {\n newCfg[paramsOverrideSymbol] = true\n } else if (newCfg[paramsOverrideSymbol]) {\n delete newCfg[paramsOverrideSymbol]\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\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(rootBase, rootInherited, undefined)\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","import { z, ZodType } from 'zod'\n\nexport const paramsOverrideSymbol: unique symbol = Symbol(\n 'rrroutes.paramsOverride',\n)\nexport type ParamsOverrideSymbol = typeof paramsOverrideSymbol\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 type NodeCfg = {\n /** @deprecated. Does nothing. */\n authenticated?: boolean\n}\n\nexport type RouteSchema<Output = unknown> = ZodType & {\n __out: Output\n}\n\nexport type RouteSchemaOutput<Schema extends ZodType> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return schema.parse(data) as RouteSchemaOutput<T>\n}\n\nexport type ToRouteSchema<S> = S extends ZodType ? RouteSchema<z.output<S>> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg> = Prettify<\n Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'> & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\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 (overrides inferred params). */\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\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 /** @internal flag used to track whether paramsSchema was explicitly provided. */\n [paramsOverrideSymbol]?: true\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]\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 RouteSchemaFromZod<T extends ZodType | undefined> = T extends ZodType\n ? RouteSchema<z.output<T>>\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> = Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType\n ? RouteSchema<ExistingOut & z.output<Parent>>\n : Existing\n : Parent extends ZodType\n ? RouteSchemaFromZod<Parent>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> &\n (Cfg[typeof paramsOverrideSymbol] extends true\n ? {\n paramsSchema: Cfg['paramsSchema']\n [paramsOverrideSymbol]: true\n }\n : {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n })\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n Acc extends readonly LeafLowProfile[] = [],\n> = R extends readonly [infer First, ...infer Rest]\n ? First extends LeafLowProfile\n ? AugmentLeaves<\n P,\n Param,\n Rest extends readonly LeafLowProfile[] ? Rest : [],\n Append<\n Acc,\n LeafLowProfile<\n First['method'],\n `${P}${First['path']}`,\n AugmentedCfg<First['cfg'], Param>\n >\n >\n >\n : never\n : Acc\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\nexport function buildCacheKey<L extends AnyLeaf>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}) {\n let p = args.leaf.path\n if (args.params) {\n p = compilePath<L['path']>(p, args.params)\n }\n return [\n args.leaf.method,\n ...(p.split('/').filter(Boolean) as SplitPath<typeof p>),\n args.query ?? {},\n ] as const\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' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\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 Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n cfg: Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed'\n > & {\n feed: Feed\n bodySchema: B extends ZodType ? RouteSchema<z.infer<B>> : undefined\n querySchema: Q extends ZodType ? RouteSchema<z.infer<Q>> : undefined\n paramsSchema: P extends ZodType ? RouteSchema<z.infer<P>> : undefined\n outputSchema: O extends ZodType ? RouteSchema<z.infer<O>> : undefined\n }\n >\n>\nexport function buildLowProfileLeaf(leaf: any): any {\n return {\n ...leaf,\n cfg: {\n ...leaf.cfg,\n bodySchema: leaf.cfg.bodySchema as RouteSchema<\n z.infer<typeof leaf.cfg.bodySchema>\n >,\n querySchema: leaf.cfg.querySchema as RouteSchema<\n z.infer<typeof leaf.cfg.querySchema>\n >,\n paramsSchema: leaf.cfg.paramsSchema as RouteSchema<\n z.infer<typeof leaf.cfg.paramsSchema>\n >,\n outputSchema: leaf.cfg.outputSchema as RouteSchema<\n z.infer<typeof leaf.cfg.outputSchema>\n >,\n },\n }\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer P> ? P : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeaf, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer Q> ? Q : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeaf, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer B> ? B : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\nexport type InferOutput<L extends AnyLeaf, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O> ? O : 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","// TODO:\n// * use this as a transform that infers the types from Zod, to only pass the types around instead of the full schemas -> make converters that go both ways (data to schema, schema to data)\n// * consider moving to core package\n// * update server and client side to use this type instead of raw zod schemas\nimport { 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\n/**\n * Freeze a leaf tuple into a registry with typed key lookups.\n * @param leaves Readonly tuple of leaves produced by the builder DSL.\n * @returns Registry containing the leaves array and a `byKey` lookup map.\n */\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n) {\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\n/** Nominal type alias for a finalized registry. */\nexport type Registry<R extends ReturnType<typeof finalize>> = R\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","// 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":[]}
|
|
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 } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n MethodCfg,\n NodeCfg,\n Prettify,\n} from './routesV3.core'\n\nconst paginationQueryShape = {\n pagination_cursor: z.string().optional(),\n pagination_limit: z.coerce.number().min(1).max(100).default(20),\n}\n\nconst defaultFeedQuerySchema = z.object(paginationQueryShape)\ntype PaginationShape = typeof paginationQueryShape\n\ntype ZodTypeAny = z.ZodTypeAny\ntype ParamZod<Name extends string, S extends ZodTypeAny> = z.ZodObject<{\n [K in Name]: S\n}>\ntype ZodArrayAny = z.ZodArray<ZodTypeAny>\ntype ZodObjectAny = z.ZodObject<any>\ntype AnyZodObject = z.ZodObject<any>\ntype MergedParamsResult<\n PS,\n Name extends string,\n P extends ZodTypeAny,\n> = PS extends ZodTypeAny\n ? z.ZodIntersection<PS, ParamZod<Name, P>>\n : ParamZod<Name, P>\n\nfunction getZodShape(schema: ZodObjectAny) {\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\nfunction collectNestedFieldSuggestions(\n shape: Record<string, ZodTypeAny> | 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 ZodObjectAny)\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\nconst defaultFeedOutputSchema = z.object({\n items: z.array(z.unknown()),\n nextCursor: z.string().optional(),\n})\n\nfunction augmentFeedQuerySchema<Q extends ZodTypeAny | undefined>(schema: Q) {\n if (schema && !(schema instanceof z.ZodObject)) {\n console.warn(\n 'Feed queries must be a ZodObject; default pagination applied.',\n )\n return defaultFeedQuerySchema\n }\n\n const base = (schema as ZodObjectAny) ?? z.object({})\n const shape = getZodShape(base)\n const nestedSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedSuggestions.length) {\n console.warn(\n `Feed query schemas should avoid nested objects; consider flattening fields like: ${nestedSuggestions.join(\n ', ',\n )}`,\n )\n }\n return base.extend(paginationQueryShape)\n}\n\nfunction augmentFeedOutputSchema<O extends ZodTypeAny | undefined>(schema: O) {\n if (!schema) return defaultFeedOutputSchema\n if (schema instanceof z.ZodArray) {\n return z.object({\n items: schema,\n nextCursor: z.string().optional(),\n })\n }\n if (schema instanceof z.ZodObject) {\n const shape = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n const hasItems = Boolean(shape?.items)\n if (hasItems) {\n return schema.extend({ nextCursor: z.string().optional() })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\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 */\nfunction mergeSchemas<A extends ZodTypeAny, B extends ZodTypeAny>(\n a: A,\n b: B,\n): ZodTypeAny\nfunction mergeSchemas<A extends ZodTypeAny>(a: A, b: undefined): A\nfunction mergeSchemas<B extends ZodTypeAny>(a: undefined, b: B): B\nfunction mergeSchemas(\n a: ZodTypeAny | undefined,\n b: ZodTypeAny | undefined,\n): ZodTypeAny | undefined\nfunction mergeSchemas(a: ZodTypeAny | undefined, b: ZodTypeAny | undefined) {\n if (a && b) return z.intersection(a as any, b as any)\n return (a ?? b) as ZodTypeAny | undefined\n}\n\ntype FeedOutputSchema<C extends MethodCfg> =\n C['outputSchema'] extends ZodArrayAny\n ? z.ZodObject<{\n items: C['outputSchema']\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : C['outputSchema'] extends ZodTypeAny\n ? z.ZodObject<{\n items: z.ZodArray<C['outputSchema']>\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : typeof defaultFeedOutputSchema\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 AddPaginationToQuery<Q extends AnyZodObject | undefined> =\n Q extends z.ZodObject<infer Shape>\n ? z.ZodObject<Shape & PaginationShape>\n : z.ZodObject<PaginationShape>\n\ntype FeedQueryField<C extends MethodCfg> = {\n querySchema: AddPaginationToQuery<\n C['querySchema'] extends AnyZodObject ? C['querySchema'] : undefined\n >\n}\n\ntype NonFeedQueryField<C extends MethodCfg> =\n C['querySchema'] extends ZodTypeAny\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype FeedOutputField<C extends MethodCfg> = {\n outputSchema: FeedOutputSchema<C>\n}\n\ntype NonFeedOutputField<C extends MethodCfg> =\n C['outputSchema'] extends ZodTypeAny\n ? { outputSchema: C['outputSchema'] }\n : { outputSchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodTypeAny\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & FeedOutputField<C> & ParamsField<C, PS>\n : FeedField<C> &\n NonFeedQueryField<C> &\n NonFeedOutputField<C> &\n ParamsField<C, PS>\n\ntype EffectiveCfg<C extends MethodCfg, PS> = Prettify<\n Merge<MethodCfg, BaseMethodCfg<C> & EffectiveFeedFields<C, PS>>\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<M, Base, Merge<I, LowProfileCfg<EffectiveCfg<C, PS>>>>\n\ntype MethodFns<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodTypeAny | undefined,\n Used extends HttpMethod,\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 Base,\n Append<Acc, Prettify<BuiltLeaf<'get', Base, I, C, PS>>>,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'post', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'put', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'patch', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'delete', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 ZodTypeAny | undefined,\n Used extends HttpMethod = never,\n> extends MethodFns<Base, Acc, I, PS, Used> {\n /**\n * Mount a static subtree under `name`.\n * The `leaves` are built externally via `resource(...)` and will be\n * rebased so that their paths become `${Base}/${name}${leaf.path}` and their\n * paramsSchemas are merged with the parameters already accumulated on this branch.\n */\n sub<Name extends string, R extends readonly AnyLeafLowProfile[]>(\n name: Name,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n I,\n PS,\n Used\n >\n\n /**\n * Mount a static subtree under `name` and merge extra node-level config.\n */\n sub<\n Name extends string,\n J extends NodeCfg,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n cfg: J,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n Merge<I, J>,\n PS,\n Used\n >\n\n /**\n * Introduce a `:param` segment and mount a pre-built subtree beneath it.\n * The subtree paths are rebased to `${Base}/:${Name}${leaf.path}` and\n * their paramsSchemas are intersected with the accumulated params plus this new param.\n */\n routeParameter<\n Name extends string,\n P extends ZodTypeAny,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n paramsSchema: P,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<\n Acc,\n AugmentLeaves<`${Base}/:${Name}`, MergedParamsResult<PS, Name, P>, R>\n >,\n I,\n PS,\n Used\n >\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<Base extends string = '', I extends NodeCfg = {}>(\n base?: Base,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined> {\n const rootBase = (base ?? '') as Base\n const rootInherited: NodeCfg = { ...(inherited as NodeCfg) }\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodTypeAny | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeaf[] = []\n let currentBase: string = base2\n let inheritedCfg: NodeCfg = { ...(inherited2 as NodeCfg) }\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 effectiveQuerySchema =\n cfg.feed === true\n ? augmentFeedQuerySchema(cfg.querySchema)\n : cfg.querySchema\n const effectiveOutputSchema =\n cfg.feed === true\n ? augmentFeedOutputSchema(cfg.outputSchema)\n : cfg.outputSchema\n\n const fullCfg = (\n effectiveParamsSchema\n ? {\n ...inheritedCfg,\n ...cfg,\n paramsSchema: effectiveParamsSchema,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n : {\n ...inheritedCfg,\n ...cfg,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n ) as any\n\n const leaf = {\n method,\n path: currentBase as Base2,\n cfg: fullCfg,\n } as const\n\n stack.push(leaf as unknown as AnyLeaf)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount a subtree built elsewhere.\n *\n * Usage:\n * const users = resource('').get(...).done()\n * resource('/api').sub('users', users).done()\n */\n sub<Name extends string>(\n name: Name,\n cfgOrLeaves?: NodeCfg | readonly AnyLeafLowProfile[],\n maybeLeaves?: readonly AnyLeafLowProfile[],\n ) {\n let cfg: NodeCfg | undefined\n let leaves: readonly AnyLeafLowProfile[] | undefined\n\n if (Array.isArray(cfgOrLeaves)) {\n leaves = cfgOrLeaves\n } else {\n cfg = cfgOrLeaves as NodeCfg | undefined\n leaves = maybeLeaves\n }\n\n if (!leaves) {\n throw new Error('sub() expects a leaves array as the last argument')\n }\n\n const childInherited: NodeCfg = {\n ...inheritedCfg,\n ...(cfg ?? {}),\n }\n\n const baseForChildren = `${currentBase}/${name}`\n\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 ZodTypeAny | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...childInherited,\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: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\n }\n\n return api\n },\n\n /**\n * Introduce a :param segment and mount a subtree under it.\n *\n * The subtree is built independently (e.g. resource('').get(...).done())\n * and its paths become `${currentBase}/:${name}${leaf.path}`.\n * Params schemas are intersected with the accumulated params plus the new param.\n */\n routeParameter<Name extends string, P extends ZodTypeAny>(\n name: Name,\n paramsSchema: P,\n leaves: readonly AnyLeafLowProfile[],\n ) {\n const paramObj: ParamZod<Name, P> = z.object({\n [name]: paramsSchema,\n } as Record<Name, P>)\n\n const mergedParams = (\n currentParamsSchema\n ? mergeSchemas(currentParamsSchema as any, paramObj)\n : paramObj\n ) as PS2\n\n const baseForChildren = `${currentBase}/:${name}`\n\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 ZodTypeAny | undefined\n\n const effectiveParams = mergeSchemas(mergedParams as any, leafParams)\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: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\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(rootBase, rootInherited, undefined)\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","import { z, 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 type NodeCfg = {\n /** @deprecated. Does nothing. */\n authenticated?: boolean\n}\n\nexport type RouteSchema<Output = unknown> = ZodType & {\n __out: Output\n}\n\nexport type RouteSchemaOutput<Schema extends ZodType> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return schema.parse(data) as RouteSchemaOutput<T>\n}\n\nexport type ToRouteSchema<S> = S extends ZodType ? RouteSchema<z.output<S>> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg> = Prettify<\n Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'> & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\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 sub and routeParameter). */\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\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]\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 RouteSchemaFromZod<T extends ZodType | undefined> = T extends ZodType\n ? RouteSchema<z.output<T>>\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\n ? RouteSchema<ExistingOut & z.output<Parent>>\n : Existing\n : Parent extends ZodType\n ? RouteSchemaFromZod<Parent>\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\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n Acc extends readonly LeafLowProfile[] = [],\n> = R extends readonly [infer First, ...infer Rest]\n ? First extends LeafLowProfile\n ? AugmentLeaves<\n P,\n Param,\n Rest extends readonly LeafLowProfile[] ? Rest : [],\n Append<\n Acc,\n LeafLowProfile<\n First['method'],\n `${P}${First['path']}`,\n AugmentedCfg<First['cfg'], Param>\n >\n >\n >\n : never\n : Acc\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\nexport function buildCacheKey<L extends AnyLeaf>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}) {\n let p = args.leaf.path\n if (args.params) {\n p = compilePath<L['path']>(p, args.params)\n }\n return [\n args.leaf.method,\n ...(p.split('/').filter(Boolean) as SplitPath<typeof p>),\n args.query ?? {},\n ] as const\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' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\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 Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n cfg: Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed'\n > & {\n feed: Feed\n bodySchema: B extends ZodType ? RouteSchema<z.infer<B>> : undefined\n querySchema: Q extends ZodType ? RouteSchema<z.infer<Q>> : undefined\n paramsSchema: P extends ZodType ? RouteSchema<z.infer<P>> : undefined\n outputSchema: O extends ZodType ? RouteSchema<z.infer<O>> : undefined\n }\n >\n>\nexport function buildLowProfileLeaf(leaf: any): any {\n return {\n ...leaf,\n cfg: {\n ...leaf.cfg,\n bodySchema: leaf.cfg.bodySchema as RouteSchema<\n z.infer<typeof leaf.cfg.bodySchema>\n >,\n querySchema: leaf.cfg.querySchema as RouteSchema<\n z.infer<typeof leaf.cfg.querySchema>\n >,\n paramsSchema: leaf.cfg.paramsSchema as RouteSchema<\n z.infer<typeof leaf.cfg.paramsSchema>\n >,\n outputSchema: leaf.cfg.outputSchema as RouteSchema<\n z.infer<typeof leaf.cfg.outputSchema>\n >,\n },\n }\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer P> ? P : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeaf, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer Q> ? Q : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeaf, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer B> ? B : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\nexport type InferOutput<L extends AnyLeaf, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O> ? O : 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":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
// src/core/routesV3.builder.ts
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
|
|
4
|
-
// src/core/routesV3.core.ts
|
|
5
|
-
var paramsOverrideSymbol = Symbol(
|
|
6
|
-
"rrroutes.paramsOverride"
|
|
7
|
-
);
|
|
8
|
-
var lowProfileParse = (schema, data) => {
|
|
9
|
-
return schema.parse(data);
|
|
10
|
-
};
|
|
11
|
-
function compilePath(path, params) {
|
|
12
|
-
if (!params) return path;
|
|
13
|
-
return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {
|
|
14
|
-
const v = params[k];
|
|
15
|
-
if (v === void 0 || v === null) throw new Error(`Missing param :${k}`);
|
|
16
|
-
return String(v);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
function buildCacheKey(args) {
|
|
20
|
-
let p = args.leaf.path;
|
|
21
|
-
if (args.params) {
|
|
22
|
-
p = compilePath(p, args.params);
|
|
23
|
-
}
|
|
24
|
-
return [
|
|
25
|
-
args.leaf.method,
|
|
26
|
-
...p.split("/").filter(Boolean),
|
|
27
|
-
args.query ?? {}
|
|
28
|
-
];
|
|
29
|
-
}
|
|
30
|
-
function buildLowProfileLeaf(leaf) {
|
|
31
|
-
return {
|
|
32
|
-
...leaf,
|
|
33
|
-
cfg: {
|
|
34
|
-
...leaf.cfg,
|
|
35
|
-
bodySchema: leaf.cfg.bodySchema,
|
|
36
|
-
querySchema: leaf.cfg.querySchema,
|
|
37
|
-
paramsSchema: leaf.cfg.paramsSchema,
|
|
38
|
-
outputSchema: leaf.cfg.outputSchema
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// src/core/routesV3.builder.ts
|
|
44
3
|
var paginationQueryShape = {
|
|
45
4
|
pagination_cursor: z.string().optional(),
|
|
46
5
|
pagination_limit: z.coerce.number().min(1).max(100).default(20)
|
|
@@ -145,11 +104,6 @@ function resource(base, inherited) {
|
|
|
145
104
|
...effectiveQuerySchema ? { querySchema: effectiveQuerySchema } : {},
|
|
146
105
|
...effectiveOutputSchema ? { outputSchema: effectiveOutputSchema } : {}
|
|
147
106
|
};
|
|
148
|
-
if (cfg.paramsSchema) {
|
|
149
|
-
fullCfg[paramsOverrideSymbol] = true;
|
|
150
|
-
} else if (fullCfg[paramsOverrideSymbol]) {
|
|
151
|
-
delete fullCfg[paramsOverrideSymbol];
|
|
152
|
-
}
|
|
153
107
|
const leaf = {
|
|
154
108
|
method,
|
|
155
109
|
path: currentBase,
|
|
@@ -187,8 +141,10 @@ function resource(base, inherited) {
|
|
|
187
141
|
const leaf = leafLow;
|
|
188
142
|
const leafCfg = leaf.cfg;
|
|
189
143
|
const leafParams = leafCfg.paramsSchema;
|
|
190
|
-
const
|
|
191
|
-
|
|
144
|
+
const effectiveParams = mergeSchemas(
|
|
145
|
+
currentParamsSchema,
|
|
146
|
+
leafParams
|
|
147
|
+
);
|
|
192
148
|
const newCfg = {
|
|
193
149
|
...childInherited,
|
|
194
150
|
...leafCfg
|
|
@@ -198,11 +154,6 @@ function resource(base, inherited) {
|
|
|
198
154
|
} else if ("paramsSchema" in newCfg) {
|
|
199
155
|
delete newCfg.paramsSchema;
|
|
200
156
|
}
|
|
201
|
-
if (isOverride) {
|
|
202
|
-
newCfg[paramsOverrideSymbol] = true;
|
|
203
|
-
} else if (newCfg[paramsOverrideSymbol]) {
|
|
204
|
-
delete newCfg[paramsOverrideSymbol];
|
|
205
|
-
}
|
|
206
157
|
const newLeaf = {
|
|
207
158
|
method: leaf.method,
|
|
208
159
|
path: `${baseForChildren}${leaf.path}`,
|
|
@@ -229,8 +180,7 @@ function resource(base, inherited) {
|
|
|
229
180
|
const leaf = leafLow;
|
|
230
181
|
const leafCfg = leaf.cfg;
|
|
231
182
|
const leafParams = leafCfg.paramsSchema;
|
|
232
|
-
const
|
|
233
|
-
const effectiveParams = isOverride ? leafParams : mergeSchemas(mergedParams, leafParams);
|
|
183
|
+
const effectiveParams = mergeSchemas(mergedParams, leafParams);
|
|
234
184
|
const newCfg = {
|
|
235
185
|
...inheritedCfg,
|
|
236
186
|
...leafCfg
|
|
@@ -240,11 +190,6 @@ function resource(base, inherited) {
|
|
|
240
190
|
} else if ("paramsSchema" in newCfg) {
|
|
241
191
|
delete newCfg.paramsSchema;
|
|
242
192
|
}
|
|
243
|
-
if (isOverride) {
|
|
244
|
-
newCfg[paramsOverrideSymbol] = true;
|
|
245
|
-
} else if (newCfg[paramsOverrideSymbol]) {
|
|
246
|
-
delete newCfg[paramsOverrideSymbol];
|
|
247
|
-
}
|
|
248
193
|
const newLeaf = {
|
|
249
194
|
method: leaf.method,
|
|
250
195
|
path: `${baseForChildren}${leaf.path}`,
|
|
@@ -282,6 +227,42 @@ var mergeArrays = (arr1, arr2) => {
|
|
|
282
227
|
return [...arr1, ...arr2];
|
|
283
228
|
};
|
|
284
229
|
|
|
230
|
+
// src/core/routesV3.core.ts
|
|
231
|
+
var lowProfileParse = (schema, data) => {
|
|
232
|
+
return schema.parse(data);
|
|
233
|
+
};
|
|
234
|
+
function compilePath(path, params) {
|
|
235
|
+
if (!params) return path;
|
|
236
|
+
return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {
|
|
237
|
+
const v = params[k];
|
|
238
|
+
if (v === void 0 || v === null) throw new Error(`Missing param :${k}`);
|
|
239
|
+
return String(v);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function buildCacheKey(args) {
|
|
243
|
+
let p = args.leaf.path;
|
|
244
|
+
if (args.params) {
|
|
245
|
+
p = compilePath(p, args.params);
|
|
246
|
+
}
|
|
247
|
+
return [
|
|
248
|
+
args.leaf.method,
|
|
249
|
+
...p.split("/").filter(Boolean),
|
|
250
|
+
args.query ?? {}
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
function buildLowProfileLeaf(leaf) {
|
|
254
|
+
return {
|
|
255
|
+
...leaf,
|
|
256
|
+
cfg: {
|
|
257
|
+
...leaf.cfg,
|
|
258
|
+
bodySchema: leaf.cfg.bodySchema,
|
|
259
|
+
querySchema: leaf.cfg.querySchema,
|
|
260
|
+
paramsSchema: leaf.cfg.paramsSchema,
|
|
261
|
+
outputSchema: leaf.cfg.outputSchema
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
285
266
|
// src/core/routesV3.finalize.ts
|
|
286
267
|
function finalize(leaves) {
|
|
287
268
|
const byKey = Object.fromEntries(
|
|
@@ -309,7 +290,6 @@ export {
|
|
|
309
290
|
finalize,
|
|
310
291
|
lowProfileParse,
|
|
311
292
|
mergeArrays,
|
|
312
|
-
paramsOverrideSymbol,
|
|
313
293
|
resource
|
|
314
294
|
};
|
|
315
295
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n MethodCfg,\n NodeCfg,\n Prettify,\n paramsOverrideSymbol,\n} from './routesV3.core'\n\nconst paginationQueryShape = {\n pagination_cursor: z.string().optional(),\n pagination_limit: z.coerce.number().min(1).max(100).default(20),\n}\n\nconst defaultFeedQuerySchema = z.object(paginationQueryShape)\ntype PaginationShape = typeof paginationQueryShape\n\ntype ZodTypeAny = z.ZodTypeAny\ntype ParamZod<Name extends string, S extends ZodTypeAny> = z.ZodObject<{\n [K in Name]: S\n}>\ntype ZodArrayAny = z.ZodArray<ZodTypeAny>\ntype ZodObjectAny = z.ZodObject<any>\ntype AnyZodObject = z.ZodObject<any>\ntype MergedParamsResult<\n PS,\n Name extends string,\n P extends ZodTypeAny,\n> = PS extends ZodTypeAny\n ? z.ZodIntersection<PS, ParamZod<Name, P>>\n : ParamZod<Name, P>\n\nfunction getZodShape(schema: ZodObjectAny) {\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\nfunction collectNestedFieldSuggestions(\n shape: Record<string, ZodTypeAny> | 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 ZodObjectAny)\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\nconst defaultFeedOutputSchema = z.object({\n items: z.array(z.unknown()),\n nextCursor: z.string().optional(),\n})\n\nfunction augmentFeedQuerySchema<Q extends ZodTypeAny | undefined>(schema: Q) {\n if (schema && !(schema instanceof z.ZodObject)) {\n console.warn(\n 'Feed queries must be a ZodObject; default pagination applied.',\n )\n return defaultFeedQuerySchema\n }\n\n const base = (schema as ZodObjectAny) ?? z.object({})\n const shape = getZodShape(base)\n const nestedSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedSuggestions.length) {\n console.warn(\n `Feed query schemas should avoid nested objects; consider flattening fields like: ${nestedSuggestions.join(\n ', ',\n )}`,\n )\n }\n return base.extend(paginationQueryShape)\n}\n\nfunction augmentFeedOutputSchema<O extends ZodTypeAny | undefined>(schema: O) {\n if (!schema) return defaultFeedOutputSchema\n if (schema instanceof z.ZodArray) {\n return z.object({\n items: schema,\n nextCursor: z.string().optional(),\n })\n }\n if (schema instanceof z.ZodObject) {\n const shape = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n const hasItems = Boolean(shape?.items)\n if (hasItems) {\n return schema.extend({ nextCursor: z.string().optional() })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\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 */\nfunction mergeSchemas<A extends ZodTypeAny, B extends ZodTypeAny>(\n a: A,\n b: B,\n): ZodTypeAny\nfunction mergeSchemas<A extends ZodTypeAny>(a: A, b: undefined): A\nfunction mergeSchemas<B extends ZodTypeAny>(a: undefined, b: B): B\nfunction mergeSchemas(\n a: ZodTypeAny | undefined,\n b: ZodTypeAny | undefined,\n): ZodTypeAny | undefined\nfunction mergeSchemas(a: ZodTypeAny | undefined, b: ZodTypeAny | undefined) {\n if (a && b) return z.intersection(a as any, b as any)\n return (a ?? b) as ZodTypeAny | undefined\n}\n\ntype FeedOutputSchema<C extends MethodCfg> =\n C['outputSchema'] extends ZodArrayAny\n ? z.ZodObject<{\n items: C['outputSchema']\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : C['outputSchema'] extends ZodTypeAny\n ? z.ZodObject<{\n items: z.ZodArray<C['outputSchema']>\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : typeof defaultFeedOutputSchema\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 AddPaginationToQuery<Q extends AnyZodObject | undefined> =\n Q extends z.ZodObject<infer Shape>\n ? z.ZodObject<Shape & PaginationShape>\n : z.ZodObject<PaginationShape>\n\ntype FeedQueryField<C extends MethodCfg> = {\n querySchema: AddPaginationToQuery<\n C['querySchema'] extends AnyZodObject ? C['querySchema'] : undefined\n >\n}\n\ntype NonFeedQueryField<C extends MethodCfg> =\n C['querySchema'] extends ZodTypeAny\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype FeedOutputField<C extends MethodCfg> = {\n outputSchema: FeedOutputSchema<C>\n}\n\ntype NonFeedOutputField<C extends MethodCfg> =\n C['outputSchema'] extends ZodTypeAny\n ? { outputSchema: C['outputSchema'] }\n : { outputSchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodTypeAny\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & FeedOutputField<C> & ParamsField<C, PS>\n : FeedField<C> &\n NonFeedQueryField<C> &\n NonFeedOutputField<C> &\n ParamsField<C, PS>\n\ntype EffectiveCfg<C extends MethodCfg, PS> = Prettify<\n Merge<MethodCfg, BaseMethodCfg<C> & EffectiveFeedFields<C, PS>>\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<M, Base, Merge<I, LowProfileCfg<EffectiveCfg<C, PS>>>>\n\ntype MethodFns<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodTypeAny | undefined,\n Used extends HttpMethod,\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 Base,\n Append<Acc, Prettify<BuiltLeaf<'get', Base, I, C, PS>>>,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'post', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'put', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'patch', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'delete', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 ZodTypeAny | undefined,\n Used extends HttpMethod = never,\n> extends MethodFns<Base, Acc, I, PS, Used> {\n /**\n * Mount a static subtree under `name`.\n * The `leaves` are built externally via `resource(...)` and will be\n * rebased so that their paths become `${Base}/${name}${leaf.path}` and their\n * paramsSchemas are merged with the parameters already accumulated on this branch.\n */\n sub<Name extends string, R extends readonly AnyLeafLowProfile[]>(\n name: Name,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n I,\n PS,\n Used\n >\n\n /**\n * Mount a static subtree under `name` and merge extra node-level config.\n */\n sub<\n Name extends string,\n J extends NodeCfg,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n cfg: J,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n Merge<I, J>,\n PS,\n Used\n >\n\n /**\n * Introduce a `:param` segment and mount a pre-built subtree beneath it.\n * The subtree paths are rebased to `${Base}/:${Name}${leaf.path}` and\n * their paramsSchemas are intersected with the accumulated params plus this new param.\n */\n routeParameter<\n Name extends string,\n P extends ZodTypeAny,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n paramsSchema: P,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<\n Acc,\n AugmentLeaves<`${Base}/:${Name}`, MergedParamsResult<PS, Name, P>, R>\n >,\n I,\n PS,\n Used\n >\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<Base extends string = '', I extends NodeCfg = {}>(\n base?: Base,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined> {\n const rootBase = (base ?? '') as Base\n const rootInherited: NodeCfg = { ...(inherited as NodeCfg) }\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodTypeAny | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeaf[] = []\n let currentBase: string = base2\n let inheritedCfg: NodeCfg = { ...(inherited2 as NodeCfg) }\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 effectiveQuerySchema =\n cfg.feed === true\n ? augmentFeedQuerySchema(cfg.querySchema)\n : cfg.querySchema\n const effectiveOutputSchema =\n cfg.feed === true\n ? augmentFeedOutputSchema(cfg.outputSchema)\n : cfg.outputSchema\n\n const fullCfg = (\n effectiveParamsSchema\n ? {\n ...inheritedCfg,\n ...cfg,\n paramsSchema: effectiveParamsSchema,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n : {\n ...inheritedCfg,\n ...cfg,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n ) as any\n\n if (cfg.paramsSchema) {\n fullCfg[paramsOverrideSymbol] = true\n } else if (fullCfg[paramsOverrideSymbol]) {\n delete fullCfg[paramsOverrideSymbol]\n }\n\n const leaf = {\n method,\n path: currentBase as Base2,\n cfg: fullCfg,\n } as const\n\n stack.push(leaf as unknown as AnyLeaf)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount a subtree built elsewhere.\n *\n * Usage:\n * const users = resource('').get(...).done()\n * resource('/api').sub('users', users).done()\n */\n sub<Name extends string>(\n name: Name,\n cfgOrLeaves?: NodeCfg | readonly AnyLeafLowProfile[],\n maybeLeaves?: readonly AnyLeafLowProfile[],\n ) {\n let cfg: NodeCfg | undefined\n let leaves: readonly AnyLeafLowProfile[] | undefined\n\n if (Array.isArray(cfgOrLeaves)) {\n leaves = cfgOrLeaves\n } else {\n cfg = cfgOrLeaves as NodeCfg | undefined\n leaves = maybeLeaves\n }\n\n if (!leaves) {\n throw new Error('sub() expects a leaves array as the last argument')\n }\n\n const childInherited: NodeCfg = {\n ...inheritedCfg,\n ...(cfg ?? {}),\n }\n\n const baseForChildren = `${currentBase}/${name}`\n\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 ZodTypeAny | undefined\n const isOverride = Boolean((leafCfg as any)[paramsOverrideSymbol])\n\n const effectiveParams = isOverride\n ? leafParams\n : mergeSchemas(currentParamsSchema as any, leafParams)\n\n const newCfg: MethodCfg = {\n ...childInherited,\n ...leafCfg,\n }\n\n if (effectiveParams) {\n newCfg.paramsSchema = effectiveParams\n } else if ('paramsSchema' in newCfg) {\n delete newCfg.paramsSchema\n }\n\n if (isOverride) {\n newCfg[paramsOverrideSymbol] = true\n } else if (newCfg[paramsOverrideSymbol]) {\n delete newCfg[paramsOverrideSymbol]\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\n }\n\n return api\n },\n\n /**\n * Introduce a :param segment and mount a subtree under it.\n *\n * The subtree is built independently (e.g. resource('').get(...).done())\n * and its paths become `${currentBase}/:${name}${leaf.path}`.\n * Params schemas are intersected with the accumulated params plus the new param.\n */\n routeParameter<Name extends string, P extends ZodTypeAny>(\n name: Name,\n paramsSchema: P,\n leaves: readonly AnyLeafLowProfile[],\n ) {\n const paramObj: ParamZod<Name, P> = z.object({\n [name]: paramsSchema,\n } as Record<Name, P>)\n\n const mergedParams = (\n currentParamsSchema\n ? mergeSchemas(currentParamsSchema as any, paramObj)\n : paramObj\n ) as PS2\n\n const baseForChildren = `${currentBase}/:${name}`\n\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 ZodTypeAny | undefined\n const isOverride = Boolean((leafCfg as any)[paramsOverrideSymbol])\n\n const effectiveParams = isOverride\n ? leafParams\n : mergeSchemas(mergedParams as any, leafParams)\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 if (isOverride) {\n newCfg[paramsOverrideSymbol] = true\n } else if (newCfg[paramsOverrideSymbol]) {\n delete newCfg[paramsOverrideSymbol]\n }\n\n const newLeaf: AnyLeaf = {\n method: leaf.method,\n path: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\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(rootBase, rootInherited, undefined)\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","import { z, ZodType } from 'zod'\n\nexport const paramsOverrideSymbol: unique symbol = Symbol(\n 'rrroutes.paramsOverride',\n)\nexport type ParamsOverrideSymbol = typeof paramsOverrideSymbol\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 type NodeCfg = {\n /** @deprecated. Does nothing. */\n authenticated?: boolean\n}\n\nexport type RouteSchema<Output = unknown> = ZodType & {\n __out: Output\n}\n\nexport type RouteSchemaOutput<Schema extends ZodType> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return schema.parse(data) as RouteSchemaOutput<T>\n}\n\nexport type ToRouteSchema<S> = S extends ZodType ? RouteSchema<z.output<S>> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg> = Prettify<\n Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'> & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\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 (overrides inferred params). */\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\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 /** @internal flag used to track whether paramsSchema was explicitly provided. */\n [paramsOverrideSymbol]?: true\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]\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 RouteSchemaFromZod<T extends ZodType | undefined> = T extends ZodType\n ? RouteSchema<z.output<T>>\n : undefined\n\ntype MergeRouteSchemas<\n Existing extends RouteSchema | undefined,\n Parent extends ZodType | undefined,\n> = Existing extends RouteSchema<infer ExistingOut>\n ? Parent extends ZodType\n ? RouteSchema<ExistingOut & z.output<Parent>>\n : Existing\n : Parent extends ZodType\n ? RouteSchemaFromZod<Parent>\n : undefined\n\ntype AugmentedCfg<\n Cfg extends MethodCfgLowProfile,\n Param extends ZodType | undefined,\n> = Prettify<\n Omit<Cfg, 'paramsSchema'> &\n (Cfg[typeof paramsOverrideSymbol] extends true\n ? {\n paramsSchema: Cfg['paramsSchema']\n [paramsOverrideSymbol]: true\n }\n : {\n paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>\n })\n>\n\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n Acc extends readonly LeafLowProfile[] = [],\n> = R extends readonly [infer First, ...infer Rest]\n ? First extends LeafLowProfile\n ? AugmentLeaves<\n P,\n Param,\n Rest extends readonly LeafLowProfile[] ? Rest : [],\n Append<\n Acc,\n LeafLowProfile<\n First['method'],\n `${P}${First['path']}`,\n AugmentedCfg<First['cfg'], Param>\n >\n >\n >\n : never\n : Acc\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\nexport function buildCacheKey<L extends AnyLeaf>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}) {\n let p = args.leaf.path\n if (args.params) {\n p = compilePath<L['path']>(p, args.params)\n }\n return [\n args.leaf.method,\n ...(p.split('/').filter(Boolean) as SplitPath<typeof p>),\n args.query ?? {},\n ] as const\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' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\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 Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n cfg: Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed'\n > & {\n feed: Feed\n bodySchema: B extends ZodType ? RouteSchema<z.infer<B>> : undefined\n querySchema: Q extends ZodType ? RouteSchema<z.infer<Q>> : undefined\n paramsSchema: P extends ZodType ? RouteSchema<z.infer<P>> : undefined\n outputSchema: O extends ZodType ? RouteSchema<z.infer<O>> : undefined\n }\n >\n>\nexport function buildLowProfileLeaf(leaf: any): any {\n return {\n ...leaf,\n cfg: {\n ...leaf.cfg,\n bodySchema: leaf.cfg.bodySchema as RouteSchema<\n z.infer<typeof leaf.cfg.bodySchema>\n >,\n querySchema: leaf.cfg.querySchema as RouteSchema<\n z.infer<typeof leaf.cfg.querySchema>\n >,\n paramsSchema: leaf.cfg.paramsSchema as RouteSchema<\n z.infer<typeof leaf.cfg.paramsSchema>\n >,\n outputSchema: leaf.cfg.outputSchema as RouteSchema<\n z.infer<typeof leaf.cfg.outputSchema>\n >,\n },\n }\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer P> ? P : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeaf, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer Q> ? Q : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeaf, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer B> ? B : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\nexport type InferOutput<L extends AnyLeaf, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O> ? O : 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","// TODO:\n// * use this as a transform that infers the types from Zod, to only pass the types around instead of the full schemas -> make converters that go both ways (data to schema, schema to data)\n// * consider moving to core package\n// * update server and client side to use this type instead of raw zod schemas\nimport { 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\n/**\n * Freeze a leaf tuple into a registry with typed key lookups.\n * @param leaves Readonly tuple of leaves produced by the builder DSL.\n * @returns Registry containing the leaves array and a `byKey` lookup map.\n */\nexport function finalize<const L extends readonly AnyLeafLowProfile[]>(\n leaves: L,\n) {\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\n/** Nominal type alias for a finalized registry. */\nexport type Registry<R extends ReturnType<typeof finalize>> = R\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","// 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":[]}
|
|
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 } from 'zod'\nimport {\n AnyLeaf,\n AnyLeafLowProfile,\n Append,\n AugmentLeaves,\n HttpMethod,\n Leaf,\n LowProfileCfg,\n Merge,\n MergeArray,\n MethodCfg,\n NodeCfg,\n Prettify,\n} from './routesV3.core'\n\nconst paginationQueryShape = {\n pagination_cursor: z.string().optional(),\n pagination_limit: z.coerce.number().min(1).max(100).default(20),\n}\n\nconst defaultFeedQuerySchema = z.object(paginationQueryShape)\ntype PaginationShape = typeof paginationQueryShape\n\ntype ZodTypeAny = z.ZodTypeAny\ntype ParamZod<Name extends string, S extends ZodTypeAny> = z.ZodObject<{\n [K in Name]: S\n}>\ntype ZodArrayAny = z.ZodArray<ZodTypeAny>\ntype ZodObjectAny = z.ZodObject<any>\ntype AnyZodObject = z.ZodObject<any>\ntype MergedParamsResult<\n PS,\n Name extends string,\n P extends ZodTypeAny,\n> = PS extends ZodTypeAny\n ? z.ZodIntersection<PS, ParamZod<Name, P>>\n : ParamZod<Name, P>\n\nfunction getZodShape(schema: ZodObjectAny) {\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\nfunction collectNestedFieldSuggestions(\n shape: Record<string, ZodTypeAny> | 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 ZodObjectAny)\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\nconst defaultFeedOutputSchema = z.object({\n items: z.array(z.unknown()),\n nextCursor: z.string().optional(),\n})\n\nfunction augmentFeedQuerySchema<Q extends ZodTypeAny | undefined>(schema: Q) {\n if (schema && !(schema instanceof z.ZodObject)) {\n console.warn(\n 'Feed queries must be a ZodObject; default pagination applied.',\n )\n return defaultFeedQuerySchema\n }\n\n const base = (schema as ZodObjectAny) ?? z.object({})\n const shape = getZodShape(base)\n const nestedSuggestions = collectNestedFieldSuggestions(shape)\n if (nestedSuggestions.length) {\n console.warn(\n `Feed query schemas should avoid nested objects; consider flattening fields like: ${nestedSuggestions.join(\n ', ',\n )}`,\n )\n }\n return base.extend(paginationQueryShape)\n}\n\nfunction augmentFeedOutputSchema<O extends ZodTypeAny | undefined>(schema: O) {\n if (!schema) return defaultFeedOutputSchema\n if (schema instanceof z.ZodArray) {\n return z.object({\n items: schema,\n nextCursor: z.string().optional(),\n })\n }\n if (schema instanceof z.ZodObject) {\n const shape = (schema as any).shape\n ? (schema as any).shape\n : (schema as any)._def?.shape?.()\n const hasItems = Boolean(shape?.items)\n if (hasItems) {\n return schema.extend({ nextCursor: z.string().optional() })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\n }\n return z.object({\n items: z.array(schema as ZodTypeAny),\n nextCursor: z.string().optional(),\n })\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 */\nfunction mergeSchemas<A extends ZodTypeAny, B extends ZodTypeAny>(\n a: A,\n b: B,\n): ZodTypeAny\nfunction mergeSchemas<A extends ZodTypeAny>(a: A, b: undefined): A\nfunction mergeSchemas<B extends ZodTypeAny>(a: undefined, b: B): B\nfunction mergeSchemas(\n a: ZodTypeAny | undefined,\n b: ZodTypeAny | undefined,\n): ZodTypeAny | undefined\nfunction mergeSchemas(a: ZodTypeAny | undefined, b: ZodTypeAny | undefined) {\n if (a && b) return z.intersection(a as any, b as any)\n return (a ?? b) as ZodTypeAny | undefined\n}\n\ntype FeedOutputSchema<C extends MethodCfg> =\n C['outputSchema'] extends ZodArrayAny\n ? z.ZodObject<{\n items: C['outputSchema']\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : C['outputSchema'] extends ZodTypeAny\n ? z.ZodObject<{\n items: z.ZodArray<C['outputSchema']>\n nextCursor: z.ZodOptional<z.ZodString>\n }>\n : typeof defaultFeedOutputSchema\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 AddPaginationToQuery<Q extends AnyZodObject | undefined> =\n Q extends z.ZodObject<infer Shape>\n ? z.ZodObject<Shape & PaginationShape>\n : z.ZodObject<PaginationShape>\n\ntype FeedQueryField<C extends MethodCfg> = {\n querySchema: AddPaginationToQuery<\n C['querySchema'] extends AnyZodObject ? C['querySchema'] : undefined\n >\n}\n\ntype NonFeedQueryField<C extends MethodCfg> =\n C['querySchema'] extends ZodTypeAny\n ? { querySchema: C['querySchema'] }\n : { querySchema?: undefined }\n\ntype FeedOutputField<C extends MethodCfg> = {\n outputSchema: FeedOutputSchema<C>\n}\n\ntype NonFeedOutputField<C extends MethodCfg> =\n C['outputSchema'] extends ZodTypeAny\n ? { outputSchema: C['outputSchema'] }\n : { outputSchema?: undefined }\n\ntype ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodTypeAny\n ? { paramsSchema: C['paramsSchema'] }\n : { paramsSchema: PS }\n\ntype EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true\n ? FeedField<C> & FeedQueryField<C> & FeedOutputField<C> & ParamsField<C, PS>\n : FeedField<C> &\n NonFeedQueryField<C> &\n NonFeedOutputField<C> &\n ParamsField<C, PS>\n\ntype EffectiveCfg<C extends MethodCfg, PS> = Prettify<\n Merge<MethodCfg, BaseMethodCfg<C> & EffectiveFeedFields<C, PS>>\n>\n\ntype BuiltLeaf<\n M extends HttpMethod,\n Base extends string,\n I extends NodeCfg,\n C extends MethodCfg,\n PS,\n> = Leaf<M, Base, Merge<I, LowProfileCfg<EffectiveCfg<C, PS>>>>\n\ntype MethodFns<\n Base extends string,\n Acc extends readonly AnyLeafLowProfile[],\n I extends NodeCfg,\n PS extends ZodTypeAny | undefined,\n Used extends HttpMethod,\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 Base,\n Append<Acc, Prettify<BuiltLeaf<'get', Base, I, C, PS>>>,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'post', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'put', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'patch', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 Base,\n Append<\n Acc,\n Prettify<BuiltLeaf<'delete', Base, I, Merge<C, { feed: false }>, PS>>\n >,\n I,\n PS,\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 ZodTypeAny | undefined,\n Used extends HttpMethod = never,\n> extends MethodFns<Base, Acc, I, PS, Used> {\n /**\n * Mount a static subtree under `name`.\n * The `leaves` are built externally via `resource(...)` and will be\n * rebased so that their paths become `${Base}/${name}${leaf.path}` and their\n * paramsSchemas are merged with the parameters already accumulated on this branch.\n */\n sub<Name extends string, R extends readonly AnyLeafLowProfile[]>(\n name: Name,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n I,\n PS,\n Used\n >\n\n /**\n * Mount a static subtree under `name` and merge extra node-level config.\n */\n sub<\n Name extends string,\n J extends NodeCfg,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n cfg: J,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>,\n Merge<I, J>,\n PS,\n Used\n >\n\n /**\n * Introduce a `:param` segment and mount a pre-built subtree beneath it.\n * The subtree paths are rebased to `${Base}/:${Name}${leaf.path}` and\n * their paramsSchemas are intersected with the accumulated params plus this new param.\n */\n routeParameter<\n Name extends string,\n P extends ZodTypeAny,\n R extends readonly AnyLeafLowProfile[],\n >(\n name: Name,\n paramsSchema: P,\n leaves: R,\n ): Branch<\n Base,\n MergeArray<\n Acc,\n AugmentLeaves<`${Base}/:${Name}`, MergedParamsResult<PS, Name, P>, R>\n >,\n I,\n PS,\n Used\n >\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<Base extends string = '', I extends NodeCfg = {}>(\n base?: Base,\n inherited?: I,\n): Branch<Base, readonly [], I, undefined> {\n const rootBase = (base ?? '') as Base\n const rootInherited: NodeCfg = { ...(inherited as NodeCfg) }\n\n function makeBranch<\n Base2 extends string,\n I2 extends NodeCfg,\n PS2 extends ZodTypeAny | undefined,\n >(base2: Base2, inherited2: I2, mergedParamsSchema?: PS2) {\n const stack: AnyLeaf[] = []\n let currentBase: string = base2\n let inheritedCfg: NodeCfg = { ...(inherited2 as NodeCfg) }\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 effectiveQuerySchema =\n cfg.feed === true\n ? augmentFeedQuerySchema(cfg.querySchema)\n : cfg.querySchema\n const effectiveOutputSchema =\n cfg.feed === true\n ? augmentFeedOutputSchema(cfg.outputSchema)\n : cfg.outputSchema\n\n const fullCfg = (\n effectiveParamsSchema\n ? {\n ...inheritedCfg,\n ...cfg,\n paramsSchema: effectiveParamsSchema,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n : {\n ...inheritedCfg,\n ...cfg,\n ...(effectiveQuerySchema\n ? { querySchema: effectiveQuerySchema }\n : {}),\n ...(effectiveOutputSchema\n ? { outputSchema: effectiveOutputSchema }\n : {}),\n }\n ) as any\n\n const leaf = {\n method,\n path: currentBase as Base2,\n cfg: fullCfg,\n } as const\n\n stack.push(leaf as unknown as AnyLeaf)\n\n return api\n }\n\n const api: any = {\n /**\n * Mount a subtree built elsewhere.\n *\n * Usage:\n * const users = resource('').get(...).done()\n * resource('/api').sub('users', users).done()\n */\n sub<Name extends string>(\n name: Name,\n cfgOrLeaves?: NodeCfg | readonly AnyLeafLowProfile[],\n maybeLeaves?: readonly AnyLeafLowProfile[],\n ) {\n let cfg: NodeCfg | undefined\n let leaves: readonly AnyLeafLowProfile[] | undefined\n\n if (Array.isArray(cfgOrLeaves)) {\n leaves = cfgOrLeaves\n } else {\n cfg = cfgOrLeaves as NodeCfg | undefined\n leaves = maybeLeaves\n }\n\n if (!leaves) {\n throw new Error('sub() expects a leaves array as the last argument')\n }\n\n const childInherited: NodeCfg = {\n ...inheritedCfg,\n ...(cfg ?? {}),\n }\n\n const baseForChildren = `${currentBase}/${name}`\n\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 ZodTypeAny | undefined\n\n const effectiveParams = mergeSchemas(\n currentParamsSchema as any,\n leafParams,\n )\n\n const newCfg: MethodCfg = {\n ...childInherited,\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: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\n }\n\n return api\n },\n\n /**\n * Introduce a :param segment and mount a subtree under it.\n *\n * The subtree is built independently (e.g. resource('').get(...).done())\n * and its paths become `${currentBase}/:${name}${leaf.path}`.\n * Params schemas are intersected with the accumulated params plus the new param.\n */\n routeParameter<Name extends string, P extends ZodTypeAny>(\n name: Name,\n paramsSchema: P,\n leaves: readonly AnyLeafLowProfile[],\n ) {\n const paramObj: ParamZod<Name, P> = z.object({\n [name]: paramsSchema,\n } as Record<Name, P>)\n\n const mergedParams = (\n currentParamsSchema\n ? mergeSchemas(currentParamsSchema as any, paramObj)\n : paramObj\n ) as PS2\n\n const baseForChildren = `${currentBase}/:${name}`\n\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 ZodTypeAny | undefined\n\n const effectiveParams = mergeSchemas(mergedParams as any, leafParams)\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: `${baseForChildren}${leaf.path}` as string,\n cfg: newCfg,\n }\n\n stack.push(newLeaf)\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(rootBase, rootInherited, undefined)\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","import { z, 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 type NodeCfg = {\n /** @deprecated. Does nothing. */\n authenticated?: boolean\n}\n\nexport type RouteSchema<Output = unknown> = ZodType & {\n __out: Output\n}\n\nexport type RouteSchemaOutput<Schema extends ZodType> = Schema extends {\n __out: infer Out\n}\n ? Out\n : z.output<Schema>\n\nexport const lowProfileParse = <T extends RouteSchema>(\n schema: T,\n data: unknown,\n): RouteSchemaOutput<T> => {\n return schema.parse(data) as RouteSchemaOutput<T>\n}\n\nexport type ToRouteSchema<S> = S extends ZodType ? RouteSchema<z.output<S>> : S\n\nexport type LowProfileCfg<Cfg extends MethodCfg> = Prettify<\n Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'> & {\n bodySchema: ToRouteSchema<Cfg['bodySchema']>\n querySchema: ToRouteSchema<Cfg['querySchema']>\n paramsSchema: ToRouteSchema<Cfg['paramsSchema']>\n outputSchema: ToRouteSchema<Cfg['outputSchema']>\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 sub and routeParameter). */\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\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]\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 RouteSchemaFromZod<T extends ZodType | undefined> = T extends ZodType\n ? RouteSchema<z.output<T>>\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\n ? RouteSchema<ExistingOut & z.output<Parent>>\n : Existing\n : Parent extends ZodType\n ? RouteSchemaFromZod<Parent>\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\nexport type AugmentLeaves<\n P extends string,\n Param extends ZodType | undefined,\n R extends readonly LeafLowProfile[],\n Acc extends readonly LeafLowProfile[] = [],\n> = R extends readonly [infer First, ...infer Rest]\n ? First extends LeafLowProfile\n ? AugmentLeaves<\n P,\n Param,\n Rest extends readonly LeafLowProfile[] ? Rest : [],\n Append<\n Acc,\n LeafLowProfile<\n First['method'],\n `${P}${First['path']}`,\n AugmentedCfg<First['cfg'], Param>\n >\n >\n >\n : never\n : Acc\n// helpers (optional)\ntype SegmentParams<S extends string> = S extends `:${infer P}` ? P : never\ntype Split<S extends string> = S extends ''\n ? []\n : S extends `${infer A}/${infer B}`\n ? [A, ...Split<B>]\n : [S]\ntype ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>\n\n/** Derive a params object type from a literal route string. */\nexport type ExtractParamsFromPath<Path extends string> =\n ExtractParamNames<Path> extends never\n ? never\n : Record<ExtractParamNames<Path>, string | number>\n\n/**\n * Interpolate `:params` in a path using the given values.\n * @param path Literal route string containing `:param` segments.\n * @param params Object of parameter values to interpolate.\n * @returns Path string with parameters substituted.\n */\nexport function compilePath<Path extends string>(\n path: Path,\n params: ExtractParamsFromPath<Path>,\n) {\n if (!params) return path\n return path.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {\n const v = (params as any)[k]\n if (v === undefined || v === null) throw new Error(`Missing param :${k}`)\n return String(v)\n })\n}\n\n/**\n * Build a deterministic cache key for the given leaf.\n * The key matches the shape consumed by React Query helpers.\n * @param args.leaf Leaf describing the endpoint.\n * @param args.params Optional params used to build the path.\n * @param args.query Optional query payload.\n * @returns Tuple suitable for React Query cache keys.\n */\ntype SplitPath<P extends string> = P extends ''\n ? []\n : P extends `${infer A}/${infer B}`\n ? [A, ...SplitPath<B>]\n : [P]\nexport function buildCacheKey<L extends AnyLeaf>(args: {\n leaf: L\n params?: ExtractParamsFromPath<L['path']>\n query?: InferQuery<L>\n}) {\n let p = args.leaf.path\n if (args.params) {\n p = compilePath<L['path']>(p, args.params)\n }\n return [\n args.leaf.method,\n ...(p.split('/').filter(Boolean) as SplitPath<typeof p>),\n args.query ?? {},\n ] as const\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' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n> & {\n bodySchema?: RouteSchema\n querySchema?: RouteSchema\n paramsSchema?: RouteSchema\n outputSchema?: RouteSchema\n}\nexport type AnyLeafLowProfile = LeafLowProfile<\n HttpMethod,\n string,\n MethodCfgLowProfile\n>\n\nexport function buildLowProfileLeaf<\n const M extends HttpMethod,\n const Path extends string,\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 Feed extends boolean = false,\n>(leaf: {\n method: M\n path: Path\n cfg: Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema'\n > & {\n feed?: Feed\n bodySchema?: B\n querySchema?: Q\n paramsSchema?: P\n outputSchema?: O\n }\n}): LeafLowProfile<\n M,\n Path,\n Prettify<\n Omit<\n MethodCfg,\n 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed'\n > & {\n feed: Feed\n bodySchema: B extends ZodType ? RouteSchema<z.infer<B>> : undefined\n querySchema: Q extends ZodType ? RouteSchema<z.infer<Q>> : undefined\n paramsSchema: P extends ZodType ? RouteSchema<z.infer<P>> : undefined\n outputSchema: O extends ZodType ? RouteSchema<z.infer<O>> : undefined\n }\n >\n>\nexport function buildLowProfileLeaf(leaf: any): any {\n return {\n ...leaf,\n cfg: {\n ...leaf.cfg,\n bodySchema: leaf.cfg.bodySchema as RouteSchema<\n z.infer<typeof leaf.cfg.bodySchema>\n >,\n querySchema: leaf.cfg.querySchema as RouteSchema<\n z.infer<typeof leaf.cfg.querySchema>\n >,\n paramsSchema: leaf.cfg.paramsSchema as RouteSchema<\n z.infer<typeof leaf.cfg.paramsSchema>\n >,\n outputSchema: leaf.cfg.outputSchema as RouteSchema<\n z.infer<typeof leaf.cfg.outputSchema>\n >,\n },\n }\n}\n\nexport type LeafLowProfile<\n M extends HttpMethod = HttpMethod,\n P extends string = string,\n C extends MethodCfgLowProfile = MethodCfgLowProfile,\n> = {\n /** Lowercase HTTP method (get/post/...). */\n readonly method: M\n /** Concrete path for the route (e.g. `/v1/users/:userId`). */\n readonly path: P\n /** Readonly snapshot of route configuration. */\n readonly cfg: Readonly<C>\n}\n/** Infer params either from the explicit params schema or from the path literal. */\nexport type InferParams<L extends AnyLeafLowProfile, Fallback = never> =\n L['cfg']['paramsSchema'] extends RouteSchema<infer P> ? P : Fallback\n\n/** Infer query shape from a Zod schema when present. */\nexport type InferQuery<L extends AnyLeaf, Fallback = never> =\n L['cfg']['querySchema'] extends RouteSchema<infer Q> ? Q : Fallback\n\n/** Infer request body shape from a Zod schema when present. */\nexport type InferBody<L extends AnyLeaf, Fallback = never> =\n L['cfg']['bodySchema'] extends RouteSchema<infer B> ? B : Fallback\n\n/** Infer handler output shape from a Zod schema. Defaults to unknown. */\nexport type InferOutput<L extends AnyLeaf, Fallback = never> =\n L['cfg']['outputSchema'] extends RouteSchema<infer O> ? O : 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":[]}
|