@mpen/routekit 0.1.0 → 0.1.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 (133) hide show
  1. package/dist/bin.d.mts +4 -0
  2. package/dist/client/react.d.mts +178 -0
  3. package/dist/client/react.mjs +142 -0
  4. package/dist/client.d.mts +433 -0
  5. package/dist/client.mjs +264 -0
  6. package/dist/content-BuDOmhH_.mjs +102 -0
  7. package/dist/core-CzUCxvGk.d.mts +140 -0
  8. package/dist/core-DbmQauwS.mjs +81 -0
  9. package/dist/handlers.d.mts +72 -0
  10. package/dist/handlers.mjs +153 -0
  11. package/dist/index.d.mts +3 -0
  12. package/dist/index.mjs +1152 -0
  13. package/dist/middleware.d.mts +388 -0
  14. package/dist/middleware.mjs +1222 -0
  15. package/dist/request-Dn0zc-xm.mjs +1025 -0
  16. package/dist/response/content.d.mts +79 -0
  17. package/dist/response/content.mjs +2 -0
  18. package/dist/response/json-rpc.d.mts +1 -0
  19. package/dist/response/json-rpc.mjs +1 -0
  20. package/dist/response/problem/valibot.d.mts +230 -0
  21. package/dist/response/problem/valibot.mjs +258 -0
  22. package/dist/response/problem.d.mts +415 -0
  23. package/dist/response/problem.mjs +183 -0
  24. package/dist/response/status.d.mts +45 -0
  25. package/dist/response/status.mjs +2 -0
  26. package/dist/responses-B379Ep9Y.d.mts +296 -0
  27. package/dist/responses-BpVrgeYi.mjs +101 -0
  28. package/dist/router-Cwb7ak0J.d.mts +1819 -0
  29. package/dist/routes.d.mts +282 -0
  30. package/dist/routes.mjs +311 -0
  31. package/dist/status-C-8mw-FB.mjs +59 -0
  32. package/dist/valibot-D7liFYyB.d.mts +290 -0
  33. package/dist/valibot-Du97X-TS.mjs +326 -0
  34. package/package.json +8 -2
  35. package/src/bin/gen-api-client.test.ts +0 -70
  36. package/src/bin/gen-api-client.ts +0 -986
  37. package/src/client/headers.ts +0 -31
  38. package/src/client/index.ts +0 -8
  39. package/src/client/promise.ts +0 -11
  40. package/src/client/react/index.test.tsx +0 -266
  41. package/src/client/react/index.ts +0 -431
  42. package/src/client/responses.test.ts +0 -151
  43. package/src/client/responses.ts +0 -278
  44. package/src/client/transport.ts +0 -74
  45. package/src/client/transports/body-codec.ts +0 -61
  46. package/src/client/transports/fetch.ts +0 -113
  47. package/src/client/tsconfig.json +0 -9
  48. package/src/client/types.ts +0 -15
  49. package/src/client/url.ts +0 -31
  50. package/src/index.ts +0 -63
  51. package/src/router/fetch-types.ts +0 -13
  52. package/src/router/handlers/index.ts +0 -2
  53. package/src/router/handlers/openapi/index.ts +0 -2
  54. package/src/router/handlers/openapi/openapi.ts +0 -293
  55. package/src/router/integration/zod-openapi.test.ts +0 -74
  56. package/src/router/lib/charset.test.ts +0 -22
  57. package/src/router/lib/charset.ts +0 -133
  58. package/src/router/lib/collections.ts +0 -3
  59. package/src/router/lib/format.test.ts +0 -67
  60. package/src/router/lib/format.ts +0 -35
  61. package/src/router/lib/host.ts +0 -4
  62. package/src/router/lib/json-schema.ts +0 -6
  63. package/src/router/lib/media-type.test.ts +0 -122
  64. package/src/router/lib/media-type.ts +0 -289
  65. package/src/router/lib/pathname.test.ts +0 -18
  66. package/src/router/lib/pathname.ts +0 -19
  67. package/src/router/lib/route-names.ts +0 -70
  68. package/src/router/lib/route-normalize.test.ts +0 -36
  69. package/src/router/lib/route-normalize.ts +0 -67
  70. package/src/router/lib/schema-merge.ts +0 -56
  71. package/src/router/middleware/accept-ctx.test.ts +0 -33
  72. package/src/router/middleware/accept-ctx.ts +0 -12
  73. package/src/router/middleware/body-limit.test.ts +0 -112
  74. package/src/router/middleware/body-limit.ts +0 -121
  75. package/src/router/middleware/content-type-context.ts +0 -0
  76. package/src/router/middleware/cors.test.ts +0 -269
  77. package/src/router/middleware/cors.ts +0 -490
  78. package/src/router/middleware/csrf.test.ts +0 -106
  79. package/src/router/middleware/csrf.ts +0 -192
  80. package/src/router/middleware/define.ts +0 -249
  81. package/src/router/middleware/index.ts +0 -34
  82. package/src/router/middleware/jsxhtml-response.ts +0 -0
  83. package/src/router/middleware/oas-swagger.ts +0 -0
  84. package/src/router/middleware/rate-limit.test.ts +0 -886
  85. package/src/router/middleware/rate-limit.ts +0 -920
  86. package/src/router/middleware/request-id-ctx.test.ts +0 -183
  87. package/src/router/middleware/request-id-ctx.ts +0 -135
  88. package/src/router/middleware/request-logger-format.test.ts +0 -16
  89. package/src/router/middleware/request-logger-format.ts +0 -269
  90. package/src/router/middleware/request-logger.test.ts +0 -267
  91. package/src/router/middleware/request-logger.ts +0 -131
  92. package/src/router/middleware/start-time-ctx.ts +0 -5
  93. package/src/router/request.ts +0 -611
  94. package/src/router/response/core.ts +0 -181
  95. package/src/router/response/directives.ts +0 -233
  96. package/src/router/response/formats/content/bodyless.ts +0 -54
  97. package/src/router/response/formats/content/content.ts +0 -79
  98. package/src/router/response/formats/content/index.ts +0 -2
  99. package/src/router/response/formats/json-rpc/index.ts +0 -2
  100. package/src/router/response/formats/problem/badRequest.ts +0 -90
  101. package/src/router/response/formats/problem/conflict.ts +0 -90
  102. package/src/router/response/formats/problem/created.ts +0 -40
  103. package/src/router/response/formats/problem/index.ts +0 -27
  104. package/src/router/response/formats/problem/notFound.ts +0 -90
  105. package/src/router/response/formats/problem/permissionDenied.ts +0 -90
  106. package/src/router/response/formats/problem/problem.test.ts +0 -888
  107. package/src/router/response/formats/problem/rateLimited.ts +0 -90
  108. package/src/router/response/formats/problem/responses.ts +0 -219
  109. package/src/router/response/formats/problem/root-errors.ts +0 -48
  110. package/src/router/response/formats/problem/sessionExpired.ts +0 -90
  111. package/src/router/response/formats/problem/types.ts +0 -170
  112. package/src/router/response/formats/problem/unauthenticated.ts +0 -90
  113. package/src/router/response/formats/problem/valibot.ts +0 -410
  114. package/src/router/response/formats/status/index.ts +0 -1
  115. package/src/router/response/formats/status/responses.ts +0 -59
  116. package/src/router/response/formats/status/status.test.ts +0 -21
  117. package/src/router/response/framers.ts +0 -85
  118. package/src/router/response/index.ts +0 -28
  119. package/src/router/response/openapi.test.ts +0 -96
  120. package/src/router/response/openapi.ts +0 -1
  121. package/src/router/response/serializers.ts +0 -66
  122. package/src/router/response/stream.ts +0 -35
  123. package/src/router/router.test.ts +0 -1571
  124. package/src/router/router.ts +0 -1965
  125. package/src/router/routes/index.ts +0 -46
  126. package/src/router/routes/valibot/index.ts +0 -18
  127. package/src/router/routes/valibot/valibot.ts +0 -1393
  128. package/src/router/routes/valibot.test.ts +0 -286
  129. package/src/router/routes/zod/index.ts +0 -18
  130. package/src/router/routes/zod/zod.ts +0 -1318
  131. package/src/router/routes/zod.test.ts +0 -280
  132. package/src/router/server-interface.ts +0 -31
  133. package/src/router/types.ts +0 -657
@@ -0,0 +1,290 @@
1
+ import { C as MiddlewareInput, I as RouteOptions, N as Route, a as MiddlewareResponseDeclaration, f as ContextFromMiddlewareInput, g as HandlerResult, h as HandlerContext, l as AddedContextFromMiddlewareInput, n as DeclaredMiddleware, r as DefineMiddlewareOptions, t as Router } from "./router-Cwb7ak0J.mjs";
2
+ import { n as RoutekitResponse } from "./core-CzUCxvGk.mjs";
3
+ import * as v from "valibot";
4
+
5
+ //#region src/router/routes/valibot/valibot.d.ts
6
+ /**
7
+ * Validation error component identifiers for Valibot-backed routes.
8
+ */
9
+ declare const enum ValibotValidationError {
10
+ REQUEST_BODY = 0,
11
+ URL_PATH = 1,
12
+ QUERY_PARAMETERS = 2
13
+ }
14
+ type AnyValibotSchema = v.GenericSchema;
15
+ type ValibotSchema = AnyValibotSchema | undefined;
16
+ type ValibotObjectSchema = v.ObjectSchema<v.ObjectEntries, v.ErrorMessage<v.ObjectIssue> | undefined>;
17
+ type ValibotPathSchema = ValibotObjectSchema | undefined;
18
+ type AnyValibotResponseBodySchemas = Partial<Record<number | 'default', AnyValibotSchema>>;
19
+ type ValibotResponseBodySchemas = AnyValibotResponseBodySchemas | undefined;
20
+ type ResponseValidationMode = false | 'strict' | 'parse';
21
+ type ResponseValidationOption = boolean | ResponseValidationMode;
22
+ type ValibotRouteContext<Ctx extends object, BuilderMiddleware, RouteMiddleware> = Ctx & AddedContextFromMiddlewareInput<BuilderMiddleware> & AddedContextFromMiddlewareInput<RouteMiddleware>;
23
+ type ValibotBuilderMiddlewareInput<Ctx extends object, BuilderMiddleware extends MiddlewareInput<Ctx>, RouteMiddleware extends MiddlewareInput<Ctx>> = [BuilderMiddleware] extends [undefined] ? RouteMiddleware : [RouteMiddleware] extends [undefined] ? BuilderMiddleware : MiddlewareInput<Ctx>;
24
+ /**
25
+ * Default validation error payload returned by Valibot-backed routes.
26
+ */
27
+ type ValibotValidationErrorBody = {
28
+ component: 'request_body' | 'url_path' | 'query_parameters';
29
+ issues: v.BaseIssue<unknown>[];
30
+ message: string;
31
+ };
32
+ /**
33
+ * Valibot schema input that mirrors the core route `schema` shape.
34
+ */
35
+ type ValibotRouteSchemaInput<BodySchema extends ValibotSchema = undefined, PathSchema extends ValibotPathSchema = undefined, QuerySchema extends ValibotSchema = undefined, ResponseBodySchemas extends ValibotResponseBodySchemas = undefined> = {
36
+ request?: {
37
+ query?: QuerySchema;
38
+ path?: PathSchema;
39
+ body?: BodySchema;
40
+ };
41
+ response?: {
42
+ body?: ResponseBodySchemas;
43
+ };
44
+ };
45
+ type AnyValibotRouteSchemaInput = ValibotRouteSchemaInput<AnyValibotSchema, ValibotObjectSchema, AnyValibotSchema, AnyValibotResponseBodySchemas>;
46
+ type InferSchema<Schema extends ValibotSchema> = Schema extends v.GenericSchema ? v.InferOutput<Schema> : unknown;
47
+ type InferResponseBodySchemaUnion<ResponseBodySchemas extends AnyValibotResponseBodySchemas> = [keyof ResponseBodySchemas] extends [never] ? unknown : { [Status in keyof ResponseBodySchemas]: NonNullable<ResponseBodySchemas[Status]> extends AnyValibotSchema ? v.InferOutput<NonNullable<ResponseBodySchemas[Status]>> : never }[keyof ResponseBodySchemas];
48
+ type InferResponseBody<ResponseBodySchemas extends ValibotResponseBodySchemas> = ResponseBodySchemas extends AnyValibotResponseBodySchemas ? 200 extends keyof ResponseBodySchemas ? InferResponseBodySchemaUnion<ResponseBodySchemas> : 'default' extends keyof ResponseBodySchemas ? InferResponseBodySchemaUnion<ResponseBodySchemas> : unknown : unknown;
49
+ type NormalizeSchema<Schema> = Schema extends AnyValibotRouteSchemaInput ? Schema : ValibotRouteSchemaInput<undefined, undefined, undefined, undefined>;
50
+ type ExtractBodySchema<Schema extends AnyValibotRouteSchemaInput | undefined> = NormalizeSchema<Schema> extends ValibotRouteSchemaInput<infer BodySchema, infer _PathSchema, infer _QuerySchema, infer _ResponseBodySchemas> ? BodySchema : undefined;
51
+ type ExtractPathSchema<Schema extends AnyValibotRouteSchemaInput | undefined> = NormalizeSchema<Schema> extends ValibotRouteSchemaInput<infer _BodySchema, infer PathSchema, infer _QuerySchema, infer _ResponseBodySchemas> ? PathSchema : undefined;
52
+ type ExtractQuerySchema<Schema extends AnyValibotRouteSchemaInput | undefined> = NormalizeSchema<Schema> extends ValibotRouteSchemaInput<infer _BodySchema, infer _PathSchema, infer QuerySchema, infer _ResponseBodySchemas> ? QuerySchema : undefined;
53
+ type ExtractResponseBodySchemas<Schema extends AnyValibotRouteSchemaInput | undefined> = NormalizeSchema<Schema> extends ValibotRouteSchemaInput<infer _BodySchema, infer _PathSchema, infer _QuerySchema, infer ResponseBodySchemas> ? ResponseBodySchemas : undefined;
54
+ type ValibotMiddlewareDeclarations<Schemas extends AnyValibotResponseBodySchemas> = { [Status in keyof Schemas]: NonNullable<Schemas[Status]> extends AnyValibotSchema ? MiddlewareResponseDeclaration<v.InferOutput<NonNullable<Schemas[Status]>>> : never };
55
+ type ValibotDeclaredResponse<Schemas extends AnyValibotResponseBodySchemas> = { [Status in keyof Schemas]-?: NonNullable<Schemas[Status]> extends AnyValibotSchema ? RoutekitResponse<v.InferOutput<NonNullable<Schemas[Status]>>, Status extends number ? Status : number> : never }[keyof Schemas];
56
+ type ValibotSchemaMiddlewareContext<Schema extends AnyValibotRouteSchemaInput | undefined> = ValibotHandlerParams<ExtractBodySchema<Schema>, ExtractPathSchema<Schema>, ExtractQuerySchema<Schema>> & {
57
+ params: ValibotHandlerParams<ExtractBodySchema<Schema>, ExtractPathSchema<Schema>, ExtractQuerySchema<Schema>>;
58
+ };
59
+ /**
60
+ * Validated request inputs exposed to a Valibot-backed handler.
61
+ */
62
+ type ValibotHandlerParams<BodySchema extends ValibotSchema, PathSchema extends ValibotPathSchema, QuerySchema extends ValibotSchema> = {
63
+ path: InferSchema<PathSchema>;
64
+ query: InferSchema<QuerySchema>;
65
+ body: InferSchema<BodySchema>;
66
+ };
67
+ /**
68
+ * Context object exposed to a Valibot-backed handler.
69
+ */
70
+ type ValibotHandlerContext<BodySchema extends ValibotSchema, PathSchema extends ValibotPathSchema, QuerySchema extends ValibotSchema, Ctx extends object> = Omit<HandlerContext<Ctx>, 'path'> & ValibotHandlerParams<BodySchema, PathSchema, QuerySchema> & {
71
+ params: ValibotHandlerParams<BodySchema, PathSchema, QuerySchema>;
72
+ };
73
+ /**
74
+ * Validation error handler used when request parsing fails.
75
+ *
76
+ * @param component - Request component that failed validation.
77
+ * @param issues - The Valibot validation issues.
78
+ * @returns A handler result that should be returned to the client.
79
+ */
80
+ type ValibotValidationErrorHandler<Responses extends AnyValibotResponseBodySchemas = AnyValibotResponseBodySchemas> = (component: ValibotValidationError, issues: [v.BaseIssue<unknown>, ...v.BaseIssue<unknown>[]]) => ValibotDeclaredResponse<Responses>;
81
+ /**
82
+ * Shared defaults that can be applied to Valibot handler helpers.
83
+ */
84
+ type ValibotHandlerDefaults = {
85
+ /**
86
+ * Route schema fragments that should be merged into every built route.
87
+ * Route-level schemas override matching request fields and response status codes.
88
+ */
89
+ schema?: AnyValibotRouteSchemaInput;
90
+ /**
91
+ * Whether and how to apply `schema.response.body` to handler responses.
92
+ * `false` disables response validation, `true` and `'strict'` validate without changing the
93
+ * response body, and `'parse'` returns the parsed response body. Defaults to `'parse'`.
94
+ */
95
+ validateResponse?: ResponseValidationOption;
96
+ } & ({
97
+ onRequestValidationError?: undefined;
98
+ validationResponses?: undefined;
99
+ } | {
100
+ /**
101
+ * Override the default request validation error response.
102
+ */
103
+ onRequestValidationError: ValibotValidationErrorHandler;
104
+ /**
105
+ * Response schemas returned by `onRequestValidationError`.
106
+ */
107
+ validationResponses: AnyValibotResponseBodySchemas;
108
+ });
109
+ /**
110
+ * Shared defaults that can be applied to Valibot route helpers.
111
+ */
112
+ type ValibotRouteHelperDefaults<BuilderCtx extends object = object, BuilderMiddleware extends MiddlewareInput<BuilderCtx> = undefined> = ValibotHandlerDefaults & {
113
+ /**
114
+ * Middleware applied to every route built by the helper.
115
+ */
116
+ middleware?: BuilderMiddleware;
117
+ };
118
+ /**
119
+ * Handler signature used by Valibot schema boundaries and route builders.
120
+ */
121
+ type ValibotRouteHandler<BodySchema extends ValibotSchema, PathSchema extends ValibotPathSchema, QuerySchema extends ValibotSchema, ResponseBodySchemas extends ValibotResponseBodySchemas, Ctx extends object = object> = (this: Router<any>, ctx: ValibotHandlerContext<BodySchema, PathSchema, QuerySchema, Ctx>) => HandlerResult<InferResponseBody<ResponseBodySchemas>>;
122
+ /**
123
+ * Shared options used by Valibot route builders.
124
+ */
125
+ type ValibotHandlerOptions<Schema extends AnyValibotRouteSchemaInput | undefined, Ctx extends object = object> = ValibotHandlerDefaults & {
126
+ schema?: Schema;
127
+ handler: ValibotRouteHandler<ExtractBodySchema<Schema>, ExtractPathSchema<Schema>, ExtractQuerySchema<Schema>, ExtractResponseBodySchemas<Schema>, Ctx>;
128
+ };
129
+ /**
130
+ * Full route options used by Valibot route builders.
131
+ */
132
+ type ValibotRouteOptions<Schema extends AnyValibotRouteSchemaInput | undefined, Ctx extends object = object, BuilderMiddleware extends MiddlewareInput<Ctx> = undefined, RouteMiddleware extends MiddlewareInput<Ctx> = undefined> = Omit<Route<Ctx, RouteMiddleware, ValibotRouteContext<Ctx, BuilderMiddleware, RouteMiddleware>>, 'handler' | 'schema' | 'middleware'> & ValibotHandlerOptions<Schema, ValibotRouteContext<Ctx, BuilderMiddleware, RouteMiddleware>> & {
133
+ middleware?: RouteMiddleware;
134
+ };
135
+ /**
136
+ * Method-specific route options used by Valibot route builders.
137
+ */
138
+ type WithValibotOptions<Schema extends AnyValibotRouteSchemaInput | undefined, Ctx extends object = object, BuilderMiddleware extends MiddlewareInput<Ctx> = undefined, RouteMiddleware extends MiddlewareInput<Ctx> = undefined> = Omit<RouteOptions<Ctx, RouteMiddleware, ValibotRouteContext<Ctx, BuilderMiddleware, RouteMiddleware>>, 'handler' | 'schema' | 'middleware'> & ValibotHandlerOptions<Schema, ValibotRouteContext<Ctx, BuilderMiddleware, RouteMiddleware>> & {
139
+ middleware?: RouteMiddleware;
140
+ };
141
+ /**
142
+ * Valibot route builder created by [`createValibotRouteBuilder`]{@link createValibotRouteBuilder}.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * const route = createValibotRouteBuilder()
147
+ *
148
+ * router.get('/users/:id', route({
149
+ * schema: {
150
+ * request: {
151
+ * path: v.object({id: v.string()}),
152
+ * },
153
+ * },
154
+ * handler: ({path}) => ({id: path.id}),
155
+ * }))
156
+ *
157
+ * router.add(route({
158
+ * method: HttpMethod.GET,
159
+ * path: '/health',
160
+ * handler: () => ({ok: true}),
161
+ * }))
162
+ * ```
163
+ */
164
+ type ValibotRouteBuilder<BuilderCtx extends object = object, BuilderMiddleware extends MiddlewareInput<BuilderCtx> = undefined> = {
165
+ /**
166
+ * Build a full route definition that includes its own path.
167
+ *
168
+ * @param options - Full route options including `path`.
169
+ * @returns A full route definition compatible with [`Router.add`]{@link Router#add}.
170
+ */
171
+ <Schema extends AnyValibotRouteSchemaInput | undefined, RouteMiddleware extends MiddlewareInput<BuilderCtx> = undefined>(options: ValibotRouteOptions<Schema, BuilderCtx, BuilderMiddleware, RouteMiddleware>): Route<BuilderCtx, ValibotBuilderMiddlewareInput<BuilderCtx, BuilderMiddleware, RouteMiddleware>, ValibotRouteContext<BuilderCtx, BuilderMiddleware, RouteMiddleware>>;
172
+ /**
173
+ * Build method-specific route options that leave the path to the registering router.
174
+ *
175
+ * @param options - Method route options without a route path.
176
+ * @returns Route options compatible with helpers like [`Router.get`]{@link Router#get}.
177
+ */
178
+ <Schema extends AnyValibotRouteSchemaInput | undefined, RouteMiddleware extends MiddlewareInput<BuilderCtx> = undefined>(options: WithValibotOptions<Schema, BuilderCtx, BuilderMiddleware, RouteMiddleware>): RouteOptions<BuilderCtx, ValibotBuilderMiddlewareInput<BuilderCtx, BuilderMiddleware, RouteMiddleware>, ValibotRouteContext<BuilderCtx, BuilderMiddleware, RouteMiddleware>>;
179
+ };
180
+ /**
181
+ * Options for [`defineValibotMiddleware`]{@link defineValibotMiddleware}.
182
+ *
183
+ * @typeParam AddedCtx - Context made available to downstream handlers.
184
+ * @typeParam Ctx - Context required by the middleware.
185
+ * @typeParam Responses - Status-keyed Valibot schemas for locally originated responses.
186
+ */
187
+ type DefineValibotMiddlewareOptions<AddedCtx extends object, Ctx extends object, Responses extends AnyValibotResponseBodySchemas> = {
188
+ /**
189
+ * Responses that this middleware may originate.
190
+ */
191
+ responses: Responses;
192
+ /**
193
+ * Execute middleware behavior using typed `respond(...)` and `forward(...)` controls.
194
+ */
195
+ run: DefineMiddlewareOptions<AddedCtx, Ctx, ValibotMiddlewareDeclarations<Responses>>['run'];
196
+ };
197
+ /**
198
+ * Create response-declaring middleware backed by Valibot response schemas.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * const requireAuth = defineValibotMiddleware({
203
+ * responses: { 401: v.object({ message: v.string() }) },
204
+ * run: (_ctx, { respond }) => respond(response({ message: 'Sign in' }, { status: 401 })),
205
+ * })
206
+ * ```
207
+ *
208
+ * @param options - Locally originated response schemas and middleware implementation.
209
+ * @returns Declared middleware with inferred, runtime-validated terminal responses.
210
+ * @typeParam AddedCtx - Context made available to downstream handlers.
211
+ * @typeParam Ctx - Context required by the middleware.
212
+ * @typeParam Responses - Status-keyed Valibot schemas for locally originated responses.
213
+ */
214
+ declare function defineValibotMiddleware<AddedCtx extends object = {}, Ctx extends object = object, const Responses extends AnyValibotResponseBodySchemas = {}>(options: DefineValibotMiddlewareOptions<AddedCtx, Ctx, Responses>): DeclaredMiddleware<AddedCtx, Ctx>;
215
+ /**
216
+ * Options for [`valibotSchemaMiddleware`]{@link valibotSchemaMiddleware}.
217
+ *
218
+ * @typeParam Schema - Valibot request and downstream response schema declaration.
219
+ */
220
+ type ValibotSchemaMiddlewareBaseOptions<Schema extends AnyValibotRouteSchemaInput | undefined> = {
221
+ schema?: Schema;
222
+ validateResponse?: ResponseValidationOption;
223
+ };
224
+ /**
225
+ * Options for a Valibot request/response schema boundary.
226
+ *
227
+ * A custom request-validation callback must declare the response schemas it can originate.
228
+ *
229
+ * @typeParam Schema - Valibot request and downstream response schema declaration.
230
+ * @typeParam ValidationResponses - Schemas owned by a custom validation-error callback.
231
+ */
232
+ type ValibotSchemaMiddlewareOptions<Schema extends AnyValibotRouteSchemaInput | undefined, ValidationResponses extends AnyValibotResponseBodySchemas | undefined = undefined> = ValibotSchemaMiddlewareBaseOptions<Schema> & ([ValidationResponses] extends [undefined] ? {
233
+ onRequestValidationError?: undefined;
234
+ validationResponses?: undefined;
235
+ } : {
236
+ onRequestValidationError: ValibotValidationErrorHandler<Extract<ValidationResponses, AnyValibotResponseBodySchemas>>;
237
+ validationResponses: ValidationResponses;
238
+ });
239
+ /**
240
+ * Create Valibot middleware that parses request inputs and validates downstream responses.
241
+ *
242
+ * @example
243
+ * ```ts
244
+ * const parseUserId = valibotSchemaMiddleware({
245
+ * schema: { request: { path: v.object({ id: v.string() }) } },
246
+ * })
247
+ * ```
248
+ *
249
+ * @param options - Request, response, and validation-error schema behavior.
250
+ * @returns Declared middleware exposing parsed request values to downstream handlers.
251
+ * @typeParam Schema - Valibot request and downstream response schema declaration.
252
+ * @typeParam Ctx - Context required before this middleware executes.
253
+ */
254
+ declare function valibotSchemaMiddleware<Schema extends AnyValibotRouteSchemaInput | undefined, const ValidationResponses extends AnyValibotResponseBodySchemas | undefined = undefined, Ctx extends object = object>(options: ValibotSchemaMiddlewareOptions<Schema, ValidationResponses>): DeclaredMiddleware<ValibotSchemaMiddlewareContext<Schema>, Ctx>;
255
+ /**
256
+ * Create a Valibot route builder with shared defaults.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * const route = createValibotRouteBuilder({
261
+ * validateResponse: false,
262
+ * schema: {
263
+ * response: {
264
+ * body: {
265
+ * 400: v.object({message: v.string()}),
266
+ * },
267
+ * },
268
+ * },
269
+ * })
270
+ *
271
+ * router.post('/users/:id', route({
272
+ * name: 'user.update',
273
+ * schema: {
274
+ * request: {
275
+ * path: v.object({id: v.string()}),
276
+ * },
277
+ * },
278
+ * handler: ({path}) => ({id: path.id}),
279
+ * }))
280
+ * ```
281
+ *
282
+ * @param defaults - Default schema fragments, response validation, and request validation error handling.
283
+ * @returns A route builder compatible with method-specific router helpers and full route definitions.
284
+ */
285
+ declare function createValibotRouteBuilder<BuilderMiddleware extends MiddlewareInput<any>, BuilderCtx extends object = ContextFromMiddlewareInput<BuilderMiddleware>>(defaults: ValibotRouteHelperDefaults<BuilderCtx, BuilderMiddleware> & {
286
+ middleware: BuilderMiddleware;
287
+ }): ValibotRouteBuilder<BuilderCtx, BuilderMiddleware>;
288
+ declare function createValibotRouteBuilder<BuilderCtx extends object = object, BuilderMiddleware extends MiddlewareInput<BuilderCtx> = undefined>(defaults?: ValibotRouteHelperDefaults<BuilderCtx, BuilderMiddleware>): ValibotRouteBuilder<BuilderCtx, BuilderMiddleware>;
289
+ //#endregion
290
+ export { ValibotRouteHandler as a, ValibotSchemaMiddlewareOptions as c, ValibotValidationErrorHandler as d, createValibotRouteBuilder as f, ValibotRouteBuilder as i, ValibotValidationError as l, valibotSchemaMiddleware as m, ValibotHandlerContext as n, ValibotRouteHelperDefaults as o, defineValibotMiddleware as p, ValibotHandlerParams as r, ValibotRouteSchemaInput as s, DefineValibotMiddlewareOptions as t, ValibotValidationErrorBody as u };
@@ -0,0 +1,326 @@
1
+ import { M as isJsonContentType, f as defineMiddleware, t as RequestBodyError } from "./request-Dn0zc-xm.mjs";
2
+ import { a as response, i as isRoutekitResponse, r as isRoutekitBody } from "./core-DbmQauwS.mjs";
3
+ import { HttpStatus } from "@mpen/http";
4
+ import * as v from "valibot";
5
+ import { toJsonSchema } from "@valibot/to-json-schema";
6
+ //#region src/router/routes/valibot/valibot.ts
7
+ /**
8
+ * Validation error component identifiers for Valibot-backed routes.
9
+ */
10
+ let ValibotValidationError = /* @__PURE__ */ function(ValibotValidationError) {
11
+ ValibotValidationError[ValibotValidationError["REQUEST_BODY"] = 0] = "REQUEST_BODY";
12
+ ValibotValidationError[ValibotValidationError["URL_PATH"] = 1] = "URL_PATH";
13
+ ValibotValidationError[ValibotValidationError["QUERY_PARAMETERS"] = 2] = "QUERY_PARAMETERS";
14
+ return ValibotValidationError;
15
+ }({});
16
+ const validationErrorComponentName = new Map([
17
+ [0, "request_body"],
18
+ [1, "url_path"],
19
+ [2, "query_parameters"]
20
+ ]);
21
+ const jsonSchemaApproximationConfig = {
22
+ target: "draft-07",
23
+ errorMode: "ignore"
24
+ };
25
+ var ValibotResponseValidationError = class extends Error {
26
+ status;
27
+ issues;
28
+ constructor(status, issues) {
29
+ super(`Response validation failed for status ${status}: ${v.summarize(issues)}`);
30
+ this.name = "ValibotResponseValidationError";
31
+ this.status = status;
32
+ this.issues = issues;
33
+ }
34
+ };
35
+ function createValidationResponse(component, issues) {
36
+ return response({
37
+ component: validationErrorComponentName.get(component) ?? "request_body",
38
+ issues,
39
+ message: v.summarize(issues)
40
+ }, { status: HttpStatus.BAD_REQUEST });
41
+ }
42
+ function normalizeResponseValidationMode(option) {
43
+ if (option === true) return "strict";
44
+ return option;
45
+ }
46
+ function readQueryParams(searchParams) {
47
+ const query = {};
48
+ for (const [key, value] of searchParams.entries()) {
49
+ const existing = query[key];
50
+ if (existing === void 0) {
51
+ query[key] = value;
52
+ continue;
53
+ }
54
+ if (Array.isArray(existing)) existing.push(value);
55
+ else query[key] = [existing, value];
56
+ }
57
+ return query;
58
+ }
59
+ function valibotIssuesFromThrowable(error) {
60
+ return [{
61
+ kind: "schema",
62
+ type: "custom",
63
+ input: void 0,
64
+ expected: null,
65
+ received: "unknown",
66
+ message: error instanceof Error ? error.message : String(error)
67
+ }];
68
+ }
69
+ function sanitizeJsonSchema(schema) {
70
+ if (Array.isArray(schema)) return schema.map((entry) => sanitizeJsonSchema(entry));
71
+ if (!schema || typeof schema !== "object") return schema;
72
+ const sanitizedEntries = Object.entries(schema).filter(([key]) => key !== "$schema" && key !== "~standard").map(([key, value]) => [key, sanitizeJsonSchema(value)]);
73
+ return Object.fromEntries(sanitizedEntries);
74
+ }
75
+ function toRequestJsonSchema(schema) {
76
+ return sanitizeJsonSchema(toJsonSchema(schema, {
77
+ ...jsonSchemaApproximationConfig,
78
+ typeMode: "input"
79
+ }));
80
+ }
81
+ function toResponseJsonSchema(schema) {
82
+ return sanitizeJsonSchema(toJsonSchema(schema, {
83
+ ...jsonSchemaApproximationConfig,
84
+ typeMode: "output"
85
+ }));
86
+ }
87
+ function buildRouteSchema(schema) {
88
+ if (!schema) return void 0;
89
+ const request = schema.request ? {
90
+ ...schema.request.query ? { query: toRequestJsonSchema(schema.request.query) } : {},
91
+ ...schema.request.path ? { path: toRequestJsonSchema(schema.request.path) } : {},
92
+ ...schema.request.body ? { body: toRequestJsonSchema(schema.request.body) } : {}
93
+ } : void 0;
94
+ const responseBody = schema.response?.body ? Object.fromEntries(Object.entries(schema.response.body).map(([status, responseSchema]) => {
95
+ return [status === "default" ? status : Number(status), toResponseJsonSchema(responseSchema)];
96
+ })) : void 0;
97
+ const response = responseBody && Object.keys(responseBody).length > 0 ? { body: responseBody } : void 0;
98
+ if ((!request || Object.keys(request).length === 0) && !response) return;
99
+ return {
100
+ ...request && Object.keys(request).length > 0 ? { request } : {},
101
+ ...response ? { response } : {}
102
+ };
103
+ }
104
+ function buildValibotMiddlewareDeclarations(schemas) {
105
+ return Object.fromEntries(Object.entries(schemas).flatMap(([status, schema]) => schema ? [[status, {
106
+ schema: toResponseJsonSchema(schema),
107
+ parse: (value) => v.parse(schema, value)
108
+ }]] : []));
109
+ }
110
+ function defineValibotMiddleware(options) {
111
+ return defineMiddleware({
112
+ responses: buildValibotMiddlewareDeclarations(options.responses),
113
+ run: options.run
114
+ });
115
+ }
116
+ function mergeRouteSchema(defaults, schema) {
117
+ const defaultSchema = defaults.schema;
118
+ if (!defaultSchema) return schema;
119
+ if (!schema) return defaultSchema;
120
+ const request = !defaultSchema.request && !schema.request ? void 0 : {
121
+ ...defaultSchema.request,
122
+ ...schema.request
123
+ };
124
+ const defaultBody = defaultSchema.response?.body ?? {};
125
+ const routeBody = schema.response?.body ?? {};
126
+ const responseBody = {};
127
+ const statuses = new Set([...Object.keys(defaultBody), ...Object.keys(routeBody)]);
128
+ for (const status of statuses) {
129
+ const s = status === "default" ? status : Number(status);
130
+ const defaultStatusSchema = defaultBody[s];
131
+ const routeStatusSchema = routeBody[s];
132
+ if (defaultStatusSchema && routeStatusSchema) responseBody[s] = v.union([defaultStatusSchema, routeStatusSchema]);
133
+ else if (defaultStatusSchema) responseBody[s] = defaultStatusSchema;
134
+ else if (routeStatusSchema) responseBody[s] = routeStatusSchema;
135
+ }
136
+ const response = Object.keys(responseBody).length > 0 ? { body: responseBody } : void 0;
137
+ return {
138
+ ...request ? { request } : {},
139
+ ...response ? { response } : {}
140
+ };
141
+ }
142
+ function normalizeMiddlewareInput(middleware) {
143
+ if (!middleware) return [];
144
+ if (Array.isArray(middleware)) return middleware.filter(Boolean);
145
+ return [middleware];
146
+ }
147
+ function mergeMiddleware(defaultMiddleware, routeMiddleware) {
148
+ const list = [...normalizeMiddlewareInput(defaultMiddleware), ...normalizeMiddlewareInput(routeMiddleware)];
149
+ return list.length ? list : void 0;
150
+ }
151
+ function mergeValibotOptions(defaults, options) {
152
+ const { middleware: defaultMiddleware, ...defaultOptions } = defaults;
153
+ const schema = mergeRouteSchema(defaults, options.schema);
154
+ const middleware = mergeMiddleware(defaultMiddleware, options.middleware);
155
+ return {
156
+ ...defaultOptions,
157
+ ...options,
158
+ ...schema === void 0 ? {} : { schema },
159
+ ...middleware === void 0 ? {} : { middleware }
160
+ };
161
+ }
162
+ function hasRoutePath(options) {
163
+ return options.path !== void 0;
164
+ }
165
+ function isSkippableResponseValidationValue(value) {
166
+ return value instanceof ReadableStream || value instanceof Uint8Array || typeof Buffer !== "undefined" && value instanceof Buffer || !!value && typeof value === "object" && Symbol.asyncIterator in value;
167
+ }
168
+ function jsonValuesEqual(left, right) {
169
+ if (Object.is(left, right)) return true;
170
+ if (typeof left !== typeof right) return false;
171
+ if (!left || !right || typeof left !== "object") return false;
172
+ if (Array.isArray(left) || Array.isArray(right)) return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => jsonValuesEqual(value, right[index]));
173
+ const leftEntries = Object.entries(left);
174
+ const rightRecord = right;
175
+ const rightKeys = new Set(Object.keys(rightRecord));
176
+ return leftEntries.length === rightKeys.size && leftEntries.every(([key, value]) => rightKeys.has(key) && jsonValuesEqual(value, rightRecord[key]));
177
+ }
178
+ function getResponseSchemaForStatus(schema, status) {
179
+ return schema?.response?.body?.[status] ?? schema?.response?.body?.default;
180
+ }
181
+ async function readResponseBodyForValidation(response) {
182
+ if (!response.body) return void 0;
183
+ const contentType = response.headers.get("content-type") ?? "";
184
+ const clone = response.clone();
185
+ if (isJsonContentType(contentType)) return {
186
+ value: await clone.json(),
187
+ writableJson: true
188
+ };
189
+ return {
190
+ value: await clone.text(),
191
+ writableJson: false
192
+ };
193
+ }
194
+ function responseWithJsonBody(response, value) {
195
+ const headers = new Headers(response.headers);
196
+ headers.delete("content-length");
197
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
198
+ return new Response(value === void 0 ? void 0 : JSON.stringify(value), {
199
+ status: response.status,
200
+ statusText: response.statusText,
201
+ headers
202
+ });
203
+ }
204
+ function parseResponseSchema(schema, status, value, mode) {
205
+ const responseSchema = getResponseSchemaForStatus(schema, status);
206
+ if (!responseSchema) return value;
207
+ const result = v.safeParse(responseSchema, value);
208
+ if (!result.success) throw new ValibotResponseValidationError(status, result.issues);
209
+ if (mode === "strict" && !jsonValuesEqual(value, result.output)) throw new ValibotResponseValidationError(status, valibotIssuesFromThrowable(/* @__PURE__ */ new Error("Response body does not match the parsed schema output.")));
210
+ return mode === "parse" ? result.output : value;
211
+ }
212
+ async function validateHandlerResult(schema, result, mode) {
213
+ if (result instanceof Response) {
214
+ const body = await readResponseBodyForValidation(result);
215
+ if (!body) return result;
216
+ const parsed = parseResponseSchema(schema, result.status, body.value, mode);
217
+ return mode === "parse" && body.writableJson ? responseWithJsonBody(result, parsed) : result;
218
+ }
219
+ if (isRoutekitResponse(result)) {
220
+ const parsed = parseResponseSchema(schema, result.status, result.body, mode);
221
+ return mode === "parse" ? response(parsed, {
222
+ status: result.status,
223
+ headers: result.headers
224
+ }) : result;
225
+ }
226
+ if (isRoutekitBody(result)) {
227
+ const parsed = parseResponseSchema(schema, HttpStatus.OK, result.value, mode);
228
+ return mode === "parse" ? parsed : result;
229
+ }
230
+ if (isSkippableResponseValidationValue(result)) return result;
231
+ return parseResponseSchema(schema, HttpStatus.OK, result, mode);
232
+ }
233
+ const defaultValidationErrorSchema = v.object({
234
+ component: v.picklist([
235
+ "request_body",
236
+ "url_path",
237
+ "query_parameters"
238
+ ]),
239
+ issues: v.array(v.unknown()),
240
+ message: v.string()
241
+ });
242
+ /**
243
+ * Create Valibot middleware that parses request inputs and validates downstream responses.
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * const parseUserId = valibotSchemaMiddleware({
248
+ * schema: { request: { path: v.object({ id: v.string() }) } },
249
+ * })
250
+ * ```
251
+ *
252
+ * @param options - Request, response, and validation-error schema behavior.
253
+ * @returns Declared middleware exposing parsed request values to downstream handlers.
254
+ * @typeParam Schema - Valibot request and downstream response schema declaration.
255
+ * @typeParam Ctx - Context required before this middleware executes.
256
+ */
257
+ function valibotSchemaMiddleware(options) {
258
+ const validateResponse = normalizeResponseValidationMode(options.validateResponse) ?? "parse";
259
+ const parsesRequest = options.schema?.request !== void 0;
260
+ const declarations = buildValibotMiddlewareDeclarations(options.validationResponses ?? (parsesRequest ? { [HttpStatus.BAD_REQUEST]: defaultValidationErrorSchema } : {}));
261
+ const onRequestValidationError = options.onRequestValidationError ?? createValidationResponse;
262
+ return defineMiddleware({
263
+ schema: buildRouteSchema(options.schema),
264
+ responses: declarations,
265
+ async run(ctx, { next, forward, respond }) {
266
+ const bodySchema = options.schema?.request?.body;
267
+ const pathSchema = options.schema?.request?.path;
268
+ const querySchema = options.schema?.request?.query;
269
+ const queryParams = readQueryParams(ctx.url.searchParams);
270
+ const handlerParams = {
271
+ path: ctx.path,
272
+ query: void 0,
273
+ body: void 0
274
+ };
275
+ const handlerContext = ctx;
276
+ handlerContext.params = handlerParams;
277
+ if (querySchema) {
278
+ const parsed = v.safeParse(querySchema, queryParams);
279
+ if (!parsed.success) return respond(onRequestValidationError(2, parsed.issues));
280
+ handlerParams.query = parsed.output;
281
+ handlerContext.query = handlerParams.query;
282
+ }
283
+ if (pathSchema) {
284
+ const parsed = v.safeParse(pathSchema, ctx.path);
285
+ if (!parsed.success) return respond(onRequestValidationError(1, parsed.issues));
286
+ handlerParams.path = parsed.output;
287
+ handlerContext.path = handlerParams.path;
288
+ }
289
+ if (bodySchema) {
290
+ let rawBody;
291
+ try {
292
+ rawBody = await ctx.request.body.parse();
293
+ } catch (err) {
294
+ if (err instanceof RequestBodyError) throw err;
295
+ return respond(onRequestValidationError(0, valibotIssuesFromThrowable(err)));
296
+ }
297
+ const parsed = v.safeParse(bodySchema, rawBody);
298
+ if (!parsed.success) return respond(onRequestValidationError(0, parsed.issues));
299
+ handlerParams.body = parsed.output;
300
+ handlerContext.body = handlerParams.body;
301
+ }
302
+ const result = await next();
303
+ return forward(validateResponse === false ? result : await validateHandlerResult(options.schema, result, validateResponse));
304
+ }
305
+ });
306
+ }
307
+ function createValibotRouteBuilder(defaults = {}) {
308
+ return ((options) => {
309
+ const { schema, handler, onRequestValidationError, validateResponse, validationResponses, middleware, ...routeOptions } = mergeValibotOptions(defaults, options);
310
+ const routeMiddleware = mergeMiddleware(middleware, valibotSchemaMiddleware({
311
+ ...schema ? { schema } : {},
312
+ ...onRequestValidationError ? { onRequestValidationError } : {},
313
+ ...validateResponse === void 0 ? {} : { validateResponse },
314
+ ...validationResponses === void 0 ? {} : { validationResponses }
315
+ }));
316
+ const built = {
317
+ ...routeOptions,
318
+ handler,
319
+ middleware: routeMiddleware
320
+ };
321
+ if (hasRoutePath(built)) return built;
322
+ return built;
323
+ });
324
+ }
325
+ //#endregion
326
+ export { valibotSchemaMiddleware as i, createValibotRouteBuilder as n, defineValibotMiddleware as r, ValibotValidationError as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpen/routekit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Typed server-side routing utilities for Fetch-compatible runtimes.",
5
5
  "exports": {
6
6
  ".": "./dist/index.mjs",
@@ -21,7 +21,8 @@
21
21
  "routekit": "./dist/bin.mjs"
22
22
  },
23
23
  "files": [
24
- "src"
24
+ "dist",
25
+ "README.md"
25
26
  ],
26
27
  "module": "./dist/index.mjs",
27
28
  "type": "module",
@@ -91,5 +92,10 @@
91
92
  "types": "./dist/index.d.mts",
92
93
  "publishConfig": {
93
94
  "access": "public"
95
+ },
96
+ "publishHash": {
97
+ "buildDate": "2026-05-30T17:02:21.521-07:00",
98
+ "hgChangesetId": "60958a12c122+",
99
+ "sha256": "99d67ed8a13ebfe8f5edc5bb1f4d551d85fdbc287d311fffe8cdc860234ed9c6"
94
100
  }
95
101
  }