@cosmneo/onion-lasagna 0.2.1 → 0.3.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.
Files changed (61) hide show
  1. package/dist/chunk-36IO4BM7.js +113 -0
  2. package/dist/chunk-36IO4BM7.js.map +1 -0
  3. package/dist/chunk-4BVOLXDJ.js +54 -0
  4. package/dist/chunk-4BVOLXDJ.js.map +1 -0
  5. package/dist/chunk-CBTICRSM.js +34 -0
  6. package/dist/chunk-CBTICRSM.js.map +1 -0
  7. package/dist/chunk-KJ4JGZOE.js +96 -0
  8. package/dist/chunk-KJ4JGZOE.js.map +1 -0
  9. package/dist/chunk-RVSBIYY4.js +1 -0
  10. package/dist/chunk-RVSBIYY4.js.map +1 -0
  11. package/dist/{chunk-MF2JDREK.js → chunk-UNVB4INM.js} +1 -1
  12. package/dist/{chunk-MF2JDREK.js.map → chunk-UNVB4INM.js.map} +1 -1
  13. package/dist/chunk-XWKHOLIP.js +191 -0
  14. package/dist/chunk-XWKHOLIP.js.map +1 -0
  15. package/dist/event-router-definition.type-CP9uTlux.d.cts +150 -0
  16. package/dist/event-router-definition.type-D8CG-kjZ.d.ts +150 -0
  17. package/dist/events/asyncapi/index.cjs +143 -0
  18. package/dist/events/asyncapi/index.cjs.map +1 -0
  19. package/dist/events/asyncapi/index.d.cts +184 -0
  20. package/dist/events/asyncapi/index.d.ts +184 -0
  21. package/dist/events/asyncapi/index.js +8 -0
  22. package/dist/events/asyncapi/index.js.map +1 -0
  23. package/dist/events/handler/index.cjs +171 -0
  24. package/dist/events/handler/index.cjs.map +1 -0
  25. package/dist/events/handler/index.d.cts +153 -0
  26. package/dist/events/handler/index.d.ts +153 -0
  27. package/dist/events/handler/index.js +21 -0
  28. package/dist/events/handler/index.js.map +1 -0
  29. package/dist/events/index.cjs +497 -0
  30. package/dist/events/index.cjs.map +1 -0
  31. package/dist/events/index.d.cts +9 -0
  32. package/dist/events/index.d.ts +9 -0
  33. package/dist/events/index.js +41 -0
  34. package/dist/events/index.js.map +1 -0
  35. package/dist/events/server/index.cjs +291 -0
  36. package/dist/events/server/index.cjs.map +1 -0
  37. package/dist/events/server/index.d.cts +281 -0
  38. package/dist/events/server/index.d.ts +281 -0
  39. package/dist/events/server/index.js +16 -0
  40. package/dist/events/server/index.js.map +1 -0
  41. package/dist/events/shared/index.cjs +85 -0
  42. package/dist/events/shared/index.cjs.map +1 -0
  43. package/dist/events/shared/index.d.cts +35 -0
  44. package/dist/events/shared/index.d.ts +35 -0
  45. package/dist/events/shared/index.js +13 -0
  46. package/dist/events/shared/index.js.map +1 -0
  47. package/dist/http/index.cjs.map +1 -1
  48. package/dist/http/index.d.cts +2 -1
  49. package/dist/http/index.d.ts +2 -1
  50. package/dist/http/index.js +4 -4
  51. package/dist/http/route/index.cjs.map +1 -1
  52. package/dist/http/route/index.d.cts +4 -0
  53. package/dist/http/route/index.d.ts +4 -0
  54. package/dist/http/route/index.js +1 -1
  55. package/dist/http/server/index.d.cts +4 -261
  56. package/dist/http/server/index.d.ts +4 -261
  57. package/dist/types-B6Q1iCgf.d.ts +262 -0
  58. package/dist/types-afYpL7Ap.d.cts +262 -0
  59. package/dist/types-cke61juH.d.cts +42 -0
  60. package/dist/types-cke61juH.d.ts +42 -0
  61. package/package.json +35 -2
@@ -0,0 +1,113 @@
1
+ import {
2
+ isEventHandlerDefinition,
3
+ isEventRouterDefinition
4
+ } from "./chunk-CBTICRSM.js";
5
+
6
+ // src/presentation/events/handler/define-event-handler.ts
7
+ function defineEventHandler(input) {
8
+ const definition = {
9
+ eventType: input.eventType,
10
+ payload: input.payload ?? void 0,
11
+ context: input.context ?? void 0,
12
+ docs: {
13
+ summary: input.docs?.summary,
14
+ description: input.docs?.description,
15
+ tags: input.docs?.tags,
16
+ deprecated: input.docs?.deprecated ?? false
17
+ },
18
+ _types: void 0
19
+ };
20
+ return Object.freeze(definition);
21
+ }
22
+
23
+ // src/presentation/events/handler/define-event-router.ts
24
+ function defineEventRouter(handlers, options) {
25
+ const defaults = options?.defaults;
26
+ const processedHandlers = defaults?.context || defaults?.tags ? applyEventRouterDefaults(handlers, defaults) : handlers;
27
+ const definition = {
28
+ handlers: processedHandlers,
29
+ defaults,
30
+ _isEventRouter: true
31
+ };
32
+ return deepFreeze(definition);
33
+ }
34
+ function applyEventRouterDefaults(handlers, defaults) {
35
+ const result = {};
36
+ for (const [key, value] of Object.entries(handlers)) {
37
+ if (isEventHandlerDefinition(value)) {
38
+ result[key] = applyDefaultsToEventHandler(value, defaults);
39
+ } else if (isEventRouterDefinition(value)) {
40
+ result[key] = {
41
+ ...value,
42
+ handlers: applyEventRouterDefaults(value.handlers, defaults)
43
+ };
44
+ } else if (typeof value === "object" && value !== null) {
45
+ result[key] = applyEventRouterDefaults(value, defaults);
46
+ }
47
+ }
48
+ return result;
49
+ }
50
+ function applyDefaultsToEventHandler(handler, defaults) {
51
+ const needsContext = defaults.context && !handler.context;
52
+ const needsTags = defaults.tags && defaults.tags.length > 0;
53
+ if (!needsContext && !needsTags) return handler;
54
+ return Object.freeze({
55
+ ...handler,
56
+ context: handler.context ?? defaults.context ?? void 0,
57
+ docs: {
58
+ ...handler.docs,
59
+ tags: mergeTags(defaults.tags, handler.docs.tags)
60
+ }
61
+ });
62
+ }
63
+ function mergeTags(routerTags, handlerTags) {
64
+ if (!routerTags || routerTags.length === 0) return handlerTags;
65
+ if (!handlerTags || handlerTags.length === 0) return routerTags;
66
+ const merged = [...routerTags];
67
+ for (const tag of handlerTags) {
68
+ if (!merged.includes(tag)) {
69
+ merged.push(tag);
70
+ }
71
+ }
72
+ return merged;
73
+ }
74
+ function deepFreeze(obj) {
75
+ const propNames = Object.getOwnPropertyNames(obj);
76
+ for (const name of propNames) {
77
+ const value = obj[name];
78
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
79
+ deepFreeze(value);
80
+ }
81
+ }
82
+ return Object.freeze(obj);
83
+ }
84
+ function extractHandlers(input) {
85
+ return isEventRouterDefinition(input) ? input.handlers : input;
86
+ }
87
+ function isSubRouter(value) {
88
+ return typeof value === "object" && value !== null && !isEventHandlerDefinition(value) && !isEventRouterDefinition(value);
89
+ }
90
+ function deepMergeConfigs(a, b) {
91
+ const result = { ...a };
92
+ for (const key of Object.keys(b)) {
93
+ const aVal = result[key];
94
+ const bVal = b[key];
95
+ if (isSubRouter(aVal) && isSubRouter(bVal)) {
96
+ result[key] = deepMergeConfigs(aVal, bVal);
97
+ } else {
98
+ result[key] = bVal;
99
+ }
100
+ }
101
+ return result;
102
+ }
103
+ function mergeEventRouters(...routers) {
104
+ const merged = routers.map(extractHandlers).reduce(deepMergeConfigs);
105
+ return defineEventRouter(merged);
106
+ }
107
+
108
+ export {
109
+ defineEventHandler,
110
+ defineEventRouter,
111
+ mergeEventRouters
112
+ };
113
+ //# sourceMappingURL=chunk-36IO4BM7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presentation/events/handler/define-event-handler.ts","../src/presentation/events/handler/define-event-router.ts"],"sourcesContent":["/**\n * @fileoverview Factory function for creating event handler definitions.\n *\n * The `defineEventHandler` function is the main entry point for defining\n * event handlers. It mirrors `defineRoute` from the HTTP layer but is\n * tailored for asynchronous event processing.\n *\n * @module events/handler/define-event-handler\n */\n\nimport type { SchemaAdapter, InferOutput } from '../../http/schema/types';\nimport type { EventHandlerDefinition } from './types';\n\n// ============================================================================\n// Input Types\n// ============================================================================\n\n/**\n * Input for defineEventHandler.\n *\n * @example Basic handler with payload schema\n * ```typescript\n * defineEventHandler({\n * eventType: 'ticket.created',\n * payload: zodSchema(z.object({ ticketId: z.string() })),\n * docs: { summary: 'Handle ticket creation', tags: ['ticket'] },\n * })\n * ```\n *\n * @example With context schema\n * ```typescript\n * defineEventHandler({\n * eventType: 'order.shipped',\n * payload: zodSchema(orderShippedSchema),\n * context: zodSchema(eventMetadataSchema),\n * })\n * ```\n */\ninterface DefineEventHandlerInput<\n TEventType extends string,\n TPayload extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n> {\n /** Event type string used for routing (e.g., 'ticket.created'). */\n readonly eventType: TEventType;\n\n /** Payload validation schema. */\n readonly payload?: TPayload;\n\n /** Context validation schema (validates event metadata). */\n readonly context?: TContext;\n\n /** Handler documentation. */\n readonly docs?: {\n readonly summary?: string;\n readonly description?: string;\n readonly tags?: readonly string[];\n readonly deprecated?: boolean;\n };\n}\n\n// ============================================================================\n// Return type helpers\n// ============================================================================\n\ntype ResolvePayload<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\ntype ResolveContext<T> = T extends SchemaAdapter ? InferOutput<T> : undefined;\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Creates an event handler definition from the provided configuration.\n *\n * This is the main entry point for defining event handlers. The resulting\n * definition can be used for type-safe handler registration, payload\n * validation, and documentation generation.\n *\n * @param input - Event handler configuration with optional schemas\n * @returns A frozen EventHandlerDefinition object with full type information\n */\nexport function defineEventHandler<\n TEventType extends string,\n TPayload extends SchemaAdapter | undefined = undefined,\n TContext extends SchemaAdapter | undefined = undefined,\n>(\n input: DefineEventHandlerInput<TEventType, TPayload, TContext>,\n): EventHandlerDefinition<TEventType, ResolvePayload<TPayload>, ResolveContext<TContext>> {\n const definition = {\n eventType: input.eventType,\n payload: input.payload ?? undefined,\n context: input.context ?? undefined,\n docs: {\n summary: input.docs?.summary,\n description: input.docs?.description,\n tags: input.docs?.tags,\n deprecated: input.docs?.deprecated ?? false,\n },\n _types: undefined as unknown,\n };\n\n return Object.freeze(definition) as EventHandlerDefinition<\n TEventType,\n ResolvePayload<TPayload>,\n ResolveContext<TContext>\n >;\n}\n","/**\n * @fileoverview Factory function for creating event router definitions.\n *\n * The `defineEventRouter` function groups event handlers into a hierarchical\n * structure with optional router-level defaults for context and tags.\n *\n * @module events/handler/define-event-router\n */\n\nimport type {\n EventRouterConfig,\n EventRouterDefaults,\n EventRouterDefinition,\n EventHandlerDefinition,\n DeepMergeTwo,\n DeepMergeAll,\n} from './types';\nimport { isEventHandlerDefinition, isEventRouterDefinition } from './types';\n\n/**\n * Options for event router definition.\n */\nexport interface DefineEventRouterOptions {\n /**\n * Default values applied to all child handlers.\n *\n * @example\n * ```typescript\n * defineEventRouter({\n * created: onTicketCreated,\n * assigned: onTicketAssigned,\n * }, {\n * defaults: {\n * context: zodSchema(eventMetadataSchema),\n * tags: ['ticket'],\n * },\n * })\n * ```\n */\n readonly defaults?: EventRouterDefaults;\n}\n\n/**\n * Creates an event router definition from a configuration object.\n *\n * @param handlers - Object containing event handlers and nested routers\n * @param options - Optional router configuration\n * @returns A frozen EventRouterDefinition object\n *\n * @example Basic router\n * ```typescript\n * const ticketEvents = defineEventRouter({\n * created: onTicketCreated,\n * assigned: onTicketAssigned,\n * transferred: onTicketTransferred,\n * });\n * ```\n *\n * @example Nested router\n * ```typescript\n * const events = defineEventRouter({\n * ticket: {\n * created: onTicketCreated,\n * assigned: onTicketAssigned,\n * },\n * ecosystem: {\n * memberAdded: onMemberAdded,\n * },\n * });\n * ```\n */\nexport function defineEventRouter<T extends EventRouterConfig>(\n handlers: T,\n options?: DefineEventRouterOptions,\n): EventRouterDefinition<T> {\n const defaults = options?.defaults;\n\n const processedHandlers =\n defaults?.context || defaults?.tags\n ? (applyEventRouterDefaults(handlers, defaults) as T)\n : handlers;\n\n const definition: EventRouterDefinition<T> = {\n handlers: processedHandlers,\n defaults,\n _isEventRouter: true,\n };\n\n return deepFreeze(definition);\n}\n\n/**\n * Recursively applies router-level defaults to all handlers in the tree.\n */\nfunction applyEventRouterDefaults(\n handlers: EventRouterConfig,\n defaults: EventRouterDefaults,\n): EventRouterConfig {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(handlers)) {\n if (isEventHandlerDefinition(value)) {\n result[key] = applyDefaultsToEventHandler(value, defaults);\n } else if (isEventRouterDefinition(value)) {\n result[key] = {\n ...value,\n handlers: applyEventRouterDefaults(value.handlers, defaults),\n };\n } else if (typeof value === 'object' && value !== null) {\n result[key] = applyEventRouterDefaults(value as EventRouterConfig, defaults);\n }\n }\n\n return result as EventRouterConfig;\n}\n\n/**\n * Applies router-level defaults to a single event handler definition.\n */\nfunction applyDefaultsToEventHandler(\n handler: EventHandlerDefinition,\n defaults: EventRouterDefaults,\n): EventHandlerDefinition {\n const needsContext = defaults.context && !handler.context;\n const needsTags = defaults.tags && defaults.tags.length > 0;\n\n if (!needsContext && !needsTags) return handler;\n\n return Object.freeze({\n ...handler,\n context: handler.context ?? defaults.context ?? undefined,\n docs: {\n ...handler.docs,\n tags: mergeTags(defaults.tags, handler.docs.tags),\n },\n }) as EventHandlerDefinition;\n}\n\n/**\n * Merges router-level tags with handler-level tags, avoiding duplicates.\n */\nfunction mergeTags(\n routerTags?: readonly string[],\n handlerTags?: readonly string[],\n): readonly string[] | undefined {\n if (!routerTags || routerTags.length === 0) return handlerTags;\n if (!handlerTags || handlerTags.length === 0) return routerTags;\n\n const merged = [...routerTags];\n for (const tag of handlerTags) {\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// mergeEventRouters — variadic deep merge\n// ============================================================================\n\ntype EventRouterInput<T extends EventRouterConfig> = T | EventRouterDefinition<T>;\n\n/** Extracts the raw EventRouterConfig from either a plain config or an EventRouterDefinition. */\nfunction extractHandlers<T extends EventRouterConfig>(input: EventRouterInput<T>): T {\n return isEventRouterDefinition(input) ? input.handlers : input;\n}\n\n/** Returns true if `value` is a plain sub-router object. */\nfunction isSubRouter(value: unknown): value is EventRouterConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n !isEventHandlerDefinition(value) &&\n !isEventRouterDefinition(value)\n );\n}\n\n/** Recursively deep-merges two router configs. Sub-routers are merged; leaves are overwritten. */\nfunction deepMergeConfigs(a: EventRouterConfig, b: EventRouterConfig): EventRouterConfig {\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 EventRouterConfig;\n}\n\n// Overloads for 2–8 routers\nexport function mergeEventRouters<T1 extends EventRouterConfig, T2 extends EventRouterConfig>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n): EventRouterDefinition<DeepMergeTwo<T1, T2>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3]>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n T4 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n r4: EventRouterInput<T4>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3, T4]>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n T4 extends EventRouterConfig,\n T5 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n r4: EventRouterInput<T4>,\n r5: EventRouterInput<T5>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5]>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n T4 extends EventRouterConfig,\n T5 extends EventRouterConfig,\n T6 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n r4: EventRouterInput<T4>,\n r5: EventRouterInput<T5>,\n r6: EventRouterInput<T6>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6]>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n T4 extends EventRouterConfig,\n T5 extends EventRouterConfig,\n T6 extends EventRouterConfig,\n T7 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n r4: EventRouterInput<T4>,\n r5: EventRouterInput<T5>,\n r6: EventRouterInput<T6>,\n r7: EventRouterInput<T7>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7]>>;\nexport function mergeEventRouters<\n T1 extends EventRouterConfig,\n T2 extends EventRouterConfig,\n T3 extends EventRouterConfig,\n T4 extends EventRouterConfig,\n T5 extends EventRouterConfig,\n T6 extends EventRouterConfig,\n T7 extends EventRouterConfig,\n T8 extends EventRouterConfig,\n>(\n r1: EventRouterInput<T1>,\n r2: EventRouterInput<T2>,\n r3: EventRouterInput<T3>,\n r4: EventRouterInput<T4>,\n r5: EventRouterInput<T5>,\n r6: EventRouterInput<T6>,\n r7: EventRouterInput<T7>,\n r8: EventRouterInput<T8>,\n): EventRouterDefinition<DeepMergeAll<[T1, T2, T3, T4, T5, T6, T7, T8]>>;\n\n// Variadic fallback for 9+\nexport function mergeEventRouters(\n ...routers: EventRouterInput<EventRouterConfig>[]\n): EventRouterDefinition<EventRouterConfig>;\n\n// Implementation\nexport function mergeEventRouters(\n ...routers: EventRouterInput<EventRouterConfig>[]\n): EventRouterDefinition<EventRouterConfig> {\n const merged = routers.map(extractHandlers).reduce(deepMergeConfigs);\n return defineEventRouter(merged);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,54 @@
1
+ import {
2
+ isErrorType
3
+ } from "./chunk-H5TNDC5U.js";
4
+
5
+ // src/presentation/events/shared/error-mapping.ts
6
+ var DLQ_ERROR_TYPES = [
7
+ "ObjectValidationError",
8
+ "InvalidRequestError",
9
+ "UseCaseError",
10
+ "DomainError",
11
+ "UnprocessableError",
12
+ "AccessDeniedError",
13
+ "ForbiddenError",
14
+ "UnauthorizedError",
15
+ "InvariantViolationError"
16
+ ];
17
+ var RETRY_ERROR_TYPES = [
18
+ "NotFoundError",
19
+ "ConflictError",
20
+ "InfraError",
21
+ "DbError",
22
+ "NetworkError",
23
+ "TimeoutError",
24
+ "ExternalServiceError",
25
+ "PersistenceError"
26
+ ];
27
+ function mapErrorToEventResult(error) {
28
+ for (const typeName of DLQ_ERROR_TYPES) {
29
+ if (isErrorType(error, typeName)) {
30
+ return {
31
+ outcome: "dlq",
32
+ reason: error.message
33
+ };
34
+ }
35
+ }
36
+ for (const typeName of RETRY_ERROR_TYPES) {
37
+ if (isErrorType(error, typeName)) {
38
+ return {
39
+ outcome: "retry",
40
+ reason: error.message
41
+ };
42
+ }
43
+ }
44
+ const message = error instanceof Error ? error.message : "Unknown error occurred during event processing";
45
+ return {
46
+ outcome: "retry",
47
+ reason: message
48
+ };
49
+ }
50
+
51
+ export {
52
+ mapErrorToEventResult
53
+ };
54
+ //# sourceMappingURL=chunk-4BVOLXDJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presentation/events/shared/error-mapping.ts"],"sourcesContent":["/**\n * @fileoverview Error-to-EventResult mapping for event handlers.\n *\n * Maps caught errors to event processing outcomes (ack/retry/dlq).\n * Uses the same name-based type checking as the HTTP error mapper\n * for compatibility with bundled/minified code.\n *\n * @module events/shared/error-mapping\n */\n\nimport { isErrorType } from '../../http/shared/error-mapping';\nimport type { EventResult } from './types';\n\n// ============================================================================\n// Error Type Classifications\n// ============================================================================\n\n/**\n * Error types that indicate permanent failures (send to DLQ).\n * These errors will not resolve on retry.\n */\nconst DLQ_ERROR_TYPES = [\n 'ObjectValidationError',\n 'InvalidRequestError',\n 'UseCaseError',\n 'DomainError',\n 'UnprocessableError',\n 'AccessDeniedError',\n 'ForbiddenError',\n 'UnauthorizedError',\n 'InvariantViolationError',\n];\n\n/**\n * Error types that indicate transient failures (retry).\n * These errors may resolve on subsequent attempts.\n */\nconst RETRY_ERROR_TYPES = [\n 'NotFoundError',\n 'ConflictError',\n 'InfraError',\n 'DbError',\n 'NetworkError',\n 'TimeoutError',\n 'ExternalServiceError',\n 'PersistenceError',\n];\n\n// ============================================================================\n// Mapping Function\n// ============================================================================\n\n/**\n * Maps a caught error to an EventResult.\n *\n * Default mapping strategy:\n *\n * | Error Type | Outcome | Rationale |\n * |------------------------------------------------|---------|----------------------------------------|\n * | ObjectValidationError, InvalidRequestError | dlq | Bad payload — retrying won't help |\n * | UseCaseError | dlq | Business rule rejection — permanent |\n * | DomainError, InvariantViolationError | dlq | Domain invariant — permanent |\n * | UnprocessableError | dlq | Valid but not processable — permanent |\n * | AccessDeniedError, ForbiddenError, Unauthorized | dlq | Permission — permanent |\n * | NotFoundError | retry | Entity might not exist yet |\n * | ConflictError | retry | Concurrent write — may resolve |\n * | InfraError, DbError, NetworkError, TimeoutError | retry | Infrastructure/transient |\n * | Unknown | retry | Conservative — don't lose messages |\n *\n * @param error - The caught error\n * @returns An EventResult indicating how the message should be handled\n */\nexport function mapErrorToEventResult(error: unknown): EventResult {\n // Check DLQ errors first (permanent failures)\n for (const typeName of DLQ_ERROR_TYPES) {\n if (isErrorType(error, typeName)) {\n return {\n outcome: 'dlq',\n reason: (error as { message: string }).message,\n };\n }\n }\n\n // Check retry errors (transient failures)\n for (const typeName of RETRY_ERROR_TYPES) {\n if (isErrorType(error, typeName)) {\n return {\n outcome: 'retry',\n reason: (error as { message: string }).message,\n };\n }\n }\n\n // Unknown errors — retry conservatively to avoid losing messages\n const message =\n error instanceof Error ? error.message : 'Unknown error occurred during event processing';\n\n return {\n outcome: 'retry',\n reason: message,\n };\n}\n"],"mappings":";;;;;AAqBA,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA0BO,SAAS,sBAAsB,OAA6B;AAEjE,aAAW,YAAY,iBAAiB;AACtC,QAAI,YAAY,OAAO,QAAQ,GAAG;AAChC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAS,MAA8B;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAGA,aAAW,YAAY,mBAAmB;AACxC,QAAI,YAAY,OAAO,QAAQ,GAAG;AAChC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAS,MAA8B;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAE3C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;","names":[]}
@@ -0,0 +1,34 @@
1
+ // src/presentation/events/handler/types/event-router-definition.type.ts
2
+ function isEventHandlerDefinition(value) {
3
+ return typeof value === "object" && value !== null && "eventType" in value && "_types" in value;
4
+ }
5
+ function isEventRouterDefinition(value) {
6
+ return typeof value === "object" && value !== null && "_isEventRouter" in value && value._isEventRouter === true;
7
+ }
8
+ function collectEventHandlers(config, basePath = "") {
9
+ const handlers = [];
10
+ for (const [key, value] of Object.entries(config)) {
11
+ const fullKey = basePath ? `${basePath}.${key}` : key;
12
+ if (isEventHandlerDefinition(value)) {
13
+ handlers.push({ key: fullKey, handler: value });
14
+ } else if (isEventRouterDefinition(value)) {
15
+ handlers.push(...collectEventHandlers(value.handlers, fullKey));
16
+ } else if (typeof value === "object" && value !== null) {
17
+ handlers.push(...collectEventHandlers(value, fullKey));
18
+ }
19
+ }
20
+ return handlers;
21
+ }
22
+
23
+ // src/presentation/events/handler/utils.ts
24
+ function generateHandlerId(key) {
25
+ return key.replace(/\.(\w)/g, (_, char) => char.toUpperCase());
26
+ }
27
+
28
+ export {
29
+ isEventHandlerDefinition,
30
+ isEventRouterDefinition,
31
+ collectEventHandlers,
32
+ generateHandlerId
33
+ };
34
+ //# sourceMappingURL=chunk-CBTICRSM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presentation/events/handler/types/event-router-definition.type.ts","../src/presentation/events/handler/utils.ts"],"sourcesContent":["/**\n * @fileoverview Event router definition types for grouping event handlers.\n *\n * Mirrors the HTTP router definition pattern with hierarchical grouping,\n * dotted-key access, and deep merge support.\n *\n * @module events/handler/types/event-router-definition\n */\n\nimport type { EventHandlerDefinition } from './event-handler-definition.type';\nimport type { SchemaAdapter } from '../../../http/schema/types';\n\n// ============================================================================\n// Router Types\n// ============================================================================\n\n/**\n * A router entry can be an event handler definition, a nested config, or a router definition.\n */\nexport type EventRouterEntry =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n EventHandlerDefinition<string, any, any> | EventRouterConfig | EventRouterDefinition;\n\n/**\n * Configuration for an event router (group of event handlers).\n */\nexport interface EventRouterConfig {\n readonly [key: string]: EventRouterEntry;\n}\n\n/**\n * Router-level defaults applied to all child event handlers.\n */\nexport interface EventRouterDefaults {\n /** Default tags for all handlers. Merged with handler-specific tags. */\n readonly tags?: readonly string[];\n\n /** Default context schema. Applied to handlers that don't define their own. */\n readonly context?: SchemaAdapter;\n}\n\n/**\n * A fully defined event router.\n */\nexport interface EventRouterDefinition<T extends EventRouterConfig = EventRouterConfig> {\n /** The handlers and nested routers in this router. */\n readonly handlers: T;\n\n /** Default values applied to all child handlers. */\n readonly defaults?: EventRouterDefaults;\n\n /**\n * Marker to identify this as an event router.\n * @internal\n */\n readonly _isEventRouter: true;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Checks if a value is an EventHandlerDefinition.\n */\nexport function isEventHandlerDefinition(value: unknown): value is EventHandlerDefinition {\n return typeof value === 'object' && value !== null && 'eventType' in value && '_types' in value;\n}\n\n/**\n * Checks if a value is an EventRouterDefinition.\n */\nexport function isEventRouterDefinition(value: unknown): value is EventRouterDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n '_isEventRouter' in value &&\n (value as EventRouterDefinition)._isEventRouter === true\n );\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Flattens an event router into a map of dotted keys to handler definitions.\n */\nexport type FlattenEventRouter<\n T extends EventRouterConfig,\n Prefix extends string = '',\n> = T extends EventRouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends EventHandlerDefinition<any, any, any>\n ? { [P in `${Prefix}${K & string}`]: T[K] }\n : T[K] extends EventRouterConfig\n ? FlattenEventRouter<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, EventHandlerDefinition<any, any, any>>\n ? U\n : never\n : never\n : never;\n\n/**\n * Gets all handler keys from an event router.\n */\nexport type EventRouterKeys<\n T extends EventRouterConfig,\n Prefix extends string = '',\n> = T extends EventRouterConfig\n ? {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [K in keyof T]: T[K] extends EventHandlerDefinition<any, any, any>\n ? `${Prefix}${K & string}`\n : T[K] extends EventRouterConfig\n ? EventRouterKeys<T[K], `${Prefix}${K & string}.`>\n : never;\n }[keyof T]\n : never;\n\n/**\n * Gets an event handler by its dotted key path.\n */\nexport type GetEventHandler<\n T extends EventRouterConfig,\n K extends string,\n> = K extends `${infer Head}.${infer Tail}`\n ? Head extends keyof T\n ? T[Head] extends EventRouterConfig\n ? GetEventHandler<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 EventHandlerDefinition<any, any, any>\n ? T[K]\n : never\n : never;\n\n// ============================================================================\n// Deep Merge Types\n// ============================================================================\n\n/**\n * Deep-merges two event router configs at the type level.\n */\nexport type DeepMergeTwo<A extends EventRouterConfig, B extends EventRouterConfig> = {\n readonly [K in keyof A | keyof B]: K extends keyof A\n ? K extends keyof B\n ? A[K] extends EventRouterConfig\n ? B[K] extends EventRouterConfig\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 event router configs left-to-right.\n */\nexport type DeepMergeAll<T extends readonly EventRouterConfig[]> = T extends readonly [\n infer Only extends EventRouterConfig,\n]\n ? Only\n : T extends readonly [\n infer First extends EventRouterConfig,\n infer Second extends EventRouterConfig,\n ...infer Rest extends readonly EventRouterConfig[],\n ]\n ? DeepMergeAll<[DeepMergeTwo<First, Second>, ...Rest]>\n : EventRouterConfig;\n\n// ============================================================================\n// Runtime Utilities\n// ============================================================================\n\n/**\n * Collects all event handlers from a router into a flat array.\n */\nexport function collectEventHandlers(\n config: EventRouterConfig,\n basePath = '',\n): { key: string; handler: EventHandlerDefinition }[] {\n const handlers: { key: string; handler: EventHandlerDefinition }[] = [];\n\n for (const [key, value] of Object.entries(config)) {\n const fullKey = basePath ? `${basePath}.${key}` : key;\n\n if (isEventHandlerDefinition(value)) {\n handlers.push({ key: fullKey, handler: value });\n } else if (isEventRouterDefinition(value)) {\n handlers.push(...collectEventHandlers(value.handlers, fullKey));\n } else if (typeof value === 'object' && value !== null) {\n handlers.push(...collectEventHandlers(value as EventRouterConfig, fullKey));\n }\n }\n\n return handlers;\n}\n","/**\n * @fileoverview Utility functions for event handler routing.\n *\n * @module events/handler/utils\n */\n\n/**\n * Generates a handler ID from a dotted key path.\n *\n * Converts dot-separated keys to camelCase:\n * - `\"ticket.created\"` → `\"ticketCreated\"`\n * - `\"ecosystem.member.added\"` → `\"ecosystemMemberAdded\"`\n *\n * @param key - The dotted key path\n * @returns A camelCase handler ID\n */\nexport function generateHandlerId(key: string): string {\n return key.replace(/\\.(\\w)/g, (_, char: string) => char.toUpperCase());\n}\n"],"mappings":";AAiEO,SAAS,yBAAyB,OAAiD;AACxF,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe,SAAS,YAAY;AAC5F;AAKO,SAAS,wBAAwB,OAAgD;AACtF,SACE,OAAO,UAAU,YACjB,UAAU,QACV,oBAAoB,SACnB,MAAgC,mBAAmB;AAExD;AA2GO,SAAS,qBACd,QACA,WAAW,IACyC;AACpD,QAAM,WAA+D,CAAC;AAEtE,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAM,UAAU,WAAW,GAAG,QAAQ,IAAI,GAAG,KAAK;AAElD,QAAI,yBAAyB,KAAK,GAAG;AACnC,eAAS,KAAK,EAAE,KAAK,SAAS,SAAS,MAAM,CAAC;AAAA,IAChD,WAAW,wBAAwB,KAAK,GAAG;AACzC,eAAS,KAAK,GAAG,qBAAqB,MAAM,UAAU,OAAO,CAAC;AAAA,IAChE,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,eAAS,KAAK,GAAG,qBAAqB,OAA4B,OAAO,CAAC;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO;AACT;;;AC7LO,SAAS,kBAAkB,KAAqB;AACrD,SAAO,IAAI,QAAQ,WAAW,CAAC,GAAG,SAAiB,KAAK,YAAY,CAAC;AACvE;","names":[]}
@@ -0,0 +1,96 @@
1
+ import {
2
+ collectEventHandlers,
3
+ generateHandlerId,
4
+ isEventRouterDefinition
5
+ } from "./chunk-CBTICRSM.js";
6
+
7
+ // src/presentation/events/asyncapi/generate.ts
8
+ function generateAsyncAPI(router, config) {
9
+ const routerConfig = isEventRouterDefinition(router) ? router.handlers : router;
10
+ const handlers = collectEventHandlers(routerConfig);
11
+ const channels = {};
12
+ const operations = {};
13
+ const allTags = /* @__PURE__ */ new Set();
14
+ for (const { key, handler } of handlers) {
15
+ const handlerId = generateHandlerId(key);
16
+ const channelId = handler.eventType;
17
+ const message = buildMessage(handler.eventType, handler.payload, handler.docs);
18
+ if (!channels[channelId]) {
19
+ channels[channelId] = {
20
+ address: handler.eventType,
21
+ messages: {}
22
+ };
23
+ }
24
+ const channelMessages = { ...channels[channelId].messages ?? {} };
25
+ channelMessages[handlerId] = message;
26
+ channels[channelId] = { ...channels[channelId], messages: channelMessages };
27
+ const operation = {
28
+ action: "receive",
29
+ channel: { $ref: `#/channels/${channelId}` },
30
+ messages: [{ $ref: `#/channels/${channelId}/messages/${handlerId}` }]
31
+ };
32
+ if (handler.docs.summary) {
33
+ operation.summary = handler.docs.summary;
34
+ }
35
+ if (handler.docs.description) {
36
+ operation.description = handler.docs.description;
37
+ }
38
+ if (handler.docs.deprecated) {
39
+ operation.deprecated = true;
40
+ }
41
+ if (handler.docs.tags && handler.docs.tags.length > 0) {
42
+ operation.tags = handler.docs.tags.map((t) => ({
43
+ name: t
44
+ }));
45
+ for (const tag of handler.docs.tags) {
46
+ allTags.add(tag);
47
+ }
48
+ }
49
+ operations[handlerId] = operation;
50
+ }
51
+ const tags = config.tags ? [...config.tags] : [];
52
+ for (const tagName of allTags) {
53
+ if (!tags.some((t) => t.name === tagName)) {
54
+ tags.push({ name: tagName });
55
+ }
56
+ }
57
+ const info = tags.length > 0 ? { ...config.info, tags } : config.info;
58
+ const spec = {
59
+ asyncapi: config.asyncapi ?? "3.0.0",
60
+ info,
61
+ defaultContentType: config.defaultContentType ?? "application/json",
62
+ channels,
63
+ operations
64
+ };
65
+ if (config.servers && Object.keys(config.servers).length > 0) {
66
+ spec.servers = config.servers;
67
+ }
68
+ if (config.externalDocs) {
69
+ spec.externalDocs = config.externalDocs;
70
+ }
71
+ return spec;
72
+ }
73
+ function buildMessage(eventType, payload, docs) {
74
+ const message = {
75
+ name: eventType
76
+ };
77
+ if (docs.summary) {
78
+ message.summary = docs.summary;
79
+ }
80
+ if (docs.description) {
81
+ message.description = docs.description;
82
+ }
83
+ if (docs.deprecated) {
84
+ message.deprecated = true;
85
+ }
86
+ if (payload) {
87
+ const schema = payload.toJsonSchema();
88
+ message.payload = schema;
89
+ }
90
+ return message;
91
+ }
92
+
93
+ export {
94
+ generateAsyncAPI
95
+ };
96
+ //# sourceMappingURL=chunk-KJ4JGZOE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presentation/events/asyncapi/generate.ts"],"sourcesContent":["/**\n * @fileoverview AsyncAPI specification generation from event router definitions.\n *\n * The `generateAsyncAPI` function creates a complete AsyncAPI 3.0 specification\n * from an event router definition. All handler payload schemas are converted to\n * JSON Schema and included in the specification.\n *\n * @module events/asyncapi/generate\n */\n\nimport type { SchemaAdapter } from '../../http/schema/types';\nimport type { EventRouterConfig, EventRouterDefinition } from '../handler/types';\nimport { isEventRouterDefinition, collectEventHandlers } from '../handler/types';\nimport { generateHandlerId } from '../handler/utils';\nimport type {\n AsyncAPIConfig,\n AsyncAPISpec,\n AsyncAPIChannel,\n AsyncAPIOperation,\n AsyncAPIMessage,\n AsyncAPITag,\n} from './types';\n\n/**\n * Generates an AsyncAPI 3.0 specification from an event router definition.\n *\n * This function walks the event router structure, extracts JSON schemas from\n * all handler payload definitions, and builds a complete AsyncAPI 3.0 specification.\n *\n * @param router - Event router definition or raw config\n * @param config - AsyncAPI configuration (info, servers, tags, etc.)\n * @returns Complete AsyncAPI specification\n *\n * @example\n * ```typescript\n * import { generateAsyncAPI } from '@cosmneo/onion-lasagna/events/asyncapi';\n * import { notificationEventRouter } from './events/router';\n *\n * const spec = generateAsyncAPI(notificationEventRouter, {\n * info: {\n * title: 'My Event API',\n * version: '1.0.0',\n * description: 'Domain events for the application',\n * },\n * });\n *\n * app.get('/asyncapi.json', (c) => c.json(spec));\n * ```\n */\nexport function generateAsyncAPI<T extends EventRouterConfig>(\n router: T | EventRouterDefinition<T>,\n config: AsyncAPIConfig,\n): AsyncAPISpec {\n const routerConfig = isEventRouterDefinition(router) ? router.handlers : router;\n const handlers = collectEventHandlers(routerConfig);\n\n const channels: Record<string, AsyncAPIChannel> = {};\n const operations: Record<string, AsyncAPIOperation> = {};\n const allTags = new Set<string>();\n\n for (const { key, handler } of handlers) {\n const handlerId = generateHandlerId(key);\n const channelId = handler.eventType;\n\n // Build message\n const message = buildMessage(handler.eventType, handler.payload, handler.docs);\n\n // Build channel (group by eventType — multiple handlers may share a channel)\n if (!channels[channelId]) {\n channels[channelId] = {\n address: handler.eventType,\n messages: {},\n };\n }\n const channelMessages = { ...(channels[channelId]!.messages ?? {}) };\n channelMessages[handlerId] = message;\n channels[channelId] = { ...channels[channelId]!, messages: channelMessages };\n\n // Build operation (one per handler)\n const operation: AsyncAPIOperation = {\n action: 'receive',\n channel: { $ref: `#/channels/${channelId}` },\n messages: [{ $ref: `#/channels/${channelId}/messages/${handlerId}` }],\n };\n\n if (handler.docs.summary) {\n (operation as { summary: string }).summary = handler.docs.summary;\n }\n if (handler.docs.description) {\n (operation as { description: string }).description = handler.docs.description;\n }\n if (handler.docs.deprecated) {\n (operation as { deprecated: boolean }).deprecated = true;\n }\n if (handler.docs.tags && handler.docs.tags.length > 0) {\n (operation as { tags: readonly AsyncAPITag[] }).tags = handler.docs.tags.map((t) => ({\n name: t,\n }));\n for (const tag of handler.docs.tags) {\n allTags.add(tag);\n }\n }\n\n operations[handlerId] = operation;\n }\n\n // Merge custom tags with collected tags (AsyncAPI 3.0: tags live inside info)\n const tags: AsyncAPITag[] = config.tags ? [...config.tags] : [];\n for (const tagName of allTags) {\n if (!tags.some((t) => t.name === tagName)) {\n tags.push({ name: tagName });\n }\n }\n\n const info = tags.length > 0 ? { ...config.info, tags } : config.info;\n\n // Build the specification\n const spec: AsyncAPISpec = {\n asyncapi: config.asyncapi ?? '3.0.0',\n info,\n defaultContentType: config.defaultContentType ?? 'application/json',\n channels,\n operations,\n };\n\n if (config.servers && Object.keys(config.servers).length > 0) {\n (spec as { servers: typeof config.servers }).servers = config.servers;\n }\n\n if (config.externalDocs) {\n (spec as { externalDocs: typeof config.externalDocs }).externalDocs = config.externalDocs;\n }\n\n return spec;\n}\n\n/**\n * Builds an AsyncAPI message from a handler definition.\n */\nfunction buildMessage(\n eventType: string,\n payload: unknown,\n docs: {\n readonly summary?: string;\n readonly description?: string;\n readonly tags?: readonly string[];\n readonly deprecated?: boolean;\n },\n): AsyncAPIMessage {\n const message: AsyncAPIMessage = {\n name: eventType,\n };\n\n if (docs.summary) {\n (message as { summary: string }).summary = docs.summary;\n }\n if (docs.description) {\n (message as { description: string }).description = docs.description;\n }\n if (docs.deprecated) {\n (message as { deprecated: boolean }).deprecated = true;\n }\n\n if (payload) {\n const schema = (payload as SchemaAdapter).toJsonSchema();\n (message as { payload: typeof schema }).payload = schema;\n }\n\n return message;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-RVSBIYY4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -165,4 +165,4 @@ export {
165
165
  defineRouter,
166
166
  mergeRouters
167
167
  };
168
- //# sourceMappingURL=chunk-MF2JDREK.js.map
168
+ //# sourceMappingURL=chunk-UNVB4INM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/presentation/http/route/define-route.ts","../src/presentation/http/route/define-router.ts"],"sourcesContent":["/**\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 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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/presentation/http/route/define-route.ts","../src/presentation/http/route/define-router.ts"],"sourcesContent":["/**\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 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\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 T9 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 r9: RouterInput<T9>,\n): RouterDefinition<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<T1, T2>, T3>, T4>, T5>,\n T6\n >,\n T7\n >,\n T8\n >,\n T9\n >\n>;\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 T9 extends RouterConfig,\n T10 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 r9: RouterInput<T9>,\n r10: RouterInput<T10>,\n): RouterDefinition<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<T1, T2>, T3>, T4>, T5>,\n T6\n >,\n T7\n >,\n T8\n >,\n T9\n >,\n T10\n >\n>;\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 T9 extends RouterConfig,\n T10 extends RouterConfig,\n T11 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 r9: RouterInput<T9>,\n r10: RouterInput<T10>,\n r11: RouterInput<T11>,\n): RouterDefinition<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<T1, T2>, T3>, T4>, T5>,\n T6\n >,\n T7\n >,\n T8\n >,\n T9\n >,\n T10\n >,\n T11\n >\n>;\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 T9 extends RouterConfig,\n T10 extends RouterConfig,\n T11 extends RouterConfig,\n T12 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 r9: RouterInput<T9>,\n r10: RouterInput<T10>,\n r11: RouterInput<T11>,\n r12: RouterInput<T12>,\n): RouterDefinition<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<\n DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<DeepMergeTwo<T1, T2>, T3>, T4>, T5>,\n T6\n >,\n T7\n >,\n T8\n >,\n T9\n >,\n T10\n >,\n T11\n >,\n T12\n >\n>;\n\n// Variadic fallback for 13+\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":[]}