@rexeus/typeweaver-server 0.5.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.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * This file was automatically generated by typeweaver.
3
+ * DO NOT EDIT. Instead, modify the source definition file and generate again.
4
+ *
5
+ * @generated by @rexeus/typeweaver
6
+ */
7
+
8
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
9
+
10
+ import type { IHttpResponse } from "@rexeus/typeweaver-core";
11
+ import type { Middleware } from "./Middleware";
12
+ import type { ServerContext } from "./ServerContext";
13
+ import type { TypeweaverApp } from "./TypeweaverApp";
14
+
15
+ /**
16
+ * A middleware descriptor carrying compile-time metadata about what state
17
+ * it provides to downstream consumers and what state it requires from
18
+ * upstream middleware.
19
+ *
20
+ * Created via {@link defineMiddleware}. The `_brand` property exists purely
21
+ * at the type level for TypeScript's inference — its runtime value is an empty object.
22
+ *
23
+ * @template TProvides - State keys this middleware adds to the context
24
+ * @template TRequires - State keys this middleware expects to already exist
25
+ */
26
+ export type TypedMiddleware<
27
+ TProvides extends Record<string, unknown> = {},
28
+ TRequires extends Record<string, unknown> = {},
29
+ > = {
30
+ readonly handler: Middleware;
31
+ readonly _brand: {
32
+ readonly provides: TProvides;
33
+ readonly requires: TRequires;
34
+ };
35
+ };
36
+
37
+ /**
38
+ * Compile-time error type produced when a typed middleware's requirements
39
+ * are not satisfied by the current accumulated app state.
40
+ *
41
+ * When intersected with `TypedMiddleware`, produces an uninhabitable type —
42
+ * no value can satisfy both, causing a clear compiler error at the call site.
43
+ *
44
+ * The error type's properties (`required`, `available`, `missing`) appear
45
+ * in the compiler diagnostic, helping developers identify what's wrong.
46
+ */
47
+ export type StateRequirementError<
48
+ TRequired extends Record<string, unknown>,
49
+ TAvailable extends Record<string, unknown>,
50
+ > = {
51
+ readonly __error: "STATE_REQUIREMENT_NOT_MET";
52
+ readonly required: TRequired;
53
+ readonly available: TAvailable;
54
+ readonly missing: Exclude<keyof TRequired, keyof TAvailable>;
55
+ };
56
+
57
+ /**
58
+ * The type of the `next` function inside a typed middleware handler.
59
+ *
60
+ * When `TProvides` has keys, `next` requires the state object as its argument,
61
+ * enforcing at compile time that middleware provides the state it declares.
62
+ *
63
+ * When `TProvides` is empty (`{}`), `next` takes no arguments — the middleware
64
+ * is pass-through and doesn't need to provide any state.
65
+ *
66
+ * @template TProvides - The state keys this middleware declares it provides
67
+ */
68
+ export type NextFn<TProvides extends Record<string, unknown>> = [
69
+ keyof TProvides,
70
+ ] extends [never]
71
+ ? () => Promise<IHttpResponse>
72
+ : (state: TProvides) => Promise<IHttpResponse>;
73
+
74
+ /**
75
+ * Creates a typed middleware descriptor.
76
+ *
77
+ * The handler receives a `ServerContext` parameterized with the required
78
+ * upstream state, and a `next` function that enforces providing the declared
79
+ * state. When the middleware declares `TProvides`, the state must be passed
80
+ * to `next()` — the pipeline merges it into `ctx.state` before continuing.
81
+ *
82
+ * @template TProvides - State keys this middleware adds
83
+ * @template TRequires - State keys this middleware expects (defaults to none)
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * // Middleware that provides state — MUST pass it to next()
88
+ * const auth = defineMiddleware<{ userId: string }>(async (ctx, next) => {
89
+ * return next({ userId: parseToken(ctx.request.header?.["authorization"]) });
90
+ * });
91
+ *
92
+ * // Middleware with requirements — reads upstream state, provides new state
93
+ * const permissions = defineMiddleware<{ permissions: string[] }, { userId: string }>(
94
+ * async (ctx, next) => {
95
+ * const userId = ctx.state.get("userId"); // string (no undefined!)
96
+ * return next({ permissions: await loadPermissions(userId) });
97
+ * }
98
+ * );
99
+ *
100
+ * // Pass-through middleware — next() takes no args
101
+ * const logger = defineMiddleware(async (ctx, next) => {
102
+ * console.log(ctx.request.path);
103
+ * return next();
104
+ * });
105
+ * ```
106
+ */
107
+ export function defineMiddleware<
108
+ TProvides extends Record<string, unknown> = {},
109
+ TRequires extends Record<string, unknown> = {},
110
+ >(
111
+ handler: (
112
+ ctx: ServerContext<TRequires>,
113
+ next: NextFn<TProvides>
114
+ ) => Promise<IHttpResponse>
115
+ ): TypedMiddleware<TProvides, TRequires> {
116
+ return {
117
+ handler: handler as Middleware,
118
+ _brand: {} as TypedMiddleware<TProvides, TRequires>["_brand"],
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Extracts the accumulated state type from a `TypeweaverApp` instance.
124
+ *
125
+ * Use this to derive the state type for handler implementations
126
+ * without declaring it separately.
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const app = new TypeweaverApp()
131
+ * .use(authMiddleware)
132
+ * .use(permissionsMiddleware);
133
+ *
134
+ * type AppState = InferState<typeof app>;
135
+ * // { userId: string } & { permissions: string[] }
136
+ *
137
+ * const handlers: TodoApiHandler<AppState> = { ... };
138
+ * ```
139
+ */
140
+ export type InferState<T> = T extends TypeweaverApp<infer S> ? S : never;
@@ -0,0 +1,376 @@
1
+ /**
2
+ * This file was automatically generated by typeweaver.
3
+ * DO NOT EDIT. Instead, modify the source definition file and generate again.
4
+ *
5
+ * @generated by @rexeus/typeweaver
6
+ */
7
+
8
+ import { HttpResponse, RequestValidationError } from "@rexeus/typeweaver-core";
9
+ import type { IHttpResponse } from "@rexeus/typeweaver-core";
10
+ import { BodyParseError, PayloadTooLargeError } from "./Errors";
11
+ import { FetchApiAdapter } from "./FetchApiAdapter";
12
+ import { executeMiddlewarePipeline } from "./Middleware";
13
+ import { Router } from "./Router";
14
+ import { StateMap } from "./StateMap";
15
+ import type { Middleware } from "./Middleware";
16
+ import type { RequestHandler } from "./RequestHandler";
17
+ import type {
18
+ HttpResponseErrorHandler,
19
+ RouteDefinition,
20
+ UnknownErrorHandler,
21
+ ValidationErrorHandler,
22
+ } from "./Router";
23
+ import type { ServerContext } from "./ServerContext";
24
+ import type { StateRequirementError, TypedMiddleware } from "./TypedMiddleware";
25
+ import type { TypeweaverRouter } from "./TypeweaverRouter";
26
+
27
+ /**
28
+ * The main application class that provides routing, middleware, and
29
+ * request handling — all using typeweaver's native `IHttpRequest`/`IHttpResponse` format.
30
+ *
31
+ * Exposes a single `fetch()` method compatible with Bun, Deno, Cloudflare Workers,
32
+ * and adaptable to Node.js `http.createServer`.
33
+ *
34
+ * Internally, the entire pipeline operates on `IHttpRequest`/`IHttpResponse`.
35
+ * Conversion from/to Fetch API `Request`/`Response` happens **only** at the boundary.
36
+ *
37
+ * Middleware is return-based: each middleware returns an `IHttpResponse`
38
+ * instead of mutating shared state.
39
+ *
40
+ * Middleware runs for **all** requests, including 404s and 405s, so global
41
+ * concerns like logging and CORS always execute.
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const app = new TypeweaverApp()
46
+ * .use(authMiddleware) // defineMiddleware<{ userId: string }>
47
+ * .use(permissionsMiddleware) // defineMiddleware<{ perms: string[] }, { userId: string }>
48
+ * .route(new TodoRouter({ requestHandlers: { ... } }));
49
+ *
50
+ * Bun.serve({ fetch: app.fetch, port: 3000 });
51
+ * ```
52
+ */
53
+ export type TypeweaverAppOptions = {
54
+ readonly maxBodySize?: number;
55
+ readonly onError?: (error: unknown) => void;
56
+ };
57
+
58
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
59
+ export class TypeweaverApp<TState extends Record<string, unknown> = {}> {
60
+ private static readonly INTERNAL_SERVER_ERROR_BODY = {
61
+ code: "INTERNAL_SERVER_ERROR",
62
+ message: "An unexpected error occurred",
63
+ } as const;
64
+
65
+ private readonly router = new Router();
66
+ private readonly middlewares: Middleware[] = [];
67
+ private readonly adapter: FetchApiAdapter;
68
+ private readonly onError: (error: unknown) => void;
69
+
70
+ public constructor(options?: TypeweaverAppOptions) {
71
+ this.adapter = new FetchApiAdapter({ maxBodySize: options?.maxBodySize });
72
+ this.onError = options?.onError ?? console.error;
73
+ }
74
+
75
+ private safeOnError(error: unknown): void {
76
+ try {
77
+ this.onError(error);
78
+ } catch (onErrorFailure) {
79
+ console.error(
80
+ "TypeweaverApp: onError callback threw while handling error",
81
+ { onErrorFailure, originalError: error }
82
+ );
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Register a typed middleware that provides state to downstream handlers.
88
+ *
89
+ * Returns a new `TypeweaverApp` type with the accumulated state.
90
+ * Produces a compile-time error if the middleware's requirements are not met
91
+ * by the currently accumulated state.
92
+ *
93
+ * Use {@link defineMiddleware} to create typed middleware.
94
+ */
95
+ public use<
96
+ TProv extends Record<string, unknown>,
97
+ TReq extends Record<string, unknown>,
98
+ >(
99
+ middleware: TypedMiddleware<TProv, TReq> &
100
+ ([TState] extends [TReq] ? unknown : StateRequirementError<TReq, TState>)
101
+ ): TypeweaverApp<TState & TProv> {
102
+ this.middlewares.push(middleware.handler);
103
+ return this as unknown as TypeweaverApp<TState & TProv>;
104
+ }
105
+
106
+ /**
107
+ * Mount a generated `TypeweaverRouter` instance.
108
+ *
109
+ * Registers all routes from the router into the app.
110
+ * Multiple routers can be mounted on the same app.
111
+ *
112
+ * Optionally accepts a prefix to prepend to all routes from the router.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * app.route(new AccountRouter({ requestHandlers: { ... } }));
117
+ * app.route("/api/v1", new TodoRouter({ requestHandlers: { ... } }));
118
+ * ```
119
+ */
120
+ public route(router: TypeweaverRouter<Record<string, RequestHandler>>): this;
121
+ public route(
122
+ prefix: string,
123
+ router: TypeweaverRouter<Record<string, RequestHandler>>
124
+ ): this;
125
+ public route(
126
+ prefixOrRouter: string | TypeweaverRouter<Record<string, RequestHandler>>,
127
+ router?: TypeweaverRouter<Record<string, RequestHandler>>
128
+ ): this {
129
+ if (typeof prefixOrRouter === "string") {
130
+ if (!router) {
131
+ throw new Error("Router is required when mounting with a prefix");
132
+ }
133
+ return this.mountRouter(router, prefixOrRouter);
134
+ }
135
+ return this.mountRouter(prefixOrRouter);
136
+ }
137
+
138
+ /**
139
+ * Universal request handler compatible with Fetch API runtimes.
140
+ *
141
+ * The entire pipeline works with `IHttpRequest`/`IHttpResponse`.
142
+ * Conversion from/to Fetch API `Request`/`Response` happens only here, at the boundary.
143
+ *
144
+ * Middleware runs for all requests (including 404s and 405s).
145
+ * HEAD requests automatically fall back to GET handlers with body stripped from the response.
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * // Bun
150
+ * Bun.serve({ fetch: app.fetch, port: 3000 });
151
+ *
152
+ * // Deno
153
+ * Deno.serve({ port: 3000 }, app.fetch);
154
+ * ```
155
+ */
156
+ public fetch = async (request: Request): Promise<Response> => {
157
+ try {
158
+ const response = await this.processRequest(request);
159
+ return this.adapter.toResponse(response);
160
+ } catch (error) {
161
+ if (error instanceof PayloadTooLargeError) {
162
+ this.safeOnError(error);
163
+ return this.adapter.toResponse({
164
+ statusCode: 413,
165
+ body: {
166
+ code: "PAYLOAD_TOO_LARGE",
167
+ message: "Request body exceeds the size limit",
168
+ },
169
+ });
170
+ }
171
+ if (error instanceof BodyParseError) {
172
+ return this.adapter.toResponse({
173
+ statusCode: 400,
174
+ body: { code: "BAD_REQUEST", message: "Malformed request body" },
175
+ });
176
+ }
177
+ this.safeOnError(error);
178
+ return TypeweaverApp.createErrorResponse();
179
+ }
180
+ };
181
+
182
+ private async processRequest(request: Request): Promise<IHttpResponse> {
183
+ const url = new URL(request.url);
184
+ const httpRequest = await this.adapter.toRequest(request, url);
185
+
186
+ const ctx: ServerContext = {
187
+ request: httpRequest,
188
+ state: new StateMap(),
189
+ };
190
+
191
+ const response = await executeMiddlewarePipeline(
192
+ this.middlewares,
193
+ ctx,
194
+ () => this.resolveAndExecute(request.method, url.pathname, ctx)
195
+ );
196
+
197
+ return request.method.toUpperCase() === "HEAD"
198
+ ? { ...response, body: undefined }
199
+ : response;
200
+ }
201
+
202
+ /**
203
+ * Match the route and execute the handler.
204
+ * Called as the final handler in the middleware pipeline.
205
+ */
206
+ private async resolveAndExecute(
207
+ method: string,
208
+ pathname: string,
209
+ ctx: ServerContext
210
+ ): Promise<IHttpResponse> {
211
+ const match = this.router.match(method, pathname);
212
+
213
+ if (match) {
214
+ const routeCtx = this.withPathParams(ctx, match.params);
215
+ try {
216
+ return await this.executeHandler(routeCtx, match.route);
217
+ } catch (error) {
218
+ return this.handleError(error, routeCtx, match.route);
219
+ }
220
+ }
221
+
222
+ const pathMatch = this.router.matchPath(pathname);
223
+ if (pathMatch) {
224
+ return {
225
+ statusCode: 405,
226
+ header: { Allow: pathMatch.allowedMethods.join(", ") },
227
+ body: {
228
+ code: "METHOD_NOT_ALLOWED",
229
+ message: "Method not supported for this resource",
230
+ },
231
+ };
232
+ }
233
+
234
+ return {
235
+ statusCode: 404,
236
+ body: { code: "NOT_FOUND", message: "No matching resource found" },
237
+ };
238
+ }
239
+
240
+ private withPathParams(
241
+ ctx: ServerContext,
242
+ params: Record<string, string>
243
+ ): ServerContext {
244
+ if (Object.keys(params).length === 0) return ctx;
245
+ return { ...ctx, request: { ...ctx.request, param: params } };
246
+ }
247
+
248
+ private async executeHandler(
249
+ ctx: ServerContext,
250
+ route: RouteDefinition
251
+ ): Promise<IHttpResponse> {
252
+ const validatedRequest = route.routerConfig.validateRequests
253
+ ? route.validator.validate(ctx.request)
254
+ : ctx.request;
255
+
256
+ return route.handler(validatedRequest, ctx);
257
+ }
258
+
259
+ /**
260
+ * Handle errors using the route's configured error handlers.
261
+ * Handler errors bubble up to the safety net in `fetch()`.
262
+ */
263
+ private handleError(
264
+ error: unknown,
265
+ ctx: ServerContext,
266
+ route: RouteDefinition
267
+ ): IHttpResponse | Promise<IHttpResponse> {
268
+ const config = route.routerConfig;
269
+
270
+ if (error instanceof RequestValidationError) {
271
+ const handler = this.resolveErrorHandler<ValidationErrorHandler>(
272
+ config.handleValidationErrors,
273
+ TypeweaverApp.defaultValidationHandler
274
+ );
275
+ if (handler) return handler(error, ctx);
276
+ }
277
+
278
+ if (error instanceof HttpResponse) {
279
+ const handler = this.resolveErrorHandler<HttpResponseErrorHandler>(
280
+ config.handleHttpResponseErrors,
281
+ TypeweaverApp.defaultHttpResponseHandler
282
+ );
283
+ if (handler) return handler(error, ctx);
284
+ }
285
+
286
+ const handler = this.resolveErrorHandler<UnknownErrorHandler>(
287
+ config.handleUnknownErrors,
288
+ this.defaultUnknownHandler
289
+ );
290
+ if (handler) return handler(error, ctx);
291
+
292
+ throw error;
293
+ }
294
+
295
+ /**
296
+ * Resolve an error handler option to a concrete handler function.
297
+ */
298
+ private resolveErrorHandler<T extends (...args: any[]) => any>(
299
+ option: T | boolean | undefined,
300
+ defaultHandler: T
301
+ ): T | undefined {
302
+ if (option === false) return undefined;
303
+ if (option === true || option === undefined) return defaultHandler;
304
+ return option;
305
+ }
306
+
307
+ private mountRouter(
308
+ router: TypeweaverRouter<Record<string, RequestHandler>>,
309
+ prefix?: string
310
+ ): this {
311
+ const normalizedPrefix = prefix?.replace(/\/+$/, "");
312
+ for (const route of router.getRoutes()) {
313
+ this.router.add({
314
+ ...route,
315
+ path: normalizedPrefix ? normalizedPrefix + route.path : route.path,
316
+ });
317
+ }
318
+ return this;
319
+ }
320
+
321
+ private static sanitizeIssues(
322
+ issues: readonly {
323
+ readonly message: string;
324
+ readonly path: PropertyKey[];
325
+ }[]
326
+ ): readonly { message: string; path: PropertyKey[] }[] | undefined {
327
+ if (issues.length === 0) return undefined;
328
+ return issues.map(({ message, path }) => ({ message, path }));
329
+ }
330
+
331
+ private static defaultValidationHandler: ValidationErrorHandler = (
332
+ err
333
+ ): IHttpResponse => {
334
+ const issues: Record<string, unknown> = Object.create(null);
335
+
336
+ const header = TypeweaverApp.sanitizeIssues(err.headerIssues);
337
+ const body = TypeweaverApp.sanitizeIssues(err.bodyIssues);
338
+ const query = TypeweaverApp.sanitizeIssues(err.queryIssues);
339
+ const param = TypeweaverApp.sanitizeIssues(err.pathParamIssues);
340
+
341
+ if (header) issues.header = header;
342
+ if (body) issues.body = body;
343
+ if (query) issues.query = query;
344
+ if (param) issues.param = param;
345
+
346
+ return {
347
+ statusCode: 400,
348
+ body: {
349
+ code: "VALIDATION_ERROR",
350
+ message: err.message,
351
+ issues,
352
+ },
353
+ };
354
+ };
355
+
356
+ private static defaultHttpResponseHandler: HttpResponseErrorHandler = (
357
+ err
358
+ ): IHttpResponse => err;
359
+
360
+ private readonly defaultUnknownHandler: UnknownErrorHandler = (
361
+ error
362
+ ): IHttpResponse => {
363
+ this.safeOnError(error);
364
+ return { statusCode: 500, body: TypeweaverApp.INTERNAL_SERVER_ERROR_BODY };
365
+ };
366
+
367
+ private static createErrorResponse(): Response {
368
+ return new Response(
369
+ JSON.stringify(TypeweaverApp.INTERNAL_SERVER_ERROR_BODY),
370
+ {
371
+ status: 500,
372
+ headers: { "content-type": "application/json" },
373
+ }
374
+ );
375
+ }
376
+ }
@@ -0,0 +1,138 @@
1
+ // NOTE: The @generated header below is for the copy that ships to user projects.
2
+ // This file IS the source of truth — edit it here.
3
+ /**
4
+ * This file was automatically generated by typeweaver.
5
+ * DO NOT EDIT. Instead, modify the source definition file and generate again.
6
+ *
7
+ * @generated by @rexeus/typeweaver
8
+ */
9
+
10
+ import type { HttpMethod, IRequestValidator } from "@rexeus/typeweaver-core";
11
+ import type { RequestHandler } from "./RequestHandler";
12
+ import type {
13
+ HttpResponseErrorHandler,
14
+ RouteDefinition,
15
+ RouterErrorConfig,
16
+ UnknownErrorHandler,
17
+ ValidationErrorHandler,
18
+ } from "./Router";
19
+
20
+ /**
21
+ * Configuration options for TypeweaverRouter instances.
22
+ *
23
+ * @template RequestHandlers - Object type containing all handler methods for this router
24
+ */
25
+ export type TypeweaverRouterOptions<
26
+ RequestHandlers extends Record<string, RequestHandler>,
27
+ > = {
28
+ /**
29
+ * Request handler methods for each operation.
30
+ * Each handler receives a validated request and the server context.
31
+ */
32
+ readonly requestHandlers: RequestHandlers;
33
+
34
+ /**
35
+ * Enable request validation using generated validators.
36
+ * When false, requests are passed through without validation.
37
+ * @default true
38
+ */
39
+ readonly validateRequests?: boolean;
40
+
41
+ /**
42
+ * Configure handling of HttpResponse errors thrown by handlers.
43
+ * - `true`: Use default handler (returns the error as response)
44
+ * - `false`: Disable this handler (errors fall through to the unknown error handler)
45
+ * - `function`: Use custom error handler
46
+ * @default true
47
+ */
48
+ readonly handleHttpResponseErrors?: HttpResponseErrorHandler | boolean;
49
+
50
+ /**
51
+ * Configure handling of request validation errors.
52
+ * - `true`: Use default handler (400 with error details)
53
+ * - `false`: Disable this handler (errors fall through to the unknown error handler)
54
+ * - `function`: Use custom error handler
55
+ * @default true
56
+ */
57
+ readonly handleValidationErrors?: ValidationErrorHandler | boolean;
58
+
59
+ /**
60
+ * Configure handling of unknown errors.
61
+ * - `true`: Use default handler (500 Internal Server Error)
62
+ * - `false`: Disable this handler (errors bubble up to the safety net)
63
+ * - `function`: Use custom error handler
64
+ * @default true
65
+ */
66
+ readonly handleUnknownErrors?: UnknownErrorHandler | boolean;
67
+ };
68
+
69
+ /**
70
+ * Abstract base class for typeweaver-generated routers.
71
+ *
72
+ * Each generated router (e.g., `AccountRouter`, `TodoRouter`) extends this class
73
+ * and registers its routes in the constructor via `this.route(...)`.
74
+ *
75
+ * The router does **not** handle HTTP directly — it collects route definitions
76
+ * that are mounted onto a `TypeweaverApp` via `app.route(...)`.
77
+ *
78
+ * All types are in typeweaver's native `IHttpRequest`/`IHttpResponse` format.
79
+ * No framework-specific types are involved.
80
+ *
81
+ * @template RequestHandlers - Object type containing typed handler methods
82
+ */
83
+ export abstract class TypeweaverRouter<
84
+ RequestHandlers extends Record<string, RequestHandler>,
85
+ > {
86
+ protected readonly requestHandlers: RequestHandlers;
87
+ private readonly routes: RouteDefinition[] = [];
88
+ private readonly errorConfig: RouterErrorConfig;
89
+
90
+ public constructor(options: TypeweaverRouterOptions<RequestHandlers>) {
91
+ const {
92
+ requestHandlers,
93
+ validateRequests = true,
94
+ handleHttpResponseErrors = true,
95
+ handleValidationErrors = true,
96
+ handleUnknownErrors = true,
97
+ } = options;
98
+
99
+ this.requestHandlers = requestHandlers;
100
+
101
+ this.errorConfig = {
102
+ validateRequests,
103
+ handleHttpResponseErrors,
104
+ handleValidationErrors,
105
+ handleUnknownErrors,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Register a route. Called by generated subclasses in their constructor.
111
+ *
112
+ * @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
113
+ * @param path - Path pattern with `:param` placeholders
114
+ * @param validator - Request validator for this operation
115
+ * @param handler - Type-safe request handler
116
+ */
117
+ protected route(
118
+ method: HttpMethod,
119
+ path: string,
120
+ validator: IRequestValidator,
121
+ handler: RequestHandler
122
+ ): void {
123
+ this.routes.push({
124
+ method,
125
+ path,
126
+ validator,
127
+ handler,
128
+ routerConfig: this.errorConfig,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Returns all registered routes. Used by `TypeweaverApp` when mounting via `app.route(...)`.
134
+ */
135
+ public getRoutes(): readonly RouteDefinition[] {
136
+ return this.routes;
137
+ }
138
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * This file was automatically generated by typeweaver.
3
+ * DO NOT EDIT. Instead, modify the source definition file and generate again.
4
+ *
5
+ * @generated by @rexeus/typeweaver
6
+ */
7
+
8
+ /* eslint-disable import/max-dependencies */
9
+
10
+ export { TypeweaverApp, type TypeweaverAppOptions } from "./TypeweaverApp";
11
+ export {
12
+ TypeweaverRouter,
13
+ type TypeweaverRouterOptions,
14
+ } from "./TypeweaverRouter";
15
+ export { HttpMethod } from "@rexeus/typeweaver-core";
16
+ export type {
17
+ HttpResponseErrorHandler,
18
+ UnknownErrorHandler,
19
+ ValidationErrorHandler,
20
+ } from "./Router";
21
+ export type { ServerContext } from "./ServerContext";
22
+ export type { RequestHandler } from "./RequestHandler";
23
+ export { StateMap } from "./StateMap";
24
+ export {
25
+ defineMiddleware,
26
+ type InferState,
27
+ type NextFn,
28
+ type StateRequirementError,
29
+ type TypedMiddleware,
30
+ } from "./TypedMiddleware";
31
+ export {
32
+ BodyParseError,
33
+ PayloadTooLargeError,
34
+ ResponseSerializationError,
35
+ } from "./Errors";
36
+ export { FetchApiAdapter } from "./FetchApiAdapter";
37
+ export { nodeAdapter, type NodeAdapterOptions } from "./NodeAdapter";
38
+ export { pathMatcher } from "./PathMatcher";
@@ -0,0 +1 @@
1
+ {"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js":{"bytes":569,"imports":[],"format":"esm"},"src/RouterGenerator.ts":{"bytes":3869,"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-core","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-gen","kind":"import-statement","external":true},{"path":"case","kind":"import-statement","external":true},{"path":"/Users/denniswentzien/Development/rexeus/typeweaver-5/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":1036,"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-gen","kind":"import-statement","external":true},{"path":"src/RouterGenerator.ts","kind":"import-statement","original":"./RouterGenerator"},{"path":"/Users/denniswentzien/Development/rexeus/typeweaver-5/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/index.cjs":{"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-gen","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-core","kind":"import-statement","external":true},{"path":"@rexeus/typeweaver-gen","kind":"import-statement","external":true},{"path":"case","kind":"import-statement","external":true}],"exports":["default"],"entryPoint":"src/index.ts","inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js":{"bytesInOutput":314},"src/index.ts":{"bytesInOutput":583},"src/RouterGenerator.ts":{"bytesInOutput":2862}},"bytes":3988}}}