@rexeus/typeweaver-hono 0.7.0 โ†’ 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ npm install @rexeus/typeweaver-core
29
29
  ## ๐Ÿ’ก How to use
30
30
 
31
31
  ```bash
32
- npx typeweaver generate --input ./api/definition --output ./api/generated --plugins hono
32
+ npx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins hono
33
33
  ```
34
34
 
35
35
  More on the CLI in
@@ -51,28 +51,28 @@ Implement your handlers and mount the generated router in a Hono app.
51
51
  // api/user-handlers.ts
52
52
  import type { Context } from "hono";
53
53
  import { HttpStatusCode } from "@rexeus/typeweaver-core";
54
- import type { IGetUserRequest, GetUserResponse, UserNotFoundErrorResponse } from "./generated";
55
- import { GetUserSuccessResponse } from "./generated";
54
+ import type { HonoUserApiHandler, IGetUserRequest, GetUserResponse } from "./generated";
55
+ import { createUserNotFoundErrorResponse, createGetUserSuccessResponse } from "./generated";
56
56
 
57
57
  export class UserHandlers implements HonoUserApiHandler {
58
- async handleGetUserRequest(request: IGetUserRequest, context: Context): Promise<GetUserResponse> {
59
- // Symbolic database fetch
60
- const databaseResult = {} as any;
61
- if (!databaseResult) {
62
- // Will be properly handled by the generated router and returned as a 404 response
63
- return new UserNotFoundErrorResponse({
64
- statusCode: HttpStatusCode.NotFound,
65
- header: { "Content-Type": "application/json" },
66
- body: { message: "User not found" },
67
- });
68
- }
69
-
70
- return new GetUserSuccessResponse({
71
- statusCode: HttpStatusCode.OK,
58
+ async handleGetUserRequest(request: IGetUserRequest, context: Context): Promise<GetUserResponse> {
59
+ const user = await db.findUser(request.param.userId);
60
+ if (!user) {
61
+ return createUserNotFoundErrorResponse({
72
62
  header: { "Content-Type": "application/json" },
73
- body: { id: request.param.userId, name: "Jane", email: "jane@example.com" },
63
+ body: { message: "User not found" },
74
64
  });
75
- },
65
+ }
66
+
67
+ return createGetUserSuccessResponse({
68
+ header: { "Content-Type": "application/json" },
69
+ body: {
70
+ id: request.param.userId,
71
+ name: "Jane",
72
+ email: "jane@example.com",
73
+ },
74
+ });
75
+ }
76
76
  // Implement other operation handlers: handleCreateUserRequest, ...
77
77
  }
78
78
  ```
@@ -91,8 +91,10 @@ const userHandlers = new UserHandlers();
91
91
  const userRouter = new UserHono({
92
92
  requestHandlers: userHandlers,
93
93
  validateRequests: true, // default, validates requests
94
- handleValidationErrors: true, // default: returns 400 with issues
95
- handleHttpResponseErrors: true, // default: returns thrown HttpResponse as-is
94
+ validateResponses: true, // default, validates responses and strips extra fields
95
+ handleRequestValidationErrors: true, // default: returns 400 with issues
96
+ handleResponseValidationErrors: true, // default: returns 500
97
+ handleHttpResponseErrors: true, // default: returns thrown typed HTTP responses as-is
96
98
  handleUnknownErrors: true, // default: returns 500
97
99
  });
98
100
 
@@ -110,14 +112,27 @@ serve({ fetch: app.fetch, port: 3000 }, () => {
110
112
 
111
113
  - `requestHandlers`: object implementing the generated `Hono<ResourceName>ApiHandler` type
112
114
  - `validateRequests` (default: `true`): enable/disable request validation
113
- - `handleValidationErrors`: `true` | `false` | `(err, c) => IHttpResponse | Promise<IHttpResponse>`,
115
+ - `validateResponses` (default: `true`): enable/disable response validation. When enabled, responses
116
+ are validated against the operation's schema and extra body fields are stripped before sending.
117
+ - `handleRequestValidationErrors`: `true` | `false` |
118
+ `(err, c) => IHttpResponse | Promise<IHttpResponse>`
114
119
  - If `true` (default), returns `400 Bad Request` with validation issues in the body
115
120
  - If `false`, disables this handler (errors fall through to the unknown error handler)
116
121
  - If function, calls the function with the error and context, expects an `IHttpResponse` to
117
122
  return, so you can customize the response in the way you want
123
+ - `handleResponseValidationErrors`: `true` | `false` |
124
+ `(err, response, c) => IHttpResponse | Promise<IHttpResponse>`
125
+ - If `true` (default), returns `500 Internal Server Error`
126
+ - If `false`, disables response validation error handling โ€” the invalid response is returned
127
+ as-is. Validation still runs (and strips extra fields on valid responses), but invalid responses
128
+ pass through unchanged. Useful when you want field stripping without blocking invalid responses.
129
+ - If function, calls the function with the `ResponseValidationError`, the original (invalid)
130
+ response, and the Hono context. The function should return an `IHttpResponse`. If the custom
131
+ handler throws, the original response is returned as a fallback.
118
132
  - `handleHttpResponseErrors`: `true` | `false` |
119
133
  `(err, c) => IHttpResponse | Promise<IHttpResponse>`
120
- - If `true` (default), returns thrown `HttpResponse` as-is, they will be sent as the response
134
+ - If `true` (default), returns thrown typed HTTP responses (`ITypedHttpResponse`) as-is, they will
135
+ be sent as the response
121
136
  - If `false`, disables this handler (errors fall through to the unknown error handler)
122
137
  - If function, calls the function with the error and context, expects an `IHttpResponse` to
123
138
  return, so you can customize the response in the way you want
package/dist/index.cjs CHANGED
@@ -6,16 +6,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") {
10
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) {
13
- __defProp(to, key, {
14
- get: ((k) => from[k]).bind(null, key),
15
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
- });
17
- }
18
- }
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
19
15
  }
20
16
  return to;
21
17
  };
@@ -23,7 +19,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
19
  value: mod,
24
20
  enumerable: true
25
21
  }) : target, mod));
26
-
27
22
  //#endregion
28
23
  let node_path = require("node:path");
29
24
  node_path = __toESM(node_path);
@@ -32,65 +27,37 @@ let _rexeus_typeweaver_gen = require("@rexeus/typeweaver-gen");
32
27
  let _rexeus_typeweaver_core = require("@rexeus/typeweaver-core");
33
28
  let case$1 = require("case");
34
29
  case$1 = __toESM(case$1);
35
-
36
- //#region src/HonoRouterGenerator.ts
37
- var HonoRouterGenerator = class {
38
- static generate(context) {
39
- const moduleDir = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
40
- const templateFile = node_path.default.join(moduleDir, "templates", "HonoRouter.ejs");
41
- for (const [entityName, entityResource] of Object.entries(context.resources.entityResources)) this.writeHonoRouter(entityName, templateFile, entityResource.operations, context);
42
- }
43
- static writeHonoRouter(entityName, templateFile, operationResources, context) {
44
- const pascalCaseEntityName = case$1.default.pascal(entityName);
45
- const outputDir = node_path.default.join(context.outputDir, entityName);
46
- const outputPath = node_path.default.join(outputDir, `${pascalCaseEntityName}Hono.ts`);
47
- const operations = operationResources.filter((resource) => resource.definition.method !== _rexeus_typeweaver_core.HttpMethod.HEAD).map((resource) => this.createOperationData(resource)).sort((a, b) => this.compareRoutes(a, b));
48
- const content = context.renderTemplate(templateFile, {
49
- coreDir: node_path.default.relative(outputDir, context.outputDir),
50
- entityName,
51
- pascalCaseEntityName,
52
- operations
53
- });
54
- const relativePath = node_path.default.relative(context.outputDir, outputPath);
55
- context.writeFile(relativePath, content);
56
- }
57
- static createOperationData(resource) {
58
- const operationId = resource.definition.operationId;
59
- const className = case$1.default.pascal(operationId);
60
- return {
61
- operationId,
62
- className,
63
- handlerName: `handle${className}Request`,
64
- method: resource.definition.method,
65
- path: resource.definition.path
66
- };
67
- }
68
- static compareRoutes(a, b) {
69
- const aSegments = a.path.split("/").filter((s) => s);
70
- const bSegments = b.path.split("/").filter((s) => s);
71
- if (aSegments.length !== bSegments.length) return aSegments.length - bSegments.length;
72
- for (let i = 0; i < aSegments.length; i++) {
73
- const aSegment = aSegments[i];
74
- const bSegment = bSegments[i];
75
- const aIsParam = aSegment.startsWith(":");
76
- if (aIsParam !== bSegment.startsWith(":")) return aIsParam ? 1 : -1;
77
- if (aSegment !== bSegment) return aSegment.localeCompare(bSegment);
78
- }
79
- return this.getMethodPriority(a.method) - this.getMethodPriority(b.method);
80
- }
81
- static getMethodPriority(method) {
82
- return {
83
- GET: 1,
84
- POST: 2,
85
- PUT: 3,
86
- PATCH: 4,
87
- DELETE: 5,
88
- OPTIONS: 6,
89
- HEAD: 7
90
- }[method] ?? 999;
91
- }
92
- };
93
-
30
+ //#region src/honoRouterGenerator.ts
31
+ function generate(context) {
32
+ const moduleDir = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
33
+ const templateFile = node_path.default.join(moduleDir, "templates", "HonoRouter.ejs");
34
+ for (const resource of context.normalizedSpec.resources) writeHonoRouter(resource, templateFile, context);
35
+ }
36
+ function writeHonoRouter(resource, templateFile, context) {
37
+ const pascalCaseEntityName = case$1.default.pascal(resource.name);
38
+ const outputDir = context.getResourceOutputDir(resource.name);
39
+ const outputPath = node_path.default.join(outputDir, `${pascalCaseEntityName}Hono.ts`);
40
+ const operations = resource.operations.filter((operation) => operation.method !== _rexeus_typeweaver_core.HttpMethod.HEAD).map((operation) => createOperationData(operation)).sort((a, b) => (0, _rexeus_typeweaver_gen.compareRoutes)(a, b));
41
+ const content = context.renderTemplate(templateFile, {
42
+ coreDir: node_path.default.relative(outputDir, context.outputDir),
43
+ entityName: resource.name,
44
+ pascalCaseEntityName,
45
+ operations
46
+ });
47
+ const relativePath = node_path.default.relative(context.outputDir, outputPath);
48
+ context.writeFile(relativePath, content);
49
+ }
50
+ function createOperationData(operation) {
51
+ const operationId = operation.operationId;
52
+ const className = case$1.default.pascal(operationId);
53
+ return {
54
+ operationId,
55
+ className,
56
+ handlerName: `handle${className}Request`,
57
+ method: operation.method,
58
+ path: operation.path
59
+ };
60
+ }
94
61
  //#endregion
95
62
  //#region src/index.ts
96
63
  const moduleDir = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
@@ -99,9 +66,8 @@ var HonoPlugin = class extends _rexeus_typeweaver_gen.BasePlugin {
99
66
  generate(context) {
100
67
  const libSourceDir = node_path.default.join(moduleDir, "lib");
101
68
  this.copyLibFiles(context, libSourceDir, this.name);
102
- HonoRouterGenerator.generate(context);
69
+ generate(context);
103
70
  }
104
71
  };
105
-
106
72
  //#endregion
107
- module.exports = HonoPlugin;
73
+ module.exports = HonoPlugin;
package/dist/index.mjs CHANGED
@@ -1,67 +1,39 @@
1
1
  import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- import { BasePlugin } from "@rexeus/typeweaver-gen";
3
+ import { BasePlugin, compareRoutes } from "@rexeus/typeweaver-gen";
4
4
  import { HttpMethod } from "@rexeus/typeweaver-core";
5
5
  import Case from "case";
6
-
7
- //#region src/HonoRouterGenerator.ts
8
- var HonoRouterGenerator = class {
9
- static generate(context) {
10
- const moduleDir = path.dirname(fileURLToPath(import.meta.url));
11
- const templateFile = path.join(moduleDir, "templates", "HonoRouter.ejs");
12
- for (const [entityName, entityResource] of Object.entries(context.resources.entityResources)) this.writeHonoRouter(entityName, templateFile, entityResource.operations, context);
13
- }
14
- static writeHonoRouter(entityName, templateFile, operationResources, context) {
15
- const pascalCaseEntityName = Case.pascal(entityName);
16
- const outputDir = path.join(context.outputDir, entityName);
17
- const outputPath = path.join(outputDir, `${pascalCaseEntityName}Hono.ts`);
18
- const operations = operationResources.filter((resource) => resource.definition.method !== HttpMethod.HEAD).map((resource) => this.createOperationData(resource)).sort((a, b) => this.compareRoutes(a, b));
19
- const content = context.renderTemplate(templateFile, {
20
- coreDir: path.relative(outputDir, context.outputDir),
21
- entityName,
22
- pascalCaseEntityName,
23
- operations
24
- });
25
- const relativePath = path.relative(context.outputDir, outputPath);
26
- context.writeFile(relativePath, content);
27
- }
28
- static createOperationData(resource) {
29
- const operationId = resource.definition.operationId;
30
- const className = Case.pascal(operationId);
31
- return {
32
- operationId,
33
- className,
34
- handlerName: `handle${className}Request`,
35
- method: resource.definition.method,
36
- path: resource.definition.path
37
- };
38
- }
39
- static compareRoutes(a, b) {
40
- const aSegments = a.path.split("/").filter((s) => s);
41
- const bSegments = b.path.split("/").filter((s) => s);
42
- if (aSegments.length !== bSegments.length) return aSegments.length - bSegments.length;
43
- for (let i = 0; i < aSegments.length; i++) {
44
- const aSegment = aSegments[i];
45
- const bSegment = bSegments[i];
46
- const aIsParam = aSegment.startsWith(":");
47
- if (aIsParam !== bSegment.startsWith(":")) return aIsParam ? 1 : -1;
48
- if (aSegment !== bSegment) return aSegment.localeCompare(bSegment);
49
- }
50
- return this.getMethodPriority(a.method) - this.getMethodPriority(b.method);
51
- }
52
- static getMethodPriority(method) {
53
- return {
54
- GET: 1,
55
- POST: 2,
56
- PUT: 3,
57
- PATCH: 4,
58
- DELETE: 5,
59
- OPTIONS: 6,
60
- HEAD: 7
61
- }[method] ?? 999;
62
- }
63
- };
64
-
6
+ //#region src/honoRouterGenerator.ts
7
+ function generate(context) {
8
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
9
+ const templateFile = path.join(moduleDir, "templates", "HonoRouter.ejs");
10
+ for (const resource of context.normalizedSpec.resources) writeHonoRouter(resource, templateFile, context);
11
+ }
12
+ function writeHonoRouter(resource, templateFile, context) {
13
+ const pascalCaseEntityName = Case.pascal(resource.name);
14
+ const outputDir = context.getResourceOutputDir(resource.name);
15
+ const outputPath = path.join(outputDir, `${pascalCaseEntityName}Hono.ts`);
16
+ const operations = resource.operations.filter((operation) => operation.method !== HttpMethod.HEAD).map((operation) => createOperationData(operation)).sort((a, b) => compareRoutes(a, b));
17
+ const content = context.renderTemplate(templateFile, {
18
+ coreDir: path.relative(outputDir, context.outputDir),
19
+ entityName: resource.name,
20
+ pascalCaseEntityName,
21
+ operations
22
+ });
23
+ const relativePath = path.relative(context.outputDir, outputPath);
24
+ context.writeFile(relativePath, content);
25
+ }
26
+ function createOperationData(operation) {
27
+ const operationId = operation.operationId;
28
+ const className = Case.pascal(operationId);
29
+ return {
30
+ operationId,
31
+ className,
32
+ handlerName: `handle${className}Request`,
33
+ method: operation.method,
34
+ path: operation.path
35
+ };
36
+ }
65
37
  //#endregion
66
38
  //#region src/index.ts
67
39
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
@@ -70,10 +42,10 @@ var HonoPlugin = class extends BasePlugin {
70
42
  generate(context) {
71
43
  const libSourceDir = path.join(moduleDir, "lib");
72
44
  this.copyLibFiles(context, libSourceDir, this.name);
73
- HonoRouterGenerator.generate(context);
45
+ generate(context);
74
46
  }
75
47
  };
76
-
77
48
  //#endregion
78
49
  export { HonoPlugin as default };
50
+
79
51
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/HonoRouterGenerator.ts","../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { HttpMethod } from \"@rexeus/typeweaver-core\";\nimport type {\n GeneratorContext,\n OperationResource,\n} from \"@rexeus/typeweaver-gen\";\nimport Case from \"case\";\n\nexport class HonoRouterGenerator {\n public static generate(context: GeneratorContext): void {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const templateFile = path.join(moduleDir, \"templates\", \"HonoRouter.ejs\");\n\n for (const [entityName, entityResource] of Object.entries(\n context.resources.entityResources\n )) {\n this.writeHonoRouter(\n entityName,\n templateFile,\n entityResource.operations,\n context\n );\n }\n }\n\n private static writeHonoRouter(\n entityName: string,\n templateFile: string,\n operationResources: OperationResource[],\n context: GeneratorContext\n ): void {\n const pascalCaseEntityName = Case.pascal(entityName);\n const outputDir = path.join(context.outputDir, entityName);\n const outputPath = path.join(outputDir, `${pascalCaseEntityName}Hono.ts`);\n\n const operations = operationResources\n // Hono handles HEAD requests automatically, so we skip them\n .filter(resource => resource.definition.method !== HttpMethod.HEAD)\n .map(resource => this.createOperationData(resource))\n .sort((a, b) => this.compareRoutes(a, b));\n\n const content = context.renderTemplate(templateFile, {\n coreDir: path.relative(outputDir, context.outputDir),\n entityName,\n pascalCaseEntityName,\n operations,\n });\n\n const relativePath = path.relative(context.outputDir, outputPath);\n context.writeFile(relativePath, content);\n }\n\n private static createOperationData(resource: OperationResource) {\n const operationId = resource.definition.operationId;\n const className = Case.pascal(operationId);\n const handlerName = `handle${className}Request`;\n\n return {\n operationId,\n className,\n handlerName,\n method: resource.definition.method,\n path: resource.definition.path,\n };\n }\n\n private static compareRoutes(\n a: ReturnType<typeof HonoRouterGenerator.createOperationData>,\n b: ReturnType<typeof HonoRouterGenerator.createOperationData>\n ): number {\n const aSegments = a.path.split(\"/\").filter(s => s);\n const bSegments = b.path.split(\"/\").filter(s => s);\n\n // 1. Compare by depth first (shallow to deep)\n if (aSegments.length !== bSegments.length) {\n return aSegments.length - bSegments.length;\n }\n\n // 2. Compare segment by segment\n for (let i = 0; i < aSegments.length; i++) {\n const aSegment = aSegments[i]!;\n const bSegment = bSegments[i]!;\n\n const aIsParam = aSegment.startsWith(\":\");\n const bIsParam = bSegment.startsWith(\":\");\n\n // Static segments before parameters\n if (aIsParam !== bIsParam) {\n return aIsParam ? 1 : -1;\n }\n\n // Within same type, alphabetical order\n if (aSegment !== bSegment) {\n return aSegment.localeCompare(bSegment);\n }\n }\n\n // 3. Same path = sort by HTTP method priority\n return this.getMethodPriority(a.method) - this.getMethodPriority(b.method);\n }\n\n private static getMethodPriority(method: string): number {\n const priorities: Record<string, number> = {\n GET: 1,\n POST: 2,\n PUT: 3,\n PATCH: 4,\n DELETE: 5,\n OPTIONS: 6,\n HEAD: 7,\n };\n return priorities[method] ?? 999;\n }\n}\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { BasePlugin } from \"@rexeus/typeweaver-gen\";\nimport type { GeneratorContext } from \"@rexeus/typeweaver-gen\";\nimport { HonoRouterGenerator } from \"./HonoRouterGenerator\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport default class HonoPlugin extends BasePlugin {\n public name = \"hono\";\n\n public override generate(context: GeneratorContext): void {\n const libSourceDir = path.join(moduleDir, \"lib\");\n this.copyLibFiles(context, libSourceDir, this.name);\n\n HonoRouterGenerator.generate(context);\n }\n}\n"],"mappings":";;;;;;;AASA,IAAa,sBAAb,MAAiC;CAC/B,OAAc,SAAS,SAAiC;EACtD,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;EAC9D,MAAM,eAAe,KAAK,KAAK,WAAW,aAAa,iBAAiB;AAExE,OAAK,MAAM,CAAC,YAAY,mBAAmB,OAAO,QAChD,QAAQ,UAAU,gBACnB,CACC,MAAK,gBACH,YACA,cACA,eAAe,YACf,QACD;;CAIL,OAAe,gBACb,YACA,cACA,oBACA,SACM;EACN,MAAM,uBAAuB,KAAK,OAAO,WAAW;EACpD,MAAM,YAAY,KAAK,KAAK,QAAQ,WAAW,WAAW;EAC1D,MAAM,aAAa,KAAK,KAAK,WAAW,GAAG,qBAAqB,SAAS;EAEzE,MAAM,aAAa,mBAEhB,QAAO,aAAY,SAAS,WAAW,WAAW,WAAW,KAAK,CAClE,KAAI,aAAY,KAAK,oBAAoB,SAAS,CAAC,CACnD,MAAM,GAAG,MAAM,KAAK,cAAc,GAAG,EAAE,CAAC;EAE3C,MAAM,UAAU,QAAQ,eAAe,cAAc;GACnD,SAAS,KAAK,SAAS,WAAW,QAAQ,UAAU;GACpD;GACA;GACA;GACD,CAAC;EAEF,MAAM,eAAe,KAAK,SAAS,QAAQ,WAAW,WAAW;AACjE,UAAQ,UAAU,cAAc,QAAQ;;CAG1C,OAAe,oBAAoB,UAA6B;EAC9D,MAAM,cAAc,SAAS,WAAW;EACxC,MAAM,YAAY,KAAK,OAAO,YAAY;AAG1C,SAAO;GACL;GACA;GACA,aALkB,SAAS,UAAU;GAMrC,QAAQ,SAAS,WAAW;GAC5B,MAAM,SAAS,WAAW;GAC3B;;CAGH,OAAe,cACb,GACA,GACQ;EACR,MAAM,YAAY,EAAE,KAAK,MAAM,IAAI,CAAC,QAAO,MAAK,EAAE;EAClD,MAAM,YAAY,EAAE,KAAK,MAAM,IAAI,CAAC,QAAO,MAAK,EAAE;AAGlD,MAAI,UAAU,WAAW,UAAU,OACjC,QAAO,UAAU,SAAS,UAAU;AAItC,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;GACzC,MAAM,WAAW,UAAU;GAC3B,MAAM,WAAW,UAAU;GAE3B,MAAM,WAAW,SAAS,WAAW,IAAI;AAIzC,OAAI,aAHa,SAAS,WAAW,IAAI,CAIvC,QAAO,WAAW,IAAI;AAIxB,OAAI,aAAa,SACf,QAAO,SAAS,cAAc,SAAS;;AAK3C,SAAO,KAAK,kBAAkB,EAAE,OAAO,GAAG,KAAK,kBAAkB,EAAE,OAAO;;CAG5E,OAAe,kBAAkB,QAAwB;AAUvD,SAT2C;GACzC,KAAK;GACL,MAAM;GACN,KAAK;GACL,OAAO;GACP,QAAQ;GACR,SAAS;GACT,MAAM;GACP,CACiB,WAAW;;;;;;AC1GjC,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE9D,IAAqB,aAArB,cAAwC,WAAW;CACjD,AAAO,OAAO;CAEd,AAAgB,SAAS,SAAiC;EACxD,MAAM,eAAe,KAAK,KAAK,WAAW,MAAM;AAChD,OAAK,aAAa,SAAS,cAAc,KAAK,KAAK;AAEnD,sBAAoB,SAAS,QAAQ"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/honoRouterGenerator.ts","../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { HttpMethod } from \"@rexeus/typeweaver-core\";\nimport { compareRoutes } from \"@rexeus/typeweaver-gen\";\nimport type {\n GeneratorContext,\n NormalizedOperation,\n NormalizedResource,\n} from \"@rexeus/typeweaver-gen\";\nimport Case from \"case\";\n\nexport function generate(context: GeneratorContext): void {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const templateFile = path.join(moduleDir, \"templates\", \"HonoRouter.ejs\");\n\n for (const resource of context.normalizedSpec.resources) {\n writeHonoRouter(resource, templateFile, context);\n }\n}\n\nfunction writeHonoRouter(\n resource: NormalizedResource,\n templateFile: string,\n context: GeneratorContext\n): void {\n const pascalCaseEntityName = Case.pascal(resource.name);\n const outputDir = context.getResourceOutputDir(resource.name);\n const outputPath = path.join(outputDir, `${pascalCaseEntityName}Hono.ts`);\n\n const operations = resource.operations\n // Hono handles HEAD requests automatically, so we skip them\n .filter(operation => operation.method !== HttpMethod.HEAD)\n .map(operation => createOperationData(operation))\n .sort((a, b) => compareRoutes(a, b));\n\n const content = context.renderTemplate(templateFile, {\n coreDir: path.relative(outputDir, context.outputDir),\n entityName: resource.name,\n pascalCaseEntityName,\n operations,\n });\n\n const relativePath = path.relative(context.outputDir, outputPath);\n context.writeFile(relativePath, content);\n}\n\nfunction createOperationData(operation: NormalizedOperation) {\n const operationId = operation.operationId;\n const className = Case.pascal(operationId);\n const handlerName = `handle${className}Request`;\n\n return {\n operationId,\n className,\n handlerName,\n method: operation.method,\n path: operation.path,\n };\n}\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { BasePlugin } from \"@rexeus/typeweaver-gen\";\nimport type { GeneratorContext } from \"@rexeus/typeweaver-gen\";\nimport { generate as generateHonoRouters } from \"./honoRouterGenerator\";\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport default class HonoPlugin extends BasePlugin {\n public name = \"hono\";\n\n public override generate(context: GeneratorContext): void {\n const libSourceDir = path.join(moduleDir, \"lib\");\n this.copyLibFiles(context, libSourceDir, this.name);\n\n generateHonoRouters(context);\n }\n}\n"],"mappings":";;;;;;AAWA,SAAgB,SAAS,SAAiC;CACxD,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;CAC9D,MAAM,eAAe,KAAK,KAAK,WAAW,aAAa,iBAAiB;AAExE,MAAK,MAAM,YAAY,QAAQ,eAAe,UAC5C,iBAAgB,UAAU,cAAc,QAAQ;;AAIpD,SAAS,gBACP,UACA,cACA,SACM;CACN,MAAM,uBAAuB,KAAK,OAAO,SAAS,KAAK;CACvD,MAAM,YAAY,QAAQ,qBAAqB,SAAS,KAAK;CAC7D,MAAM,aAAa,KAAK,KAAK,WAAW,GAAG,qBAAqB,SAAS;CAEzE,MAAM,aAAa,SAAS,WAEzB,QAAO,cAAa,UAAU,WAAW,WAAW,KAAK,CACzD,KAAI,cAAa,oBAAoB,UAAU,CAAC,CAChD,MAAM,GAAG,MAAM,cAAc,GAAG,EAAE,CAAC;CAEtC,MAAM,UAAU,QAAQ,eAAe,cAAc;EACnD,SAAS,KAAK,SAAS,WAAW,QAAQ,UAAU;EACpD,YAAY,SAAS;EACrB;EACA;EACD,CAAC;CAEF,MAAM,eAAe,KAAK,SAAS,QAAQ,WAAW,WAAW;AACjE,SAAQ,UAAU,cAAc,QAAQ;;AAG1C,SAAS,oBAAoB,WAAgC;CAC3D,MAAM,cAAc,UAAU;CAC9B,MAAM,YAAY,KAAK,OAAO,YAAY;AAG1C,QAAO;EACL;EACA;EACA,aALkB,SAAS,UAAU;EAMrC,QAAQ,UAAU;EAClB,MAAM,UAAU;EACjB;;;;ACnDH,MAAM,YAAY,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE9D,IAAqB,aAArB,cAAwC,WAAW;CACjD,OAAc;CAEd,SAAyB,SAAiC;EACxD,MAAM,eAAe,KAAK,KAAK,WAAW,MAAM;AAChD,OAAK,aAAa,SAAS,cAAc,KAAK,KAAK;AAEnD,WAAoB,QAAQ"}
@@ -5,11 +5,21 @@
5
5
  * @generated by @rexeus/typeweaver
6
6
  */
7
7
 
8
- import { HttpResponse, RequestValidationError } from "@rexeus/typeweaver-core";
8
+ import {
9
+ createDefaultErrorBody,
10
+ createDefaultErrorResponse,
11
+ internalServerErrorDefaultError,
12
+ isTypedHttpResponse,
13
+ RequestValidationError,
14
+ validationDefaultError,
15
+ } from "@rexeus/typeweaver-core";
9
16
  import type {
10
17
  IHttpRequest,
11
18
  IHttpResponse,
12
19
  IRequestValidator,
20
+ IResponseValidator,
21
+ ITypedHttpResponse,
22
+ ResponseValidationError,
13
23
  } from "@rexeus/typeweaver-core";
14
24
  import { Hono } from "hono";
15
25
  import { HonoAdapter } from "./HonoAdapter";
@@ -25,7 +35,7 @@ import type { BlankEnv, BlankSchema, Env, Schema } from "hono/types";
25
35
  * @returns The HTTP response to send to the client
26
36
  */
27
37
  export type HonoHttpResponseErrorHandler = (
28
- error: HttpResponse,
38
+ error: ITypedHttpResponse,
29
39
  context: Context
30
40
  ) => Promise<IHttpResponse> | IHttpResponse;
31
41
 
@@ -35,7 +45,7 @@ export type HonoHttpResponseErrorHandler = (
35
45
  * @param context - The Hono context for the current request
36
46
  * @returns The HTTP response to send to the client
37
47
  */
38
- export type HonoValidationErrorHandler = (
48
+ export type HonoRequestValidationErrorHandler = (
39
49
  error: RequestValidationError,
40
50
  context: Context
41
51
  ) => Promise<IHttpResponse> | IHttpResponse;
@@ -51,6 +61,20 @@ export type HonoUnknownErrorHandler = (
51
61
  context: Context
52
62
  ) => Promise<IHttpResponse> | IHttpResponse;
53
63
 
64
+ /**
65
+ * Handles response validation errors.
66
+ * Called when a handler returns a response that does not match the expected schema.
67
+ * @param error - The response validation error with schema mismatch details
68
+ * @param response - The original (invalid) response from the handler
69
+ * @param context - The Hono context for the current request
70
+ * @returns The HTTP response to send to the client (typically a 500)
71
+ */
72
+ export type HonoResponseValidationErrorHandler = (
73
+ error: ResponseValidationError,
74
+ response: IHttpResponse,
75
+ context: Context
76
+ ) => Promise<IHttpResponse> | IHttpResponse;
77
+
54
78
  /**
55
79
  * Configuration options for TypeweaverHono routers.
56
80
  * @template RequestHandlers - Type containing all request handler methods
@@ -64,32 +88,52 @@ export type TypeweaverHonoOptions<
64
88
  * Request handler methods for each operation.
65
89
  * Each handler receives a request (validated if `validateRequests` is true) and Hono context.
66
90
  */
67
- requestHandlers: RequestHandlers;
91
+ readonly requestHandlers: RequestHandlers;
68
92
 
69
93
  /**
70
94
  * Enable request validation using generated validators.
71
95
  * When false, requests are passed through without validation.
72
96
  * @default true
73
97
  */
74
- validateRequests?: boolean;
98
+ readonly validateRequests?: boolean;
75
99
 
76
100
  /**
77
- * Configure handling of HttpResponse errors thrown by handlers.
78
- * - `true`: Use default handler (returns the error as-is)
79
- * - `false`: Let errors bubble up to Hono
80
- * - `function`: Use custom error handler
101
+ * Enable response validation using generated validators.
102
+ * When true, responses are validated and stripped of extra fields before sending.
81
103
  * @default true
82
104
  */
83
- handleHttpResponseErrors?: HonoHttpResponseErrorHandler | boolean;
105
+ readonly validateResponses?: boolean;
84
106
 
85
107
  /**
86
108
  * Configure handling of request validation errors.
87
109
  * - `true`: Use default handler (400 with error details)
88
110
  * - `false`: Let errors bubble up to Hono
111
+ * - `function`: Use custom request validation error handler
112
+ * @default true
113
+ */
114
+ readonly handleRequestValidationErrors?:
115
+ | HonoRequestValidationErrorHandler
116
+ | boolean;
117
+
118
+ /**
119
+ * Configure handling of response validation errors.
120
+ * - `true`: Use default handler (500 Internal Server Error)
121
+ * - `false`: Disable response validation error handling (return response as-is)
122
+ * - `function`: Use custom response validation error handler
123
+ * @default true
124
+ */
125
+ readonly handleResponseValidationErrors?:
126
+ | HonoResponseValidationErrorHandler
127
+ | boolean;
128
+
129
+ /**
130
+ * Configure handling of HttpResponse errors thrown by handlers.
131
+ * - `true`: Use default handler (returns the error as-is)
132
+ * - `false`: Let errors bubble up to Hono
89
133
  * - `function`: Use custom error handler
90
134
  * @default true
91
135
  */
92
- handleValidationErrors?: HonoValidationErrorHandler | boolean;
136
+ readonly handleHttpResponseErrors?: HonoHttpResponseErrorHandler | boolean;
93
137
 
94
138
  /**
95
139
  * Configure handling of unknown errors.
@@ -98,7 +142,7 @@ export type TypeweaverHonoOptions<
98
142
  * - `function`: Use custom error handler
99
143
  * @default true
100
144
  */
101
- handleUnknownErrors?: HonoUnknownErrorHandler | boolean;
145
+ readonly handleUnknownErrors?: HonoUnknownErrorHandler | boolean;
102
146
  };
103
147
 
104
148
  /**
@@ -134,11 +178,15 @@ export abstract class TypeweaverHono<
134
178
  * Resolved configuration for validation and error handling.
135
179
  */
136
180
  private readonly config: {
137
- validateRequests: boolean;
138
- errorHandlers: {
139
- validation: HonoValidationErrorHandler | undefined;
140
- httpResponse: HonoHttpResponseErrorHandler | undefined;
141
- unknown: HonoUnknownErrorHandler | undefined;
181
+ readonly validateRequests: boolean;
182
+ readonly validateResponses: boolean;
183
+ readonly errorHandlers: {
184
+ readonly requestValidation: HonoRequestValidationErrorHandler | undefined;
185
+ readonly responseValidation:
186
+ | HonoResponseValidationErrorHandler
187
+ | undefined;
188
+ readonly httpResponse: HonoHttpResponseErrorHandler | undefined;
189
+ readonly unknown: HonoUnknownErrorHandler | undefined;
142
190
  };
143
191
  };
144
192
 
@@ -146,11 +194,10 @@ export abstract class TypeweaverHono<
146
194
  * Default error handlers used when custom handlers are not provided.
147
195
  */
148
196
  private readonly defaultHandlers = {
149
- validation: (error: RequestValidationError): IHttpResponse => ({
150
- statusCode: 400,
197
+ requestValidation: (error: RequestValidationError): IHttpResponse => ({
198
+ statusCode: validationDefaultError.statusCode,
151
199
  body: {
152
- code: "VALIDATION_ERROR",
153
- message: error.message,
200
+ ...createDefaultErrorBody(validationDefaultError),
154
201
  issues: {
155
202
  header: error.headerIssues,
156
203
  body: error.bodyIssues,
@@ -160,15 +207,13 @@ export abstract class TypeweaverHono<
160
207
  },
161
208
  }),
162
209
 
163
- httpResponse: (error: HttpResponse): IHttpResponse => error,
210
+ responseValidation: (): IHttpResponse =>
211
+ createDefaultErrorResponse(internalServerErrorDefaultError),
164
212
 
165
- unknown: (): IHttpResponse => ({
166
- statusCode: 500,
167
- body: {
168
- code: "INTERNAL_SERVER_ERROR",
169
- message: "An unexpected error occurred.",
170
- },
171
- }),
213
+ httpResponse: (error: ITypedHttpResponse): IHttpResponse => error,
214
+
215
+ unknown: (): IHttpResponse =>
216
+ createDefaultErrorResponse(internalServerErrorDefaultError),
172
217
  };
173
218
 
174
219
  /**
@@ -178,15 +223,17 @@ export abstract class TypeweaverHono<
178
223
  * @param options.requestHandlers - Object containing all request handler methods
179
224
  * @param options.validateRequests - Whether to validate requests (default: true)
180
225
  * @param options.handleHttpResponseErrors - Handler or boolean for HTTP errors (default: true)
181
- * @param options.handleValidationErrors - Handler or boolean for validation errors (default: true)
226
+ * @param options.handleRequestValidationErrors - Handler or boolean for request validation errors (default: true)
182
227
  * @param options.handleUnknownErrors - Handler or boolean for unknown errors (default: true)
183
228
  */
184
229
  public constructor(options: TypeweaverHonoOptions<RequestHandlers, HonoEnv>) {
185
230
  const {
186
231
  requestHandlers,
187
232
  validateRequests = true,
233
+ validateResponses = true,
188
234
  handleHttpResponseErrors,
189
- handleValidationErrors,
235
+ handleRequestValidationErrors,
236
+ handleResponseValidationErrors,
190
237
  handleUnknownErrors,
191
238
  ...honoOptions
192
239
  } = options;
@@ -198,9 +245,15 @@ export abstract class TypeweaverHono<
198
245
  // Resolve configuration
199
246
  this.config = {
200
247
  validateRequests,
248
+ validateResponses,
201
249
  errorHandlers: {
202
- validation: this.resolveErrorHandler(handleValidationErrors, error =>
203
- this.defaultHandlers.validation(error)
250
+ requestValidation: this.resolveErrorHandler(
251
+ handleRequestValidationErrors,
252
+ error => this.defaultHandlers.requestValidation(error)
253
+ ),
254
+ responseValidation: this.resolveErrorHandler(
255
+ handleResponseValidationErrors,
256
+ (_error, _response) => this.defaultHandlers.responseValidation()
204
257
  ),
205
258
  httpResponse: this.resolveErrorHandler(
206
259
  handleHttpResponseErrors,
@@ -239,24 +292,29 @@ export abstract class TypeweaverHono<
239
292
  * Processes errors in order: validation, HTTP response, unknown.
240
293
  */
241
294
  protected registerErrorHandler(): void {
242
- this.onError(this.handleError.bind(this));
295
+ this.onError(async (error, context) =>
296
+ this.adapter.toResponse(await this.handleError(error, context))
297
+ );
243
298
  }
244
299
 
245
300
  /**
246
301
  * Safely executes an error handler and returns null if it fails.
247
- * This allows for graceful fallback to the next handler in the chain.
302
+ * This allows for graceful fallback to the next handler in the chain
303
+ * without crashing the request pipeline.
248
304
  *
249
305
  * @param handlerFn - Function that executes the error handler
250
- * @returns Response if successful, null if handler throws
306
+ * @returns The handler's response if successful, null if the handler throws
251
307
  */
252
- private async safelyExecuteHandler(
308
+ private async safelyExecuteErrorHandler(
253
309
  handlerFn: () => Promise<IHttpResponse> | IHttpResponse
254
- ): Promise<Response | null> {
310
+ ): Promise<IHttpResponse | null> {
255
311
  try {
256
- const response = await handlerFn();
257
- return this.adapter.toResponse(response);
258
- } catch {
259
- // Handler execution failed, return null to continue to next handler
312
+ return await handlerFn();
313
+ } catch (error) {
314
+ console.error(
315
+ "TypeweaverHono: error handler threw while handling error",
316
+ error
317
+ );
260
318
  return null;
261
319
  }
262
320
  }
@@ -264,24 +322,21 @@ export abstract class TypeweaverHono<
264
322
  protected async handleError(
265
323
  error: unknown,
266
324
  context: Context
267
- ): Promise<Response> {
325
+ ): Promise<IHttpResponse> {
268
326
  // Handle validation errors
269
327
  if (
270
328
  error instanceof RequestValidationError &&
271
- this.config.errorHandlers.validation
329
+ this.config.errorHandlers.requestValidation
272
330
  ) {
273
- const response = await this.safelyExecuteHandler(() =>
274
- this.config.errorHandlers.validation!(error, context)
331
+ const response = await this.safelyExecuteErrorHandler(() =>
332
+ this.config.errorHandlers.requestValidation!(error, context)
275
333
  );
276
334
  if (response) return response;
277
335
  }
278
336
 
279
337
  // Handle HTTP response errors
280
- if (
281
- error instanceof HttpResponse &&
282
- this.config.errorHandlers.httpResponse
283
- ) {
284
- const response = await this.safelyExecuteHandler(() =>
338
+ if (isTypedHttpResponse(error) && this.config.errorHandlers.httpResponse) {
339
+ const response = await this.safelyExecuteErrorHandler(() =>
285
340
  this.config.errorHandlers.httpResponse!(error, context)
286
341
  );
287
342
  if (response) return response;
@@ -289,7 +344,7 @@ export abstract class TypeweaverHono<
289
344
 
290
345
  // Handle unknown errors
291
346
  if (this.config.errorHandlers.unknown) {
292
- const response = await this.safelyExecuteHandler(() =>
347
+ const response = await this.safelyExecuteErrorHandler(() =>
293
348
  this.config.errorHandlers.unknown!(error, context)
294
349
  );
295
350
  if (response) return response;
@@ -304,7 +359,8 @@ export abstract class TypeweaverHono<
304
359
  *
305
360
  * @param context - Hono context for the current request
306
361
  * @param operationId - Unique operation identifier from the API definition
307
- * @param validator - Request validator for the specific operation
362
+ * @param requestValidator - Request validator for the specific operation
363
+ * @param responseValidator - Response validator for the specific operation
308
364
  * @param handler - Type-safe request handler function
309
365
  * @returns Hono-compatible Response object
310
366
  */
@@ -314,7 +370,8 @@ export abstract class TypeweaverHono<
314
370
  >(
315
371
  context: Context,
316
372
  operationId: string,
317
- validator: IRequestValidator,
373
+ requestValidator: IRequestValidator,
374
+ responseValidator: IResponseValidator,
318
375
  handler: HonoRequestHandler<TRequest, TResponse>
319
376
  ): Promise<Response> {
320
377
  try {
@@ -322,15 +379,67 @@ export abstract class TypeweaverHono<
322
379
 
323
380
  const httpRequest = await this.adapter.toRequest(context);
324
381
 
325
- // Conditionally validate
326
382
  const validatedRequest = this.config.validateRequests
327
- ? (validator.validate(httpRequest) as TRequest)
383
+ ? (requestValidator.validate(httpRequest) as TRequest)
328
384
  : (httpRequest as TRequest);
329
385
 
330
386
  const httpResponse = await handler(validatedRequest, context);
331
- return this.adapter.toResponse(httpResponse);
387
+ return this.adapter.toResponse(
388
+ await this.validateResponse(responseValidator, httpResponse, context)
389
+ );
332
390
  } catch (error) {
333
- return this.handleError(error, context);
391
+ if (isTypedHttpResponse(error) && this.config.validateResponses) {
392
+ const validated = await this.validateResponse(
393
+ responseValidator,
394
+ error,
395
+ context
396
+ );
397
+ return this.adapter.toResponse(validated);
398
+ }
399
+ return this.adapter.toResponse(await this.handleError(error, context));
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Validates a response against the operation's response validator.
405
+ *
406
+ * Behavior depends on configuration:
407
+ * - `validateResponses: false` โ†’ returns the original response unchanged.
408
+ * - `validateResponses: true` (default) โ†’ runs validation:
409
+ * - Valid response โ†’ returns the stripped response (extra fields removed).
410
+ * - Invalid response + handler configured โ†’ calls the handler safely.
411
+ * If the handler throws, falls back to the original response.
412
+ * - Invalid response + `handleResponseValidationErrors: false` โ†’ returns
413
+ * the original (invalid) response as-is.
414
+ *
415
+ * @param responseValidator - The response validator for the operation
416
+ * @param response - The response to validate
417
+ * @param context - The Hono context for the current request
418
+ * @returns The validated (and stripped) response, the handler's response, or the original
419
+ */
420
+ private async validateResponse(
421
+ responseValidator: IResponseValidator,
422
+ response: IHttpResponse,
423
+ context: Context
424
+ ): Promise<IHttpResponse> {
425
+ if (!this.config.validateResponses) return response;
426
+
427
+ const result = responseValidator.safeValidate(response);
428
+
429
+ if (result.isValid) return result.data;
430
+
431
+ if (this.config.errorHandlers.responseValidation) {
432
+ const handlerResponse = await this.safelyExecuteErrorHandler(() =>
433
+ this.config.errorHandlers.responseValidation!(
434
+ result.error,
435
+ response,
436
+ context
437
+ )
438
+ );
439
+
440
+ if (handlerResponse) return handlerResponse;
334
441
  }
442
+
443
+ return response;
335
444
  }
336
445
  }
@@ -12,6 +12,7 @@ import { TypeweaverHono, type HonoRequestHandler, type TypeweaverHonoOptions } f
12
12
  import type { I<%- operation.className %>Request } from "./<%- operation.className %>Request";
13
13
  import { <%- operation.className %>RequestValidator } from "./<%- operation.className %>RequestValidator";
14
14
  import type { <%- operation.className %>Response } from "./<%- operation.className %>Response";
15
+ import { <%- operation.className %>ResponseValidator } from "./<%- operation.className %>ResponseValidator";
15
16
  <% } %>
16
17
 
17
18
  export type Hono<%- pascalCaseEntityName %>ApiHandler = {
@@ -33,6 +34,7 @@ export class <%- pascalCaseEntityName %>Hono extends TypeweaverHono<Hono<%- pasc
33
34
  context,
34
35
  '<%- operation.operationId %>',
35
36
  new <%- operation.className %>RequestValidator(),
37
+ new <%- operation.className %>ResponseValidator(),
36
38
  this.requestHandlers.<%- operation.handlerName %>.bind(this.requestHandlers)
37
39
  ));
38
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rexeus/typeweaver-hono",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Generates Hono routers and handlers straight from your API definitions. Powered by Typeweaver ๐Ÿงตโœจ",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -47,20 +47,20 @@
47
47
  "homepage": "https://github.com/rexeus/typeweaver#readme",
48
48
  "peerDependencies": {
49
49
  "hono": "^4.11.0",
50
- "@rexeus/typeweaver-core": "^0.7.0",
51
- "@rexeus/typeweaver-gen": "^0.7.0"
50
+ "@rexeus/typeweaver-core": "^0.9.0",
51
+ "@rexeus/typeweaver-gen": "^0.9.0"
52
52
  },
53
53
  "devDependencies": {
54
- "hono": "^4.11.3",
54
+ "hono": "^4.12.9",
55
55
  "test-utils": "file:../test-utils",
56
- "@rexeus/typeweaver-core": "^0.7.0",
57
- "@rexeus/typeweaver-gen": "^0.7.0"
56
+ "@rexeus/typeweaver-core": "^0.9.0",
57
+ "@rexeus/typeweaver-gen": "^0.9.0"
58
58
  },
59
59
  "dependencies": {
60
60
  "case": "^1.6.3"
61
61
  },
62
62
  "scripts": {
63
- "typecheck": "tsc --noEmit",
63
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
64
64
  "format": "oxfmt",
65
65
  "build": "tsdown && mkdir -p ./dist/templates ./dist/lib && cp -r ./src/templates/* ./dist/templates/ && cp -r ./src/lib/* ./dist/lib/ && cp ../../LICENSE ../../NOTICE ./dist/",
66
66
  "test": "vitest --run",