@cosmneo/onion-lasagna 0.2.0 → 0.2.1
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/{chunk-GGSAAZPM.js → chunk-AUMHMWDD.js} +19 -20
- package/dist/chunk-AUMHMWDD.js.map +1 -0
- package/dist/chunk-H5TNDC5U.js +138 -0
- package/dist/chunk-H5TNDC5U.js.map +1 -0
- package/dist/chunk-MF2JDREK.js +168 -0
- package/dist/chunk-MF2JDREK.js.map +1 -0
- package/dist/{chunk-PUVAB3JX.js → chunk-XIRJ73IO.js} +38 -36
- package/dist/chunk-XIRJ73IO.js.map +1 -0
- package/dist/{chunk-DS7TE6KZ.js → chunk-XP6PLTV2.js} +11 -3
- package/dist/chunk-XP6PLTV2.js.map +1 -0
- package/dist/global.js +3 -3
- package/dist/http/index.cjs +563 -93
- package/dist/http/index.cjs.map +1 -1
- package/dist/http/index.d.cts +4 -3
- package/dist/http/index.d.ts +4 -3
- package/dist/http/index.js +30 -12
- package/dist/http/openapi/index.cjs +43 -35
- package/dist/http/openapi/index.cjs.map +1 -1
- package/dist/http/openapi/index.d.cts +8 -34
- package/dist/http/openapi/index.d.ts +8 -34
- package/dist/http/openapi/index.js +2 -2
- package/dist/http/route/index.cjs +106 -9
- package/dist/http/route/index.cjs.map +1 -1
- package/dist/http/route/index.d.cts +133 -227
- package/dist/http/route/index.d.ts +133 -227
- package/dist/http/route/index.js +5 -2
- package/dist/http/server/index.cjs +24 -19
- package/dist/http/server/index.cjs.map +1 -1
- package/dist/http/server/index.d.cts +1 -1
- package/dist/http/server/index.d.ts +1 -1
- package/dist/http/server/index.js +2 -2
- package/dist/http/shared/index.cjs.map +1 -1
- package/dist/http/shared/index.d.cts +10 -14
- package/dist/http/shared/index.d.ts +10 -14
- package/dist/http/shared/index.js +11 -127
- package/dist/http/shared/index.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/{router-definition.type-ynBhT16T.d.cts → router-definition.type-BElX-Pl4.d.cts} +169 -256
- package/dist/{router-definition.type-DORVlLNk.d.ts → router-definition.type-DxG8ncJZ.d.ts} +169 -256
- package/package.json +1 -1
- package/dist/chunk-BZULBF4N.js +0 -82
- package/dist/chunk-BZULBF4N.js.map +0 -1
- package/dist/chunk-DS7TE6KZ.js.map +0 -1
- package/dist/chunk-GGSAAZPM.js.map +0 -1
- package/dist/chunk-PUVAB3JX.js.map +0 -1
|
@@ -24,6 +24,7 @@ __export(route_exports, {
|
|
|
24
24
|
collectRoutes: () => collectRoutes,
|
|
25
25
|
defineRoute: () => defineRoute,
|
|
26
26
|
defineRouter: () => defineRouter,
|
|
27
|
+
generateOperationId: () => generateOperationId,
|
|
27
28
|
getPathParamNames: () => getPathParamNames,
|
|
28
29
|
hasPathParams: () => hasPathParams,
|
|
29
30
|
isRouteDefinition: () => isRouteDefinition,
|
|
@@ -34,19 +35,61 @@ __export(route_exports, {
|
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(route_exports);
|
|
36
37
|
|
|
38
|
+
// src/presentation/http/schema/types/schema-adapter.type.ts
|
|
39
|
+
function isSchemaAdapter(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && "validate" in value && typeof value.validate === "function" && "toJsonSchema" in value && typeof value.toJsonSchema === "function";
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
// src/presentation/http/route/define-route.ts
|
|
44
|
+
function extractSchema(field) {
|
|
45
|
+
if (field == null) return void 0;
|
|
46
|
+
if (isSchemaAdapter(field)) return field;
|
|
47
|
+
return field.schema;
|
|
48
|
+
}
|
|
49
|
+
function extractMeta(field) {
|
|
50
|
+
if (field == null || isSchemaAdapter(field)) return void 0;
|
|
51
|
+
const config = field;
|
|
52
|
+
if (config.description == null && config.contentType == null && config.required == null) {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
description: config.description,
|
|
57
|
+
contentType: config.contentType,
|
|
58
|
+
required: config.required
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function normalizeResponses(responses) {
|
|
62
|
+
const result = {};
|
|
63
|
+
for (const [key, value] of Object.entries(responses)) {
|
|
64
|
+
result[String(key)] = value;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
38
68
|
function defineRoute(input) {
|
|
69
|
+
const req = input.request;
|
|
70
|
+
const bodyMeta = extractMeta(req?.body);
|
|
71
|
+
const queryMeta = extractMeta(req?.query);
|
|
72
|
+
const paramsMeta = extractMeta(req?.params);
|
|
73
|
+
const headersMeta = extractMeta(req?.headers);
|
|
74
|
+
const contextMeta = extractMeta(req?.context);
|
|
75
|
+
const _meta = {
|
|
76
|
+
...bodyMeta ? { body: bodyMeta } : {},
|
|
77
|
+
...queryMeta ? { query: { description: queryMeta.description } } : {},
|
|
78
|
+
...paramsMeta ? { params: { description: paramsMeta.description } } : {},
|
|
79
|
+
...headersMeta ? { headers: { description: headersMeta.description } } : {},
|
|
80
|
+
...contextMeta ? { context: { description: contextMeta.description } } : {}
|
|
81
|
+
};
|
|
39
82
|
const definition = {
|
|
40
83
|
method: input.method,
|
|
41
84
|
path: input.path,
|
|
42
85
|
request: {
|
|
43
|
-
body:
|
|
44
|
-
query:
|
|
45
|
-
params:
|
|
46
|
-
headers:
|
|
47
|
-
context:
|
|
86
|
+
body: extractSchema(req?.body) ?? void 0,
|
|
87
|
+
query: extractSchema(req?.query) ?? void 0,
|
|
88
|
+
params: extractSchema(req?.params) ?? void 0,
|
|
89
|
+
headers: extractSchema(req?.headers) ?? void 0,
|
|
90
|
+
context: extractSchema(req?.context) ?? void 0
|
|
48
91
|
},
|
|
49
|
-
responses: input.responses,
|
|
92
|
+
responses: input.responses ? normalizeResponses(input.responses) : void 0,
|
|
50
93
|
docs: {
|
|
51
94
|
summary: input.docs?.summary,
|
|
52
95
|
description: input.docs?.description,
|
|
@@ -56,6 +99,7 @@ function defineRoute(input) {
|
|
|
56
99
|
security: input.docs?.security,
|
|
57
100
|
externalDocs: input.docs?.externalDocs
|
|
58
101
|
},
|
|
102
|
+
_meta,
|
|
59
103
|
_types: void 0
|
|
60
104
|
};
|
|
61
105
|
return Object.freeze(definition);
|
|
@@ -88,7 +132,7 @@ function normalizePath(path) {
|
|
|
88
132
|
|
|
89
133
|
// src/presentation/http/route/types/router-definition.type.ts
|
|
90
134
|
function isRouteDefinition(value) {
|
|
91
|
-
return typeof value === "object" && value !== null && "method" in value && "path" in value && "
|
|
135
|
+
return typeof value === "object" && value !== null && "method" in value && "path" in value && "_types" in value;
|
|
92
136
|
}
|
|
93
137
|
function isRouterDefinition(value) {
|
|
94
138
|
return typeof value === "object" && value !== null && "_isRouter" in value && value._isRouter === true;
|
|
@@ -110,14 +154,59 @@ function collectRoutes(config, basePath = "") {
|
|
|
110
154
|
|
|
111
155
|
// src/presentation/http/route/define-router.ts
|
|
112
156
|
function defineRouter(routes, options) {
|
|
157
|
+
const defaults = options?.defaults;
|
|
158
|
+
const processedRoutes = defaults?.context || defaults?.tags ? applyRouterDefaults(routes, defaults) : routes;
|
|
113
159
|
const definition = {
|
|
114
|
-
routes,
|
|
160
|
+
routes: processedRoutes,
|
|
115
161
|
basePath: options?.basePath,
|
|
116
|
-
|
|
162
|
+
defaults,
|
|
117
163
|
_isRouter: true
|
|
118
164
|
};
|
|
119
165
|
return deepFreeze(definition);
|
|
120
166
|
}
|
|
167
|
+
function applyRouterDefaults(routes, defaults) {
|
|
168
|
+
const result = {};
|
|
169
|
+
for (const [key, value] of Object.entries(routes)) {
|
|
170
|
+
if (isRouteDefinition(value)) {
|
|
171
|
+
result[key] = applyDefaultsToRoute(value, defaults);
|
|
172
|
+
} else if (isRouterDefinition(value)) {
|
|
173
|
+
result[key] = {
|
|
174
|
+
...value,
|
|
175
|
+
routes: applyRouterDefaults(value.routes, defaults)
|
|
176
|
+
};
|
|
177
|
+
} else if (typeof value === "object" && value !== null) {
|
|
178
|
+
result[key] = applyRouterDefaults(value, defaults);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
function applyDefaultsToRoute(route, defaults) {
|
|
184
|
+
const needsContext = defaults.context && !route.request.context;
|
|
185
|
+
const needsTags = defaults.tags && defaults.tags.length > 0;
|
|
186
|
+
if (!needsContext && !needsTags) return route;
|
|
187
|
+
return Object.freeze({
|
|
188
|
+
...route,
|
|
189
|
+
request: {
|
|
190
|
+
...route.request,
|
|
191
|
+
context: route.request.context ?? defaults.context ?? void 0
|
|
192
|
+
},
|
|
193
|
+
docs: {
|
|
194
|
+
...route.docs,
|
|
195
|
+
tags: mergeTags(defaults.tags, route.docs.tags)
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function mergeTags(routerTags, routeTags) {
|
|
200
|
+
if (!routerTags || routerTags.length === 0) return routeTags;
|
|
201
|
+
if (!routeTags || routeTags.length === 0) return routerTags;
|
|
202
|
+
const merged = [...routerTags];
|
|
203
|
+
for (const tag of routeTags) {
|
|
204
|
+
if (!merged.includes(tag)) {
|
|
205
|
+
merged.push(tag);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return merged;
|
|
209
|
+
}
|
|
121
210
|
function deepFreeze(obj) {
|
|
122
211
|
const propNames = Object.getOwnPropertyNames(obj);
|
|
123
212
|
for (const name of propNames) {
|
|
@@ -151,12 +240,20 @@ function mergeRouters(...routers) {
|
|
|
151
240
|
const merged = routers.map(extractRoutes).reduce(deepMergeConfigs);
|
|
152
241
|
return defineRouter(merged);
|
|
153
242
|
}
|
|
243
|
+
|
|
244
|
+
// src/presentation/http/route/utils.ts
|
|
245
|
+
function generateOperationId(key) {
|
|
246
|
+
return key.split(".").map(
|
|
247
|
+
(segment, index) => index === 0 ? segment : segment.charAt(0).toUpperCase() + segment.slice(1)
|
|
248
|
+
).join("");
|
|
249
|
+
}
|
|
154
250
|
// Annotate the CommonJS export names for ESM import in node:
|
|
155
251
|
0 && (module.exports = {
|
|
156
252
|
buildPath,
|
|
157
253
|
collectRoutes,
|
|
158
254
|
defineRoute,
|
|
159
255
|
defineRouter,
|
|
256
|
+
generateOperationId,
|
|
160
257
|
getPathParamNames,
|
|
161
258
|
hasPathParams,
|
|
162
259
|
isRouteDefinition,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/http/route/index.ts","../../../src/presentation/http/route/define-route.ts","../../../src/presentation/http/route/types/path-params.type.ts","../../../src/presentation/http/route/types/router-definition.type.ts","../../../src/presentation/http/route/define-router.ts"],"sourcesContent":["/**\n * @fileoverview Route module exports.\n *\n * This module provides route and router definition functions and types\n * for the unified system.\n *\n * @module unified/route\n *\n * @example Define a route\n * ```typescript\n * import { defineRoute } from '@cosmneo/onion-lasagna/http';\n * import { zodSchema, z } from '@cosmneo/onion-lasagna/http/schema/zod';\n *\n * const getUser = defineRoute({\n * method: 'GET',\n * path: '/api/users/:userId',\n * responses: {\n * 200: {\n * description: 'User found',\n * schema: zodSchema(z.object({\n * id: z.string(),\n * name: z.string(),\n * })),\n * },\n * 404: { description: 'User not found' },\n * },\n * });\n * ```\n *\n * @example Define a router\n * ```typescript\n * import { defineRouter } from '@cosmneo/onion-lasagna/http';\n *\n * const api = defineRouter({\n * users: {\n * get: getUserRoute,\n * list: listUsersRoute,\n * create: createUserRoute,\n * },\n * });\n * ```\n */\n\n// Export factory functions\nexport { defineRoute } from './define-route';\nexport { defineRouter, mergeRouters } from './define-router';\nexport type { DefineRouterOptions } from './define-router';\n\n// Export all types\nexport * from './types';\n","/**\n * @fileoverview Factory function for creating route definitions.\n *\n * The `defineRoute` function is the main entry point for defining routes\n * in the unified system. It provides type inference and validation\n * for route configurations.\n *\n * @module unified/route/define-route\n */\n\nimport type { SchemaAdapter, InferOutput } from '../schema/types';\nimport type { HttpMethod, ResponsesConfig, RouteDefinition, PathParams } from './types';\n\n// ============================================================================\n// Input Types\n// ============================================================================\n\n/**\n * Request body configuration input.\n */\ninterface BodyInput<TSchema extends SchemaAdapter> {\n readonly schema: TSchema;\n readonly contentType?: string;\n readonly required?: boolean;\n readonly description?: string;\n}\n\n/**\n * Query parameters configuration input.\n */\ninterface QueryInput<TSchema extends SchemaAdapter> {\n readonly schema: TSchema;\n readonly description?: string;\n}\n\n/**\n * Path parameters configuration input.\n */\ninterface ParamsInput<TSchema extends SchemaAdapter> {\n readonly schema: TSchema;\n readonly description?: string;\n}\n\n/**\n * Headers configuration input.\n */\ninterface HeadersInput<TSchema extends SchemaAdapter> {\n readonly schema: TSchema;\n readonly description?: string;\n}\n\n/**\n * Context configuration input.\n * Used to validate and type context data from middleware (e.g., JWT payload).\n */\ninterface ContextInput<TSchema extends SchemaAdapter> {\n readonly schema: TSchema;\n readonly description?: string;\n}\n\n/**\n * Response configuration input.\n */\ninterface ResponseInput<TSchema extends SchemaAdapter | undefined = undefined> {\n readonly description: string;\n readonly schema?: TSchema;\n readonly contentType?: string;\n}\n\n/**\n * Complete input for defineRoute.\n */\ninterface DefineRouteInput<\n TMethod extends HttpMethod,\n TPath extends string,\n TBody extends SchemaAdapter | undefined = undefined,\n TQuery extends SchemaAdapter | undefined = undefined,\n TParams extends SchemaAdapter | undefined = undefined,\n THeaders extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n TResponses extends Record<number, ResponseInput<SchemaAdapter | undefined>> = Record<\n number,\n never\n >,\n> {\n readonly method: TMethod;\n readonly path: TPath;\n readonly request?: {\n readonly body?: TBody extends SchemaAdapter ? BodyInput<TBody> : undefined;\n readonly query?: TQuery extends SchemaAdapter ? QueryInput<TQuery> : undefined;\n readonly params?: TParams extends SchemaAdapter ? ParamsInput<TParams> : undefined;\n readonly headers?: THeaders extends SchemaAdapter ? HeadersInput<THeaders> : undefined;\n readonly context?: TContext extends SchemaAdapter ? ContextInput<TContext> : undefined;\n };\n readonly responses: TResponses;\n readonly docs?: {\n readonly summary?: string;\n readonly description?: string;\n readonly tags?: readonly string[];\n readonly operationId?: string;\n readonly deprecated?: boolean;\n readonly security?: readonly Record<string, readonly string[]>[];\n readonly externalDocs?: {\n readonly url: string;\n readonly description?: string;\n };\n };\n}\n\n// ============================================================================\n// Output Types\n// ============================================================================\n\n/**\n * Converts response inputs to response config type.\n */\ntype ToResponsesConfig<T extends Record<number, ResponseInput<SchemaAdapter | undefined>>> = {\n [K in keyof T]: T[K] extends ResponseInput<infer TSchema>\n ? {\n description: string;\n schema: TSchema extends SchemaAdapter ? TSchema : undefined;\n contentType?: string;\n }\n : never;\n};\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Creates a route definition from the provided configuration.\n *\n * This is the main entry point for defining routes in the unified system.\n * The resulting definition can be used for:\n * - Type-safe client generation\n * - Server-side route registration\n * - OpenAPI specification generation\n *\n * @param input - Route configuration\n * @returns A frozen RouteDefinition object with full type information\n *\n * @example Basic GET route\n * ```typescript\n * import { defineRoute } from '@cosmneo/onion-lasagna/http';\n * import { zodSchema, z } from '@cosmneo/onion-lasagna/http/schema/zod';\n *\n * const listUsers = defineRoute({\n * method: 'GET',\n * path: '/api/users',\n * request: {\n * query: {\n * schema: zodSchema(z.object({\n * page: z.coerce.number().optional().default(1),\n * limit: z.coerce.number().optional().default(20),\n * })),\n * },\n * },\n * responses: {\n * 200: {\n * description: 'List of users',\n * schema: zodSchema(z.object({\n * users: z.array(z.object({\n * id: z.string(),\n * name: z.string(),\n * })),\n * total: z.number(),\n * })),\n * },\n * },\n * docs: {\n * summary: 'List all users',\n * tags: ['Users'],\n * },\n * });\n * ```\n *\n * @example POST route with path parameters\n * ```typescript\n * const createTask = defineRoute({\n * method: 'POST',\n * path: '/api/projects/:projectId/tasks',\n * request: {\n * body: {\n * schema: zodSchema(z.object({\n * title: z.string().min(1).max(200),\n * description: z.string().optional(),\n * })),\n * },\n * },\n * responses: {\n * 201: {\n * description: 'Task created',\n * schema: zodSchema(z.object({\n * id: z.string().uuid(),\n * title: z.string(),\n * projectId: z.string(),\n * createdAt: z.string().datetime(),\n * })),\n * },\n * 400: {\n * description: 'Invalid request',\n * },\n * 404: {\n * description: 'Project not found',\n * },\n * },\n * docs: {\n * summary: 'Create a new task',\n * tags: ['Tasks'],\n * operationId: 'createTask',\n * },\n * });\n * ```\n */\nexport function defineRoute<\n TMethod extends HttpMethod,\n TPath extends string,\n TBody extends SchemaAdapter | undefined = undefined,\n TQuery extends SchemaAdapter | undefined = undefined,\n TParams extends SchemaAdapter | undefined = undefined,\n THeaders extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n TResponses extends Record<number, ResponseInput<SchemaAdapter | undefined>> = Record<\n number,\n never\n >,\n>(\n input: DefineRouteInput<TMethod, TPath, TBody, TQuery, TParams, THeaders, TContext, TResponses>,\n): RouteDefinition<\n TMethod,\n TPath,\n TBody extends SchemaAdapter ? InferOutput<TBody> : undefined,\n TQuery extends SchemaAdapter ? InferOutput<TQuery> : undefined,\n TParams extends SchemaAdapter ? InferOutput<TParams> : PathParams<TPath>,\n THeaders extends SchemaAdapter ? InferOutput<THeaders> : undefined,\n TContext extends SchemaAdapter ? InferOutput<TContext> : undefined,\n ToResponsesConfig<TResponses> & ResponsesConfig\n> {\n const definition = {\n method: input.method,\n path: input.path,\n request: {\n body: input.request?.body ?? undefined,\n query: input.request?.query ?? undefined,\n params: input.request?.params ?? undefined,\n headers: input.request?.headers ?? undefined,\n context: input.request?.context ?? undefined,\n },\n responses: input.responses as ToResponsesConfig<TResponses> & ResponsesConfig,\n docs: {\n summary: input.docs?.summary,\n description: input.docs?.description,\n tags: input.docs?.tags,\n operationId: input.docs?.operationId,\n deprecated: input.docs?.deprecated ?? false,\n security: input.docs?.security,\n externalDocs: input.docs?.externalDocs,\n },\n _types: undefined as unknown,\n } as RouteDefinition<\n TMethod,\n TPath,\n TBody extends SchemaAdapter ? InferOutput<TBody> : undefined,\n TQuery extends SchemaAdapter ? InferOutput<TQuery> : undefined,\n TParams extends SchemaAdapter ? InferOutput<TParams> : PathParams<TPath>,\n THeaders extends SchemaAdapter ? InferOutput<THeaders> : undefined,\n TContext extends SchemaAdapter ? InferOutput<TContext> : undefined,\n ToResponsesConfig<TResponses> & ResponsesConfig\n >;\n\n // Freeze the definition to prevent accidental mutation\n return Object.freeze(definition);\n}\n","/**\n * @fileoverview Path parameter extraction types.\n *\n * These types enable TypeScript to extract path parameter names from\n * URL path templates at compile time, providing full type safety for\n * path parameters in routes.\n *\n * @module unified/route/types/path-params\n */\n\n/**\n * Extracts parameter names from a path template string.\n *\n * Supports both `:param` and `{param}` syntaxes for maximum compatibility\n * with different routing conventions.\n *\n * @example Colon syntax (Express-style)\n * ```typescript\n * type Params = ExtractPathParamNames<'/users/:userId/posts/:postId'>;\n * // 'userId' | 'postId'\n * ```\n *\n * @example Brace syntax (OpenAPI-style)\n * ```typescript\n * type Params = ExtractPathParamNames<'/users/{userId}/posts/{postId}'>;\n * // 'userId' | 'postId'\n * ```\n *\n * @example No parameters\n * ```typescript\n * type Params = ExtractPathParamNames<'/users'>;\n * // never\n * ```\n */\nexport type ExtractPathParamNames<T extends string> =\n // Match :param followed by more path\n T extends `${string}:${infer Param}/${infer Rest}`\n ? Param | ExtractPathParamNames<`/${Rest}`>\n : // Match :param at end\n T extends `${string}:${infer Param}`\n ? Param\n : // Match {param} followed by more path\n T extends `${string}{${infer Param}}/${infer Rest}`\n ? Param | ExtractPathParamNames<`/${Rest}`>\n : // Match {param} at end\n T extends `${string}{${infer Param}}`\n ? Param\n : never;\n\n/**\n * Creates an object type with all path parameters as string properties.\n *\n * @example\n * ```typescript\n * type Params = PathParams<'/projects/:projectId/tasks/:taskId'>;\n * // { projectId: string; taskId: string }\n *\n * type NoParams = PathParams<'/projects'>;\n * // Record<string, never> (empty object type)\n * ```\n */\nexport type PathParams<T extends string> =\n ExtractPathParamNames<T> extends never\n ? Record<string, never>\n : Record<ExtractPathParamNames<T>, string>;\n\n/**\n * Checks if a path has any parameters.\n *\n * @example\n * ```typescript\n * type HasParams = HasPathParams<'/users/:id'>; // true\n * type NoParams = HasPathParams<'/users'>; // false\n * ```\n */\nexport type HasPathParams<T extends string> = ExtractPathParamNames<T> extends never ? false : true;\n\n/**\n * Converts a path template with parameters to a regex pattern.\n * This is used internally for route matching.\n *\n * @example\n * ```typescript\n * pathToRegex('/users/:id/posts/:postId')\n * // /^\\/users\\/([^\\/]+)\\/posts\\/([^\\/]+)\\/?$/\n * ```\n */\nexport function pathToRegex(path: string): RegExp {\n const pattern = path\n // Escape special regex characters except : and {}\n .replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n // Replace :param with capture group\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '([^/]+)')\n // Replace {param} with capture group\n .replace(/\\\\\\{([a-zA-Z_][a-zA-Z0-9_]*)\\\\\\}/g, '([^/]+)');\n\n return new RegExp(`^${pattern}/?$`);\n}\n\n/**\n * Extracts parameter names from a path string at runtime.\n *\n * @example\n * ```typescript\n * getPathParamNames('/users/:userId/posts/:postId')\n * // ['userId', 'postId']\n * ```\n */\nexport function getPathParamNames(path: string): string[] {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- regex capture group always exists\n const colonParams = [...path.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)/g)].map((m) => m[1]!);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- regex capture group always exists\n const braceParams = [...path.matchAll(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g)].map((m) => m[1]!);\n return [...colonParams, ...braceParams];\n}\n\n/**\n * Checks if a path has any parameters at runtime.\n */\nexport function hasPathParams(path: string): boolean {\n return /:([a-zA-Z_][a-zA-Z0-9_]*)/.test(path) || /\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/.test(path);\n}\n\n/**\n * Replaces path parameters with actual values.\n *\n * @example\n * ```typescript\n * buildPath('/users/:userId/posts/:postId', { userId: '123', postId: '456' })\n * // '/users/123/posts/456'\n *\n * buildPath('/users/{userId}', { userId: '123' })\n * // '/users/123'\n * ```\n */\nexport function buildPath(template: string, params: Record<string, string>): string {\n let result = template;\n\n // Replace :param syntax\n for (const [key, value] of Object.entries(params)) {\n result = result.replace(`:${key}`, encodeURIComponent(value));\n result = result.replace(`{${key}}`, encodeURIComponent(value));\n }\n\n return result;\n}\n\n/**\n * Normalizes a path template to use consistent :param syntax.\n *\n * @example\n * ```typescript\n * normalizePath('/users/{userId}')\n * // '/users/:userId'\n * ```\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g, ':$1');\n}\n","/**\n * @fileoverview Router definition types for grouping routes.\n *\n * A router is a hierarchical grouping of routes that enables:\n * - Organized API structure\n * - Nested client method generation\n * - Grouped OpenAPI tags\n *\n * @module unified/route/types/router-definition\n */\n\nimport type { RouteDefinition, ResponsesConfig } from './route-definition.type';\nimport type { HttpMethod } from './http.type';\n\n// ============================================================================\n// Router Types\n// ============================================================================\n\n/**\n * A router entry can be either a route definition or a nested router.\n * Uses permissive types to allow any valid route definition.\n */\nexport type RouterEntry =\n | RouteDefinition<\n HttpMethod,\n string,\n unknown,\n unknown,\n unknown,\n unknown,\n unknown,\n ResponsesConfig\n >\n | RouterConfig;\n\n/**\n * Configuration for a router (group of routes).\n */\nexport interface RouterConfig {\n readonly [key: string]: RouterEntry;\n}\n\n/**\n * A fully defined router.\n */\nexport interface RouterDefinition<T extends RouterConfig = RouterConfig> {\n /**\n * The routes and nested routers in this router.\n */\n readonly routes: T;\n\n /**\n * Base path prefix for all routes in this router.\n */\n readonly basePath?: string;\n\n /**\n * Default tags for all routes in this router.\n */\n readonly tags?: readonly string[];\n\n /**\n * Marker to identify this as a router.\n * @internal\n */\n readonly _isRouter: true;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Checks if a value is a RouteDefinition.\n */\nexport function isRouteDefinition(value: unknown): value is RouteDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'method' in value &&\n 'path' in value &&\n 'responses' in value &&\n '_types' in value\n );\n}\n\n/**\n * Checks if a value is a RouterDefinition.\n */\nexport function isRouterDefinition(value: unknown): value is RouterDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n '_isRouter' in value &&\n (value as RouterDefinition)._isRouter === true\n );\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Flattens a router into a map of path keys to route definitions.\n *\n * @example\n * ```typescript\n * const router = defineRouter({\n * users: {\n * list: listUsersRoute,\n * get: getUserRoute,\n * },\n * posts: {\n * create: createPostRoute,\n * },\n * });\n *\n * type Flat = FlattenRouter<typeof router>;\n * // {\n * // 'users.list': typeof listUsersRoute,\n * // 'users.get': typeof getUserRoute,\n * // 'posts.create': typeof createPostRoute,\n * // }\n * ```\n */\nexport type FlattenRouter<\n T extends RouterConfig,\n Prefix extends string = '',\n> = T extends RouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? { [P in `${Prefix}${K & string}`]: T[K] }\n : T[K] extends RouterConfig\n ? FlattenRouter<T[K], `${Prefix}${K & string}.`>\n : never;\n }[keyof T] extends infer U\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n U extends Record<string, RouteDefinition<any, any, any, any, any, any, any, any>>\n ? U\n : never\n : never\n : never;\n\n/**\n * Gets all route keys from a router.\n *\n * @example\n * ```typescript\n * type Keys = RouterKeys<typeof router>;\n * // 'users.list' | 'users.get' | 'posts.create'\n * ```\n */\nexport type RouterKeys<T extends RouterConfig, Prefix extends string = ''> = T extends RouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? `${Prefix}${K & string}`\n : T[K] extends RouterConfig\n ? RouterKeys<T[K], `${Prefix}${K & string}.`>\n : never;\n }[keyof T]\n : never;\n\n/**\n * Gets a route by its dotted key path.\n *\n * @example\n * ```typescript\n * type UserGet = GetRoute<typeof router, 'users.get'>;\n * // typeof getUserRoute\n * ```\n */\nexport type GetRoute<\n T extends RouterConfig,\n K extends string,\n> = K extends `${infer Head}.${infer Tail}`\n ? Head extends keyof T\n ? T[Head] extends RouterConfig\n ? GetRoute<T[Head], Tail>\n : never\n : never\n : K extends keyof T\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? T[K]\n : never\n : never;\n\n// ============================================================================\n// Deep Merge Types\n// ============================================================================\n\n/**\n * Deep-merges two router configs at the type level.\n *\n * - If both sides are sub-routers (extend RouterConfig), recurse.\n * - Otherwise last-one-wins (B overrides A).\n * - RouteDefinition does NOT extend RouterConfig (it has `method`, `path`, etc.)\n * so the conditional correctly distinguishes leaves from sub-routers.\n */\nexport type DeepMergeTwo<A extends RouterConfig, B extends RouterConfig> = {\n readonly [K in keyof A | keyof B]: K extends keyof A\n ? K extends keyof B\n ? A[K] extends RouterConfig\n ? B[K] extends RouterConfig\n ? DeepMergeTwo<A[K], B[K]>\n : B[K]\n : B[K]\n : A[K]\n : K extends keyof B\n ? B[K]\n : never;\n};\n\n/**\n * Recursively deep-merges N router configs left-to-right.\n */\nexport type DeepMergeAll<T extends readonly RouterConfig[]> = T extends readonly [\n infer Only extends RouterConfig,\n]\n ? Only\n : T extends readonly [\n infer First extends RouterConfig,\n infer Second extends RouterConfig,\n ...infer Rest extends readonly RouterConfig[],\n ]\n ? DeepMergeAll<[DeepMergeTwo<First, Second>, ...Rest]>\n : RouterConfig;\n\n/**\n * Recursively flattens complex types for clean IDE hover display.\n * Applied at return sites (not inside recursion) so DTS emit stays fast —\n * TypeScript only resolves when concrete types are provided.\n *\n * Works with any recursive object type: router configs, client types,\n * React Query hooks, etc. Functions and primitives pass through unchanged.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PrettifyDeep<T> = T extends (...args: any[]) => any\n ? T\n : T extends object\n ? { readonly [K in keyof T]: PrettifyDeep<T[K]> }\n : T;\n\n/**\n * Collects all routes from a router into an array.\n */\nexport function collectRoutes(\n config: RouterConfig,\n basePath = '',\n): { key: string; route: RouteDefinition }[] {\n const routes: { key: string; route: RouteDefinition }[] = [];\n\n for (const [key, value] of Object.entries(config)) {\n const fullKey = basePath ? `${basePath}.${key}` : key;\n\n if (isRouteDefinition(value)) {\n routes.push({ key: fullKey, route: value });\n } else if (isRouterDefinition(value)) {\n routes.push(...collectRoutes(value.routes, fullKey));\n } else if (typeof value === 'object' && value !== null) {\n routes.push(...collectRoutes(value as RouterConfig, fullKey));\n }\n }\n\n return routes;\n}\n","/**\n * @fileoverview Factory function for creating router definitions.\n *\n * The `defineRouter` function groups routes into a hierarchical structure\n * that enables organized API clients, OpenAPI tag grouping, and structured\n * server route registration.\n *\n * @module unified/route/define-router\n */\n\nimport type { RouterConfig, RouterDefinition, DeepMergeTwo, DeepMergeAll } from './types';\nimport { isRouteDefinition, isRouterDefinition } from './types';\n\n/**\n * Options for router definition.\n */\nexport interface DefineRouterOptions {\n /**\n * Base path prefix for all routes in this router.\n * Will be prepended to all route paths.\n *\n * @example\n * ```typescript\n * defineRouter({ ... }, { basePath: '/api/v1' })\n * ```\n */\n readonly basePath?: string;\n\n /**\n * Default tags for all routes in this router.\n * Will be merged with route-specific tags.\n */\n readonly tags?: readonly string[];\n}\n\n/**\n * Creates a router definition from a configuration object.\n *\n * A router is a hierarchical grouping of routes that provides:\n * - Organized API structure with nested namespaces\n * - Typed client method generation\n * - OpenAPI tag grouping\n * - Server route registration\n *\n * @param routes - Object containing routes and nested routers\n * @param options - Optional router configuration\n * @returns A frozen RouterDefinition object\n *\n * @example Basic router\n * ```typescript\n * import { defineRouter } from '@cosmneo/onion-lasagna/http';\n *\n * const api = defineRouter({\n * users: {\n * list: listUsersRoute,\n * get: getUserRoute,\n * create: createUserRoute,\n * update: updateUserRoute,\n * delete: deleteUserRoute,\n * },\n * posts: {\n * list: listPostsRoute,\n * get: getPostRoute,\n * create: createPostRoute,\n * },\n * });\n *\n * // Client usage:\n * // client.users.list({ query: { page: 1 } })\n * // client.users.get({ params: { id: '123' } })\n * // client.posts.create({ body: { title: 'Hello' } })\n * ```\n *\n * @example Nested routers\n * ```typescript\n * const projectRouter = defineRouter({\n * list: listProjectsRoute,\n * get: getProjectRoute,\n * tasks: {\n * list: listTasksRoute,\n * create: createTaskRoute,\n * update: updateTaskRoute,\n * },\n * members: {\n * list: listMembersRoute,\n * add: addMemberRoute,\n * remove: removeMemberRoute,\n * },\n * });\n *\n * const api = defineRouter({\n * projects: projectRouter.routes,\n * users: userRouter.routes,\n * });\n *\n * // Client usage:\n * // client.projects.tasks.create({ params: { projectId: '123' }, body: { ... } })\n * ```\n *\n * @example With base path and tags\n * ```typescript\n * const adminApi = defineRouter({\n * users: {\n * list: listUsersRoute,\n * ban: banUserRoute,\n * },\n * analytics: {\n * dashboard: getDashboardRoute,\n * reports: getReportsRoute,\n * },\n * }, {\n * basePath: '/admin',\n * tags: ['Admin'],\n * });\n * ```\n */\nexport function defineRouter<T extends RouterConfig>(\n routes: T,\n options?: DefineRouterOptions,\n): RouterDefinition<T> {\n const definition: RouterDefinition<T> = {\n routes,\n basePath: options?.basePath,\n tags: options?.tags,\n _isRouter: true,\n };\n\n // Deep freeze the router definition\n return deepFreeze(definition);\n}\n\n/**\n * Deep freezes an object and all its nested objects.\n */\nfunction deepFreeze<T extends object>(obj: T): T {\n // Get all property names\n const propNames = Object.getOwnPropertyNames(obj) as (keyof T)[];\n\n // Freeze properties before freezing self\n for (const name of propNames) {\n const value = obj[name];\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n deepFreeze(value);\n }\n }\n\n return Object.freeze(obj);\n}\n\n// ============================================================================\n// mergeRouters — variadic deep merge\n// ============================================================================\n\ntype RouterInput<T extends RouterConfig> = T | RouterDefinition<T>;\n\n/** Extracts the raw RouterConfig from either a plain config or a RouterDefinition. */\nfunction extractRoutes<T extends RouterConfig>(input: RouterInput<T>): T {\n return isRouterDefinition(input) ? input.routes : input;\n}\n\n/** Returns true if `value` is a plain sub-router object (not a RouteDefinition, not a RouterDefinition). */\nfunction isSubRouter(value: unknown): value is RouterConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n !isRouteDefinition(value) &&\n !isRouterDefinition(value)\n );\n}\n\n/** Recursively deep-merges two router configs. Sub-routers are merged; leaves are overwritten. */\nfunction deepMergeConfigs(a: RouterConfig, b: RouterConfig): RouterConfig {\n const result: Record<string, unknown> = { ...a };\n\n for (const key of Object.keys(b)) {\n const aVal = result[key];\n const bVal = b[key];\n\n if (isSubRouter(aVal) && isSubRouter(bVal)) {\n result[key] = deepMergeConfigs(aVal, bVal);\n } else {\n result[key] = bVal;\n }\n }\n\n return result as RouterConfig;\n}\n\n// Overloads for 2–8 routers (clean IDE experience)\n\n/**\n * Merges multiple routers into a single router with deep merge.\n *\n * Overlapping sub-router keys are recursively merged instead of overwritten.\n * Leaf routes (RouteDefinition) use last-one-wins semantics.\n *\n * @example\n * ```typescript\n * const api = mergeRouters(\n * userRouter,\n * organizationRouter,\n * feedbackRouter,\n * );\n * // If all three define `users`, their sub-routes are deep-merged.\n * ```\n */\nexport function mergeRouters<T1 extends RouterConfig, T2 extends RouterConfig>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n): RouterDefinition<DeepMergeTwo<T1, T2>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n T7 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n r7: RouterInput<T7>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n T7 extends RouterConfig,\n T8 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n r7: RouterInput<T7>,\n r8: RouterInput<T8>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7, T8]>>;\n\n// Variadic fallback for 9+\nexport function mergeRouters(\n ...routers: RouterInput<RouterConfig>[]\n): RouterDefinition<RouterConfig>;\n\n// Implementation\nexport function mergeRouters(\n ...routers: RouterInput<RouterConfig>[]\n): RouterDefinition<RouterConfig> {\n const merged = routers.map(extractRoutes).reduce(deepMergeConfigs);\n return defineRouter(merged);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/http/route/index.ts","../../../src/presentation/http/schema/types/schema-adapter.type.ts","../../../src/presentation/http/route/define-route.ts","../../../src/presentation/http/route/types/path-params.type.ts","../../../src/presentation/http/route/types/router-definition.type.ts","../../../src/presentation/http/route/define-router.ts","../../../src/presentation/http/route/utils.ts"],"sourcesContent":["/**\n * @fileoverview Route module exports.\n *\n * This module provides route and router definition functions and types\n * for the unified system.\n *\n * @module unified/route\n *\n * @example Define a route\n * ```typescript\n * import { defineRoute } from '@cosmneo/onion-lasagna/http';\n * import { zodSchema } from '@cosmneo/onion-lasagna-zod';\n *\n * const getUser = defineRoute({\n * method: 'GET',\n * path: '/api/users/:userId',\n * response: zodSchema(z.object({\n * id: z.string(),\n * name: z.string(),\n * })),\n * });\n * ```\n *\n * @example Define a router\n * ```typescript\n * import { defineRouter } from '@cosmneo/onion-lasagna/http';\n *\n * const api = defineRouter({\n * users: {\n * get: getUserRoute,\n * list: listUsersRoute,\n * create: createUserRoute,\n * },\n * });\n * ```\n */\n\n// Export factory functions\nexport { defineRoute } from './define-route';\nexport { defineRouter, mergeRouters } from './define-router';\nexport type { DefineRouterOptions } from './define-router';\n\n// Export utility functions\nexport { generateOperationId } from './utils';\n\n// Export all types\nexport * from './types';\n","/**\n * @fileoverview Schema adapter interface for validation library abstraction.\n *\n * The SchemaAdapter interface provides a unified API for working with\n * different validation libraries (Zod, TypeBox, Valibot, ArkType).\n * Each adapter wraps a library-specific schema and provides:\n * - Runtime validation\n * - JSON Schema conversion for OpenAPI\n * - TypeScript type inference via phantom types\n *\n * @module unified/schema/types/schema-adapter\n */\n\nimport type { JsonSchema } from './json-schema.type';\nimport type { ValidationResult } from './validation.type';\n\n/**\n * Schema adapter interface that abstracts validation library specifics.\n *\n * This interface is the core abstraction that enables the unified route\n * system to work with any validation library. Implementations wrap a\n * library-specific schema (Zod, TypeBox, etc.) and provide a consistent API.\n *\n * @typeParam TOutput - The TypeScript type of successfully validated data.\n * For schemas with transforms, this is the output type.\n * @typeParam TInput - The TypeScript type expected as input (before transforms).\n * Defaults to TOutput for schemas without transforms.\n *\n * @example Creating an adapter (using Zod)\n * ```typescript\n * import { z } from 'zod';\n * import { zodSchema } from '@cosmneo/onion-lasagna/http/schema/zod';\n *\n * const userSchema = zodSchema(z.object({\n * name: z.string().min(1),\n * email: z.string().email(),\n * }));\n *\n * // Validate data\n * const result = userSchema.validate(input);\n * if (result.success) {\n * // result.data is typed as { name: string; email: string }\n * }\n *\n * // Get JSON Schema for OpenAPI\n * const jsonSchema = userSchema.toJsonSchema();\n * ```\n */\nexport interface SchemaAdapter<TOutput = unknown, TInput = TOutput> {\n /**\n * Validates unknown data against the schema.\n *\n * This method performs full validation including:\n * - Type checking\n * - Constraint validation (min/max, patterns, etc.)\n * - Nested object/array validation\n * - Custom validations defined in the schema\n *\n * For schemas with transforms, the returned data will be the transformed value.\n *\n * @param data - Unknown data to validate\n * @returns Validation result with typed data on success or issues on failure\n *\n * @example\n * ```typescript\n * const result = schema.validate({ name: 'John', age: 25 });\n * if (result.success) {\n * console.log(result.data.name); // TypeScript knows this is a string\n * } else {\n * console.log(result.issues); // Array of validation errors\n * }\n * ```\n */\n validate(data: unknown): ValidationResult<TOutput>;\n\n /**\n * Converts the schema to JSON Schema format for OpenAPI generation.\n *\n * The returned schema should be compatible with JSON Schema Draft 7\n * and OpenAPI 3.0/3.1 specifications. Complex schemas with transforms\n * or refinements may produce simplified JSON Schema representations.\n *\n * @param options - Optional configuration for schema generation\n * @returns JSON Schema representation of this schema\n *\n * @example\n * ```typescript\n * const jsonSchema = schema.toJsonSchema();\n * // {\n * // type: 'object',\n * // properties: {\n * // name: { type: 'string', minLength: 1 },\n * // email: { type: 'string', format: 'email' }\n * // },\n * // required: ['name', 'email']\n * // }\n * ```\n */\n toJsonSchema(options?: JsonSchemaOptions): JsonSchema;\n\n /**\n * Phantom type marker for output type inference.\n * This property is never accessed at runtime - it exists only for TypeScript.\n *\n * @internal\n */\n readonly _output: TOutput;\n\n /**\n * Phantom type marker for input type inference.\n * This property is never accessed at runtime - it exists only for TypeScript.\n * Useful for schemas with transforms where input and output types differ.\n *\n * @internal\n */\n readonly _input: TInput;\n\n /**\n * Optional: Reference to the underlying schema for advanced use cases.\n * The type depends on the validation library being used.\n *\n * @internal\n */\n readonly _schema?: unknown;\n}\n\n/**\n * Options for JSON Schema generation.\n */\nexport interface JsonSchemaOptions {\n /**\n * Strategy for handling $ref references.\n * - 'none': Inline all schemas, no $refs\n * - 'root': Create $refs only at the root level\n * - 'all': Use $refs wherever possible (most compact)\n *\n * @default 'none'\n */\n readonly refStrategy?: 'none' | 'root' | 'all';\n\n /**\n * Base path for $ref references.\n * @default '#/$defs/'\n */\n readonly basePath?: string;\n\n /**\n * Custom definitions to include in the schema.\n */\n readonly definitions?: Record<string, JsonSchema>;\n\n /**\n * Whether to include schema metadata (title, description, etc.).\n * @default true\n */\n readonly includeMetadata?: boolean;\n}\n\n/**\n * Infers the output type from a SchemaAdapter.\n *\n * @example\n * ```typescript\n * const userSchema = zodSchema(z.object({ name: z.string() }));\n * type User = InferOutput<typeof userSchema>;\n * // { name: string }\n * ```\n */\nexport type InferOutput<T extends SchemaAdapter<unknown, unknown>> =\n T extends SchemaAdapter<infer O, unknown> ? O : never;\n\n/**\n * Infers the input type from a SchemaAdapter.\n * For schemas without transforms, this is the same as InferOutput.\n *\n * @example\n * ```typescript\n * const dateSchema = zodSchema(z.string().transform(s => new Date(s)));\n * type DateInput = InferInput<typeof dateSchema>;\n * // string (the input before transform)\n * type DateOutput = InferOutput<typeof dateSchema>;\n * // Date (the output after transform)\n * ```\n */\nexport type InferInput<T extends SchemaAdapter<unknown, unknown>> =\n T extends SchemaAdapter<unknown, infer I> ? I : never;\n\n/**\n * Type guard to check if a value is a SchemaAdapter.\n */\nexport function isSchemaAdapter(value: unknown): value is SchemaAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'validate' in value &&\n typeof (value as SchemaAdapter).validate === 'function' &&\n 'toJsonSchema' in value &&\n typeof (value as SchemaAdapter).toJsonSchema === 'function'\n );\n}\n\n/**\n * Creates a schema adapter that always passes validation.\n * Useful for routes that accept any input.\n *\n * @example\n * ```typescript\n * const anySchema = createPassthroughAdapter<unknown>();\n * anySchema.validate(anything); // always succeeds\n * ```\n */\nexport function createPassthroughAdapter<T = unknown>(): SchemaAdapter<T, T> {\n return {\n validate: (data) => ({ success: true, data: data as T }),\n toJsonSchema: () => ({}),\n _output: undefined as T,\n _input: undefined as T,\n };\n}\n\n/**\n * Creates a schema adapter that always fails validation with a message.\n * Useful for deprecating routes or marking them as not accepting input.\n *\n * @example\n * ```typescript\n * const noBodySchema = createRejectingAdapter('This endpoint does not accept a request body');\n * ```\n */\nexport function createRejectingAdapter<T = never>(message: string): SchemaAdapter<T, T> {\n return {\n validate: () => ({\n success: false,\n issues: [{ path: [], message }],\n }),\n toJsonSchema: () => ({ not: {} }),\n _output: undefined as T,\n _input: undefined as T,\n };\n}\n","/**\n * @fileoverview Factory function for creating route definitions (v2).\n *\n * The `defineRoute` function is the main entry point for defining routes.\n * Request schemas are grouped under a `request` field, while responses\n * are defined via the `responses` field with per-status-code config.\n *\n * Each schema field accepts either a bare `SchemaAdapter` or an object with\n * metadata: `{ schema, description?, contentType?, required? }`.\n *\n * The success response type is inferred from the first 2xx status with a schema.\n *\n * @module unified/route/define-route\n */\n\nimport type { SchemaAdapter, InferOutput } from '../schema/types';\nimport { isSchemaAdapter } from '../schema/types';\nimport type {\n HttpMethod,\n RouteDefinition,\n PathParams,\n SchemaFieldInput,\n RouteFieldMeta,\n ResponseFieldConfig,\n ResponsesDefinition,\n ExtractSuccessSchema,\n} from './types';\n\n// ============================================================================\n// Input Types\n// ============================================================================\n\n/**\n * Complete input for defineRoute.\n *\n * @example GET with query and response\n * ```typescript\n * defineRoute({\n * method: 'GET',\n * path: '/api/users',\n * request: {\n * query: zodSchema(z.object({ page: z.coerce.number().default(1) })),\n * },\n * responses: {\n * 200: { schema: zodSchema(userListSchema) },\n * },\n * docs: { summary: 'List users', tags: ['Users'] },\n * })\n * ```\n *\n * @example POST with body and multiple statuses\n * ```typescript\n * defineRoute({\n * method: 'POST',\n * path: '/api/users',\n * request: {\n * body: zodSchema(createUserSchema),\n * },\n * responses: {\n * 201: { schema: zodSchema(userSchema), description: 'Created' },\n * 400: { description: 'Validation error' },\n * 409: { description: 'Email already in use' },\n * },\n * })\n * ```\n *\n * @example DELETE with 204\n * ```typescript\n * defineRoute({\n * method: 'DELETE',\n * path: '/api/users/:userId',\n * responses: {\n * 204: { description: 'User deleted' },\n * 404: { description: 'User not found' },\n * },\n * })\n * ```\n */\ninterface DefineRouteInput<\n TMethod extends HttpMethod,\n TPath extends string,\n TBody extends SchemaAdapter | undefined = undefined,\n TQuery extends SchemaAdapter | undefined = undefined,\n TParams extends SchemaAdapter | undefined = undefined,\n THeaders extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n TResponses extends ResponsesDefinition | undefined = undefined,\n> {\n /** HTTP method for this route. */\n readonly method: TMethod;\n\n /** URL path pattern with optional parameters (`:param` or `{param}`). */\n readonly path: TPath;\n\n /** Request schemas (body, query, params, headers, context). */\n readonly request?: {\n /** Request body schema (or `{ schema, description?, contentType?, required? }`). */\n readonly body?: TBody extends SchemaAdapter ? SchemaFieldInput<TBody> : TBody;\n\n /** Query parameters schema (or `{ schema, description? }`). */\n readonly query?: TQuery extends SchemaAdapter ? SchemaFieldInput<TQuery> : TQuery;\n\n /** Path parameters schema (or `{ schema, description? }`). If omitted, inferred from path template. */\n readonly params?: TParams extends SchemaAdapter ? SchemaFieldInput<TParams> : TParams;\n\n /** Headers schema (or `{ schema, description? }`). */\n readonly headers?: THeaders extends SchemaAdapter ? SchemaFieldInput<THeaders> : THeaders;\n\n /** Context schema (or `{ schema, description? }`). */\n readonly context?: TContext extends SchemaAdapter ? SchemaFieldInput<TContext> : TContext;\n };\n\n /**\n * Per-status response definitions.\n *\n * Each key is an HTTP status code. Each value can have:\n * - `schema` — response body schema (drives type inference for 2xx)\n * - `description` — OpenAPI response description\n * - `contentType` — response content type (default: `application/json`)\n */\n readonly responses?: TResponses;\n\n /** OpenAPI documentation. */\n readonly docs?: {\n readonly summary?: string;\n readonly description?: string;\n readonly tags?: readonly string[];\n readonly operationId?: string;\n readonly deprecated?: boolean;\n readonly security?: readonly Record<string, readonly string[]>[];\n readonly externalDocs?: {\n readonly url: string;\n readonly description?: string;\n };\n };\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Extracts the SchemaAdapter from a field that may be bare or wrapped in config.\n */\nfunction extractSchema<T extends SchemaAdapter>(\n field: SchemaFieldInput<T> | undefined,\n): T | undefined {\n if (field == null) return undefined;\n if (isSchemaAdapter(field)) return field as T;\n return (field as { schema: T }).schema;\n}\n\n/**\n * Extracts metadata from a field config, if it was passed as an object.\n */\nfunction extractMeta(\n field: SchemaFieldInput | undefined,\n): { description?: string; contentType?: string; required?: boolean } | undefined {\n if (field == null || isSchemaAdapter(field)) return undefined;\n const config = field as { description?: string; contentType?: string; required?: boolean };\n if (config.description == null && config.contentType == null && config.required == null) {\n return undefined;\n }\n return {\n description: config.description,\n contentType: config.contentType,\n required: config.required,\n };\n}\n\n/**\n * Normalizes responses record keys to strings.\n */\nfunction normalizeResponses(\n responses: Record<string | number, ResponseFieldConfig>,\n): Record<string, ResponseFieldConfig> {\n const result: Record<string, ResponseFieldConfig> = {};\n for (const [key, value] of Object.entries(responses)) {\n result[String(key)] = value;\n }\n return result;\n}\n\n// ============================================================================\n// Return type helpers\n// ============================================================================\n\ntype ResolveBody<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\ntype ResolveQuery<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\ntype ResolveParams<T, TPath extends string> = T extends SchemaAdapter\n ? InferOutput<T>\n : PathParams<TPath>;\ntype ResolveHeaders<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\ntype ResolveContext<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\n\ntype ResolveResponse<T> = T extends ResponsesDefinition\n ? ExtractSuccessSchema<T> extends SchemaAdapter\n ? InferOutput<ExtractSuccessSchema<T>>\n : undefined\n : undefined;\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Creates a route definition from the provided configuration.\n *\n * This is the main entry point for defining routes. The resulting definition\n * can be used for type-safe client generation, server-side route registration,\n * and OpenAPI specification generation.\n *\n * @param input - Route configuration with request schemas and responses\n * @returns A frozen RouteDefinition object with full type information\n */\nexport function defineRoute<\n TMethod extends HttpMethod,\n TPath extends string,\n TBody extends SchemaAdapter | undefined = undefined,\n TQuery extends SchemaAdapter | undefined = undefined,\n TParams extends SchemaAdapter | undefined = undefined,\n THeaders extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n TResponses extends ResponsesDefinition | undefined = undefined,\n>(\n input: DefineRouteInput<TMethod, TPath, TBody, TQuery, TParams, THeaders, TContext, TResponses>,\n): RouteDefinition<\n TMethod,\n TPath,\n ResolveBody<TBody>,\n ResolveQuery<TQuery>,\n ResolveParams<TParams, TPath>,\n ResolveHeaders<THeaders>,\n ResolveContext<TContext>,\n ResolveResponse<TResponses>\n> {\n const req = input.request;\n\n // Build _meta from any config-wrapped fields\n const bodyMeta = extractMeta(req?.body as SchemaFieldInput | undefined);\n const queryMeta = extractMeta(req?.query as SchemaFieldInput | undefined);\n const paramsMeta = extractMeta(req?.params as SchemaFieldInput | undefined);\n const headersMeta = extractMeta(req?.headers as SchemaFieldInput | undefined);\n const contextMeta = extractMeta(req?.context as SchemaFieldInput | undefined);\n\n const _meta: RouteFieldMeta = {\n ...(bodyMeta ? { body: bodyMeta } : {}),\n ...(queryMeta ? { query: { description: queryMeta.description } } : {}),\n ...(paramsMeta ? { params: { description: paramsMeta.description } } : {}),\n ...(headersMeta ? { headers: { description: headersMeta.description } } : {}),\n ...(contextMeta ? { context: { description: contextMeta.description } } : {}),\n };\n\n const definition = {\n method: input.method,\n path: input.path,\n request: {\n body: extractSchema(req?.body as SchemaFieldInput | undefined) ?? undefined,\n query: extractSchema(req?.query as SchemaFieldInput | undefined) ?? undefined,\n params: extractSchema(req?.params as SchemaFieldInput | undefined) ?? undefined,\n headers: extractSchema(req?.headers as SchemaFieldInput | undefined) ?? undefined,\n context: extractSchema(req?.context as SchemaFieldInput | undefined) ?? undefined,\n },\n responses: input.responses ? normalizeResponses(input.responses) : undefined,\n docs: {\n summary: input.docs?.summary,\n description: input.docs?.description,\n tags: input.docs?.tags,\n operationId: input.docs?.operationId,\n deprecated: input.docs?.deprecated ?? false,\n security: input.docs?.security,\n externalDocs: input.docs?.externalDocs,\n },\n _meta,\n _types: undefined as unknown,\n };\n\n return Object.freeze(definition) as RouteDefinition<\n TMethod,\n TPath,\n ResolveBody<TBody>,\n ResolveQuery<TQuery>,\n ResolveParams<TParams, TPath>,\n ResolveHeaders<THeaders>,\n ResolveContext<TContext>,\n ResolveResponse<TResponses>\n >;\n}\n","/**\n * @fileoverview Path parameter extraction types.\n *\n * These types enable TypeScript to extract path parameter names from\n * URL path templates at compile time, providing full type safety for\n * path parameters in routes.\n *\n * @module unified/route/types/path-params\n */\n\n/**\n * Extracts parameter names from a path template string.\n *\n * Supports both `:param` and `{param}` syntaxes for maximum compatibility\n * with different routing conventions.\n *\n * @example Colon syntax (Express-style)\n * ```typescript\n * type Params = ExtractPathParamNames<'/users/:userId/posts/:postId'>;\n * // 'userId' | 'postId'\n * ```\n *\n * @example Brace syntax (OpenAPI-style)\n * ```typescript\n * type Params = ExtractPathParamNames<'/users/{userId}/posts/{postId}'>;\n * // 'userId' | 'postId'\n * ```\n *\n * @example No parameters\n * ```typescript\n * type Params = ExtractPathParamNames<'/users'>;\n * // never\n * ```\n */\nexport type ExtractPathParamNames<T extends string> =\n // Match :param followed by more path\n T extends `${string}:${infer Param}/${infer Rest}`\n ? Param | ExtractPathParamNames<`/${Rest}`>\n : // Match :param at end\n T extends `${string}:${infer Param}`\n ? Param\n : // Match {param} followed by more path\n T extends `${string}{${infer Param}}/${infer Rest}`\n ? Param | ExtractPathParamNames<`/${Rest}`>\n : // Match {param} at end\n T extends `${string}{${infer Param}}`\n ? Param\n : never;\n\n/**\n * Creates an object type with all path parameters as string properties.\n *\n * @example\n * ```typescript\n * type Params = PathParams<'/projects/:projectId/tasks/:taskId'>;\n * // { projectId: string; taskId: string }\n *\n * type NoParams = PathParams<'/projects'>;\n * // Record<string, never> (empty object type)\n * ```\n */\nexport type PathParams<T extends string> =\n ExtractPathParamNames<T> extends never\n ? Record<string, never>\n : Record<ExtractPathParamNames<T>, string>;\n\n/**\n * Checks if a path has any parameters.\n *\n * @example\n * ```typescript\n * type HasParams = HasPathParams<'/users/:id'>; // true\n * type NoParams = HasPathParams<'/users'>; // false\n * ```\n */\nexport type HasPathParams<T extends string> = ExtractPathParamNames<T> extends never ? false : true;\n\n/**\n * Converts a path template with parameters to a regex pattern.\n * This is used internally for route matching.\n *\n * @example\n * ```typescript\n * pathToRegex('/users/:id/posts/:postId')\n * // /^\\/users\\/([^\\/]+)\\/posts\\/([^\\/]+)\\/?$/\n * ```\n */\nexport function pathToRegex(path: string): RegExp {\n const pattern = path\n // Escape special regex characters except : and {}\n .replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n // Replace :param with capture group\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '([^/]+)')\n // Replace {param} with capture group\n .replace(/\\\\\\{([a-zA-Z_][a-zA-Z0-9_]*)\\\\\\}/g, '([^/]+)');\n\n return new RegExp(`^${pattern}/?$`);\n}\n\n/**\n * Extracts parameter names from a path string at runtime.\n *\n * @example\n * ```typescript\n * getPathParamNames('/users/:userId/posts/:postId')\n * // ['userId', 'postId']\n * ```\n */\nexport function getPathParamNames(path: string): string[] {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- regex capture group always exists\n const colonParams = [...path.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)/g)].map((m) => m[1]!);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- regex capture group always exists\n const braceParams = [...path.matchAll(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g)].map((m) => m[1]!);\n return [...colonParams, ...braceParams];\n}\n\n/**\n * Checks if a path has any parameters at runtime.\n */\nexport function hasPathParams(path: string): boolean {\n return /:([a-zA-Z_][a-zA-Z0-9_]*)/.test(path) || /\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/.test(path);\n}\n\n/**\n * Replaces path parameters with actual values.\n *\n * @example\n * ```typescript\n * buildPath('/users/:userId/posts/:postId', { userId: '123', postId: '456' })\n * // '/users/123/posts/456'\n *\n * buildPath('/users/{userId}', { userId: '123' })\n * // '/users/123'\n * ```\n */\nexport function buildPath(template: string, params: Record<string, string>): string {\n let result = template;\n\n // Replace :param syntax\n for (const [key, value] of Object.entries(params)) {\n result = result.replace(`:${key}`, encodeURIComponent(value));\n result = result.replace(`{${key}}`, encodeURIComponent(value));\n }\n\n return result;\n}\n\n/**\n * Normalizes a path template to use consistent :param syntax.\n *\n * @example\n * ```typescript\n * normalizePath('/users/{userId}')\n * // '/users/:userId'\n * ```\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g, ':$1');\n}\n","/**\n * @fileoverview Router definition types for grouping routes.\n *\n * A router is a hierarchical grouping of routes that enables:\n * - Organized API structure\n * - Nested client method generation\n * - Grouped OpenAPI tags\n *\n * @module unified/route/types/router-definition\n */\n\nimport type { RouteDefinition } from './route-definition.type';\nimport type { HttpMethod } from './http.type';\nimport type { SchemaAdapter } from '../../schema/types';\n\n// ============================================================================\n// Router Types\n// ============================================================================\n\n/**\n * A router entry can be a route definition, a nested router config, or a router definition.\n */\nexport type RouterEntry =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | RouteDefinition<HttpMethod, string, unknown, unknown, unknown, unknown, unknown, any>\n | RouterConfig\n | RouterDefinition;\n\n/**\n * Configuration for a router (group of routes).\n */\nexport interface RouterConfig {\n readonly [key: string]: RouterEntry;\n}\n\n/**\n * Router-level defaults applied to all child routes.\n */\nexport interface RouterDefaults {\n /**\n * Default tags for all routes in this router.\n * Merged with route-specific tags.\n */\n readonly tags?: readonly string[];\n\n /**\n * Default context schema for all routes in this router.\n * Applied to routes that don't define their own context.\n */\n readonly context?: SchemaAdapter;\n}\n\n/**\n * A fully defined router.\n */\nexport interface RouterDefinition<T extends RouterConfig = RouterConfig> {\n /**\n * The routes and nested routers in this router.\n */\n readonly routes: T;\n\n /**\n * Base path prefix for all routes in this router.\n */\n readonly basePath?: string;\n\n /**\n * Default values applied to all child routes.\n */\n readonly defaults?: RouterDefaults;\n\n /**\n * Marker to identify this as a router.\n * @internal\n */\n readonly _isRouter: true;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Checks if a value is a RouteDefinition.\n */\nexport function isRouteDefinition(value: unknown): value is RouteDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'method' in value &&\n 'path' in value &&\n '_types' in value\n );\n}\n\n/**\n * Checks if a value is a RouterDefinition.\n */\nexport function isRouterDefinition(value: unknown): value is RouterDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n '_isRouter' in value &&\n (value as RouterDefinition)._isRouter === true\n );\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Flattens a router into a map of path keys to route definitions.\n */\nexport type FlattenRouter<\n T extends RouterConfig,\n Prefix extends string = '',\n> = T extends RouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? { [P in `${Prefix}${K & string}`]: T[K] }\n : T[K] extends RouterConfig\n ? FlattenRouter<T[K], `${Prefix}${K & string}.`>\n : never;\n }[keyof T] extends infer U\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n U extends Record<string, RouteDefinition<any, any, any, any, any, any, any, any>>\n ? U\n : never\n : never\n : never;\n\n/**\n * Gets all route keys from a router.\n */\nexport type RouterKeys<T extends RouterConfig, Prefix extends string = ''> = T extends RouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? `${Prefix}${K & string}`\n : T[K] extends RouterConfig\n ? RouterKeys<T[K], `${Prefix}${K & string}.`>\n : never;\n }[keyof T]\n : never;\n\n/**\n * Gets a route by its dotted key path.\n */\nexport type GetRoute<\n T extends RouterConfig,\n K extends string,\n> = K extends `${infer Head}.${infer Tail}`\n ? Head extends keyof T\n ? T[Head] extends RouterConfig\n ? GetRoute<T[Head], Tail>\n : never\n : never\n : K extends keyof T\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T[K] extends RouteDefinition<any, any, any, any, any, any, any, any>\n ? T[K]\n : never\n : never;\n\n// ============================================================================\n// Deep Merge Types\n// ============================================================================\n\n/**\n * Deep-merges two router configs at the type level.\n */\nexport type DeepMergeTwo<A extends RouterConfig, B extends RouterConfig> = {\n readonly [K in keyof A | keyof B]: K extends keyof A\n ? K extends keyof B\n ? A[K] extends RouterConfig\n ? B[K] extends RouterConfig\n ? DeepMergeTwo<A[K], B[K]>\n : B[K]\n : B[K]\n : A[K]\n : K extends keyof B\n ? B[K]\n : never;\n};\n\n/**\n * Recursively deep-merges N router configs left-to-right.\n */\nexport type DeepMergeAll<T extends readonly RouterConfig[]> = T extends readonly [\n infer Only extends RouterConfig,\n]\n ? Only\n : T extends readonly [\n infer First extends RouterConfig,\n infer Second extends RouterConfig,\n ...infer Rest extends readonly RouterConfig[],\n ]\n ? DeepMergeAll<[DeepMergeTwo<First, Second>, ...Rest]>\n : RouterConfig;\n\n/**\n * Recursively flattens complex types for clean IDE hover display.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PrettifyDeep<T> = T extends (...args: any[]) => any\n ? T\n : T extends object\n ? { readonly [K in keyof T]: PrettifyDeep<T[K]> }\n : T;\n\n/**\n * Collects all routes from a router into an array.\n */\nexport function collectRoutes(\n config: RouterConfig,\n basePath = '',\n): { key: string; route: RouteDefinition }[] {\n const routes: { key: string; route: RouteDefinition }[] = [];\n\n for (const [key, value] of Object.entries(config)) {\n const fullKey = basePath ? `${basePath}.${key}` : key;\n\n if (isRouteDefinition(value)) {\n routes.push({ key: fullKey, route: value });\n } else if (isRouterDefinition(value)) {\n routes.push(...collectRoutes(value.routes, fullKey));\n } else if (typeof value === 'object' && value !== null) {\n routes.push(...collectRoutes(value as RouterConfig, fullKey));\n }\n }\n\n return routes;\n}\n","/**\n * @fileoverview Factory function for creating router definitions.\n *\n * The `defineRouter` function groups routes into a hierarchical structure\n * with optional router-level defaults for context and tags.\n *\n * @module unified/route/define-router\n */\n\nimport type {\n RouterConfig,\n RouterDefaults,\n RouterDefinition,\n RouteDefinition,\n DeepMergeTwo,\n DeepMergeAll,\n} from './types';\nimport { isRouteDefinition, isRouterDefinition } from './types';\n\n/**\n * Options for router definition.\n */\nexport interface DefineRouterOptions {\n /**\n * Base path prefix for all routes in this router.\n * Will be prepended to all route paths.\n */\n readonly basePath?: string;\n\n /**\n * Default values applied to all child routes.\n *\n * @example\n * ```typescript\n * defineRouter({\n * list: listUsersRoute,\n * get: getUserRoute,\n * }, {\n * defaults: {\n * context: zodSchema(executionContextSchema),\n * tags: ['Users'],\n * },\n * })\n * ```\n */\n readonly defaults?: RouterDefaults;\n}\n\n/**\n * Creates a router definition from a configuration object.\n *\n * A router is a hierarchical grouping of routes that provides:\n * - Organized API structure with nested namespaces\n * - Typed client method generation\n * - OpenAPI tag grouping\n * - Router-level defaults for context and tags\n *\n * @param routes - Object containing routes and nested routers\n * @param options - Optional router configuration\n * @returns A frozen RouterDefinition object\n *\n * @example Basic router\n * ```typescript\n * const api = defineRouter({\n * users: {\n * list: listUsersRoute,\n * get: getUserRoute,\n * create: createUserRoute,\n * },\n * });\n * ```\n *\n * @example With router-level defaults\n * ```typescript\n * const api = defineRouter({\n * list: listUsersRoute,\n * get: getUserRoute,\n * }, {\n * basePath: '/api/v1',\n * defaults: {\n * context: zodSchema(executionContextSchema),\n * tags: ['Users'],\n * },\n * });\n * // Context is applied to all routes that don't define their own.\n * // Tags are merged with each route's existing tags.\n * ```\n */\nexport function defineRouter<T extends RouterConfig>(\n routes: T,\n options?: DefineRouterOptions,\n): RouterDefinition<T> {\n const defaults = options?.defaults;\n\n // Apply defaults to routes if context or tags are provided\n const processedRoutes =\n defaults?.context || defaults?.tags ? (applyRouterDefaults(routes, defaults) as T) : routes;\n\n const definition: RouterDefinition<T> = {\n routes: processedRoutes,\n basePath: options?.basePath,\n defaults,\n _isRouter: true,\n };\n\n // Deep freeze the router definition\n return deepFreeze(definition);\n}\n\n/**\n * Recursively applies router-level defaults to all routes in the tree.\n */\nfunction applyRouterDefaults(routes: RouterConfig, defaults: RouterDefaults): RouterConfig {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(routes)) {\n if (isRouteDefinition(value)) {\n result[key] = applyDefaultsToRoute(value, defaults);\n } else if (isRouterDefinition(value)) {\n result[key] = {\n ...value,\n routes: applyRouterDefaults(value.routes, defaults),\n };\n } else if (typeof value === 'object' && value !== null) {\n result[key] = applyRouterDefaults(value as RouterConfig, defaults);\n }\n }\n\n return result as RouterConfig;\n}\n\n/**\n * Applies router-level defaults to a single route definition.\n */\nfunction applyDefaultsToRoute(route: RouteDefinition, defaults: RouterDefaults): RouteDefinition {\n const needsContext = defaults.context && !route.request.context;\n const needsTags = defaults.tags && defaults.tags.length > 0;\n\n if (!needsContext && !needsTags) return route;\n\n return Object.freeze({\n ...route,\n request: {\n ...route.request,\n context: route.request.context ?? defaults.context ?? undefined,\n },\n docs: {\n ...route.docs,\n tags: mergeTags(defaults.tags, route.docs.tags),\n },\n }) as RouteDefinition;\n}\n\n/**\n * Merges router-level tags with route-level tags, avoiding duplicates.\n */\nfunction mergeTags(\n routerTags?: readonly string[],\n routeTags?: readonly string[],\n): readonly string[] | undefined {\n if (!routerTags || routerTags.length === 0) return routeTags;\n if (!routeTags || routeTags.length === 0) return routerTags;\n\n // Merge, preserving order: router tags first, then route-specific tags (no duplicates)\n const merged = [...routerTags];\n for (const tag of routeTags) {\n if (!merged.includes(tag)) {\n merged.push(tag);\n }\n }\n return merged;\n}\n\n/**\n * Deep freezes an object and all its nested objects.\n */\nfunction deepFreeze<T extends object>(obj: T): T {\n const propNames = Object.getOwnPropertyNames(obj) as (keyof T)[];\n\n for (const name of propNames) {\n const value = obj[name];\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n deepFreeze(value);\n }\n }\n\n return Object.freeze(obj);\n}\n\n// ============================================================================\n// mergeRouters — variadic deep merge\n// ============================================================================\n\ntype RouterInput<T extends RouterConfig> = T | RouterDefinition<T>;\n\n/** Extracts the raw RouterConfig from either a plain config or a RouterDefinition. */\nfunction extractRoutes<T extends RouterConfig>(input: RouterInput<T>): T {\n return isRouterDefinition(input) ? input.routes : input;\n}\n\n/** Returns true if `value` is a plain sub-router object (not a RouteDefinition, not a RouterDefinition). */\nfunction isSubRouter(value: unknown): value is RouterConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n !isRouteDefinition(value) &&\n !isRouterDefinition(value)\n );\n}\n\n/** Recursively deep-merges two router configs. Sub-routers are merged; leaves are overwritten. */\nfunction deepMergeConfigs(a: RouterConfig, b: RouterConfig): RouterConfig {\n const result: Record<string, unknown> = { ...a };\n\n for (const key of Object.keys(b)) {\n const aVal = result[key];\n const bVal = b[key];\n\n if (isSubRouter(aVal) && isSubRouter(bVal)) {\n result[key] = deepMergeConfigs(aVal, bVal);\n } else {\n result[key] = bVal;\n }\n }\n\n return result as RouterConfig;\n}\n\n// Overloads for 2–8 routers (clean IDE experience)\nexport function mergeRouters<T1 extends RouterConfig, T2 extends RouterConfig>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n): RouterDefinition<DeepMergeTwo<T1, T2>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n T7 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n r7: RouterInput<T7>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7]>>;\nexport function mergeRouters<\n T1 extends RouterConfig,\n T2 extends RouterConfig,\n T3 extends RouterConfig,\n T4 extends RouterConfig,\n T5 extends RouterConfig,\n T6 extends RouterConfig,\n T7 extends RouterConfig,\n T8 extends RouterConfig,\n>(\n r1: RouterInput<T1>,\n r2: RouterInput<T2>,\n r3: RouterInput<T3>,\n r4: RouterInput<T4>,\n r5: RouterInput<T5>,\n r6: RouterInput<T6>,\n r7: RouterInput<T7>,\n r8: RouterInput<T8>,\n): RouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7, T8]>>;\n\n// Variadic fallback for 9+\nexport function mergeRouters(\n ...routers: RouterInput<RouterConfig>[]\n): RouterDefinition<RouterConfig>;\n\n// Implementation\nexport function mergeRouters(\n ...routers: RouterInput<RouterConfig>[]\n): RouterDefinition<RouterConfig> {\n const merged = routers.map(extractRoutes).reduce(deepMergeConfigs);\n return defineRouter(merged);\n}\n","/**\n * @fileoverview Route utility functions.\n *\n * @module unified/route/utils\n */\n\n/**\n * Generates an operationId from a router key path.\n *\n * Converts dotted key paths to camelCase:\n * - `\"users.list\"` → `\"usersList\"`\n * - `\"organizations.members.get\"` → `\"organizationsMembersGet\"`\n *\n * @param key - The dotted router key path\n * @returns A camelCase operationId string\n */\nexport function generateOperationId(key: string): string {\n return key\n .split('.')\n .map((segment, index) =>\n index === 0 ? segment : segment.charAt(0).toUpperCase() + segment.slice(1),\n )\n .join('');\n}\n"],"mappings":"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","names":[]}
|