@rexeus/typeweaver-clients 0.4.2 → 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.
package/README.md CHANGED
@@ -31,7 +31,8 @@ npm install @rexeus/typeweaver-core
31
31
  npx typeweaver generate --input ./api/definitions --output ./api/generated --plugins clients
32
32
  ```
33
33
 
34
- More on the CLI in [@rexeus/typeweaver](https://github.com/rexeus/typeweaver/tree/main/packages/cli/README.md#️-cli).
34
+ More on the CLI in
35
+ [@rexeus/typeweaver](https://github.com/rexeus/typeweaver/tree/main/packages/cli/README.md#️-cli).
35
36
 
36
37
  ## 📂 Generated Output
37
38
 
@@ -48,7 +49,8 @@ Resource-specific HTTP clients are generated as `<ResourceName>Client.ts` files,
48
49
 
49
50
  - **Type-safe HTTP methods** - Method overloads for each operation ensuring compile-time type
50
51
  checking
51
- - **axios based** - Supports all axios features and interceptors by using custom axios instances
52
+ - **fetch based** - Zero dependencies, uses the native fetch API. Supports custom fetch functions
53
+ for middleware and testing
52
54
  - **Response type mapping** - Each response is automatically mapped to the associated response class
53
55
  and an instance of the class is returned. This ensures that all responses are in the defined
54
56
  format and it is type-safe.
@@ -66,8 +68,8 @@ Resource-specific HTTP clients are generated as `<ResourceName>Client.ts` files,
66
68
  import { TodoClient } from "path/to/generated/output";
67
69
 
68
70
  const client = new TodoClient({
69
- axiosInstance: customAxios, // Custom axios instance
70
- baseUrl: "https://api.example.com", // Base URL for all requests
71
+ fetchFn: customFetch, // Custom fetch function (optional, defaults to globalThis.fetch)
72
+ baseUrl: "https://api.example.com", // Base URL for all requests (required)
71
73
  unknownResponseHandling: "throw", // "throw" | "passthrough" for unknown responses
72
74
  // -> In "passthrough" mode, the received status code determines if the response is thrown
73
75
  isSuccessStatusCode: code => code < 400, // Custom success status code predicate, determines whether the response is successful or should be thrown
@@ -133,4 +135,4 @@ try {
133
135
 
134
136
  ## 📄 License
135
137
 
136
- Apache 2.0 © Dennis Wentzien 2025
138
+ Apache 2.0 © Dennis Wentzien 2026
package/dist/LICENSE CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright 2025 Dennis Wentzien
190
+ Copyright 2026 Dennis Wentzien
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
package/dist/NOTICE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2025 Dennis Wentzien
1
+ Copyright 2026 Dennis Wentzien
2
2
 
3
3
  This project is licensed under the Apache License, Version 2.0
4
4
  See LICENSE file for details.
@@ -5,16 +5,18 @@
5
5
  * @generated by @rexeus/typeweaver
6
6
  */
7
7
 
8
- import axios, { AxiosError } from "axios";
9
8
  import type {
10
9
  IHttpHeader,
11
10
  IHttpParam,
12
11
  IHttpQuery,
13
12
  IHttpResponse,
14
13
  } from "@rexeus/typeweaver-core";
14
+ import { NetworkError } from "./NetworkError";
15
+ import { PathParameterError } from "./PathParameterError";
15
16
  import { RequestCommand } from "./RequestCommand";
17
+ import { ResponseParseError } from "./ResponseParseError";
18
+ import type { NetworkErrorCode } from "./NetworkError";
16
19
  import type { ProcessResponseOptions } from "./RequestCommand";
17
- import type { AxiosHeaderValue, AxiosInstance, AxiosResponse } from "axios";
18
20
 
19
21
  /**
20
22
  * Configuration options for handling unknown responses.
@@ -25,14 +27,25 @@ export type UnknownResponseHandling = "throw" | "passthrough";
25
27
  * Configuration options for ApiClient initialization.
26
28
  */
27
29
  export type ApiClientProps = {
28
- /** Custom Axios instance with pre-configured defaults */
29
- axiosInstance?: AxiosInstance;
30
- /** Base URL for API requests. If not provided, must be set in axiosInstance */
31
- baseUrl?: string;
30
+ /** Custom fetch function for HTTP requests. Defaults to globalThis.fetch */
31
+ readonly fetchFn?: typeof globalThis.fetch;
32
+ /** Base URL for API requests */
33
+ readonly baseUrl: string;
32
34
  /** How to handle unknown responses. Defaults to "throw" */
33
- unknownResponseHandling?: UnknownResponseHandling;
35
+ readonly unknownResponseHandling?: UnknownResponseHandling;
34
36
  /** Predicate to determine if a status code represents success. Defaults to 2xx status codes */
35
- isSuccessStatusCode?: (statusCode: number) => boolean;
37
+ readonly isSuccessStatusCode?: (statusCode: number) => boolean;
38
+ /** Request timeout in milliseconds. When set, requests will be aborted after this duration */
39
+ readonly timeoutMs?: number;
40
+ };
41
+
42
+ const NETWORK_ERROR_MESSAGES: Readonly<
43
+ Partial<Record<NetworkErrorCode, string>>
44
+ > = {
45
+ ECONNREFUSED: "Connection refused",
46
+ ECONNRESET: "Connection reset by peer",
47
+ ENOTFOUND: "DNS lookup failed",
48
+ ETIMEDOUT: "Connection timed out",
36
49
  };
37
50
 
38
51
  /**
@@ -41,47 +54,38 @@ export type ApiClientProps = {
41
54
  * This class provides HTTP request execution with:
42
55
  * - Automatic path parameter substitution (`:param` style)
43
56
  * - Query string building with array support
44
- * - Header normalization (converts to Header-Case)
45
57
  * - Network error handling with specific error messages
46
58
  * - Integration with RequestCommand pattern for type safety
47
59
  */
48
60
  export abstract class ApiClient {
49
- /** The Axios instance used for HTTP requests */
50
- public readonly axiosInstance: AxiosInstance;
51
- /** The base URL for all API requests */
61
+ private readonly fetchFn: typeof globalThis.fetch;
52
62
  public readonly baseUrl: string;
53
- /** How to handle unknown responses */
54
63
  public readonly unknownResponseHandling: UnknownResponseHandling;
55
- /** Predicate to determine if a status code represents success */
56
64
  public readonly isSuccessStatusCode: (statusCode: number) => boolean;
65
+ private readonly timeoutMs: number | undefined;
57
66
 
58
- /**
59
- * Creates a new ApiClient instance.
60
- *
61
- * @param props - Configuration options
62
- * @throws {Error} If no base URL is provided in props or axios instance
63
- */
64
67
  protected constructor(props: ApiClientProps) {
65
- this.axiosInstance = props.axiosInstance ?? axios.create();
68
+ this.fetchFn = props.fetchFn ?? globalThis.fetch.bind(globalThis);
69
+ this.baseUrl = props.baseUrl;
66
70
 
67
- this.baseUrl = props.baseUrl ?? this.axiosInstance.defaults.baseURL ?? "";
68
71
  if (!this.baseUrl) {
69
- throw new Error(
70
- "Base URL must be provided either in axios instance or in constructor"
71
- );
72
+ throw new Error("Base URL must be provided");
72
73
  }
74
+
75
+ if (
76
+ props.timeoutMs !== undefined &&
77
+ (props.timeoutMs <= 0 || !Number.isFinite(props.timeoutMs))
78
+ ) {
79
+ throw new Error("timeoutMs must be a positive finite number");
80
+ }
81
+
73
82
  this.unknownResponseHandling = props.unknownResponseHandling ?? "throw";
74
83
  this.isSuccessStatusCode =
75
84
  props.isSuccessStatusCode ??
76
85
  ((statusCode: number) => statusCode >= 200 && statusCode < 300);
86
+ this.timeoutMs = props.timeoutMs;
77
87
  }
78
88
 
79
- /**
80
- * Gets the process response options for this client instance.
81
- *
82
- * @returns The configuration options for processing responses
83
- * @protected
84
- */
85
89
  protected get processResponseOptions(): ProcessResponseOptions {
86
90
  return {
87
91
  unknownResponseHandling: this.unknownResponseHandling,
@@ -89,80 +93,247 @@ export abstract class ApiClient {
89
93
  };
90
94
  }
91
95
 
92
- /**
93
- * Executes an HTTP request using the provided command.
94
- *
95
- * This method:
96
- * 1. Substitutes path parameters (e.g., `:id` with actual values)
97
- * 2. Builds the complete URL with query parameters
98
- * 3. Sends the HTTP request via Axios
99
- * 4. Normalizes the response format
100
- * 5. Handles network errors with specific error messages
101
- *
102
- * @param request - The request command containing all HTTP parameters
103
- * @returns Promise resolving to the HTTP response
104
- * @throws {Error} Network errors with specific messages (connection refused, timeout, etc.)
105
- * @protected
106
- */
107
96
  protected async execute(request: RequestCommand): Promise<IHttpResponse> {
108
97
  const { method, path, header, query, param, body } = request;
109
98
 
110
- const headers = this.createHeader(header);
111
99
  const pathWithParam = this.createPath(path, param);
112
- const url = this.createUrl(pathWithParam, query);
100
+ const relativeUrl = this.createUrl(pathWithParam, query);
101
+ const fullUrl = this.buildFullUrl(relativeUrl);
113
102
 
114
- try {
115
- const response = await this.axiosInstance.request({
116
- method,
117
- url,
118
- data: body,
119
- headers,
120
- baseURL: this.baseUrl,
121
- });
122
-
123
- return this.createResponse(response);
124
- } catch (error) {
125
- if (error instanceof AxiosError) {
126
- if (error.response) {
127
- return this.createResponse(error.response);
128
- }
129
-
130
- // TODO: improve network error handling
131
- if (error.code === "ECONNREFUSED") {
132
- throw new Error("Network error: Connection refused");
133
- }
134
- if (error.code === "ECONNRESET") {
135
- throw new Error("Network error: Connection reset by peer");
136
- }
137
- if (error.code === "ENOTFOUND") {
138
- throw new Error("Network error: DNS lookup failed");
139
- }
140
- if (error.code === "ETIMEDOUT") {
141
- throw new Error("Network error: Connection timed out");
142
- }
103
+ const response = await this.performFetch(method, fullUrl, {
104
+ method,
105
+ headers: this.flattenHeaders(header),
106
+ body: this.serializeBody(body),
107
+ signal:
108
+ this.timeoutMs !== undefined
109
+ ? AbortSignal.timeout(this.timeoutMs)
110
+ : undefined,
111
+ });
143
112
 
144
- throw new Error("Network error: Unknown error");
145
- }
113
+ return await this.createResponse(response, method, fullUrl);
114
+ }
146
115
 
147
- throw new Error(
148
- `Network error: ${error instanceof Error ? error.message : String(error)}`
149
- );
116
+ private async performFetch(
117
+ method: string,
118
+ url: string,
119
+ init: RequestInit
120
+ ): Promise<Response> {
121
+ try {
122
+ return await this.fetchFn(url, init);
123
+ } catch (error) {
124
+ throw this.createNetworkError(error, method, url);
150
125
  }
151
126
  }
152
127
 
153
- private createResponse(response: AxiosResponse): IHttpResponse {
128
+ private async createResponse(
129
+ response: Response,
130
+ method: string,
131
+ url: string
132
+ ): Promise<IHttpResponse> {
154
133
  const header: IHttpHeader = {};
155
- Object.entries(response.headers).forEach(([key, value]) => {
156
- this.addMultiValue(header, key, String(value));
134
+ response.headers.forEach((value, key) => {
135
+ header[key] = value;
157
136
  });
158
137
 
138
+ if (typeof response.headers.getSetCookie === "function") {
139
+ const cookies = response.headers.getSetCookie();
140
+ if (cookies.length > 1) {
141
+ header["set-cookie"] = cookies;
142
+ }
143
+ }
144
+
145
+ const body = await this.parseResponseBody(response, method, url);
146
+
159
147
  return {
160
- body: response.data,
148
+ body,
161
149
  header,
162
150
  statusCode: response.status,
163
151
  };
164
152
  }
165
153
 
154
+ private async readBody<T>(
155
+ read: () => Promise<T>,
156
+ response: Response,
157
+ method: string,
158
+ url: string
159
+ ): Promise<T> {
160
+ try {
161
+ return await read();
162
+ } catch (error) {
163
+ throw new ResponseParseError(
164
+ `Failed to read response body (${method} ${url})`,
165
+ response.status,
166
+ "",
167
+ { cause: error instanceof Error ? error : undefined }
168
+ );
169
+ }
170
+ }
171
+
172
+ private async parseResponseBody(
173
+ response: Response,
174
+ method: string,
175
+ url: string
176
+ ): Promise<unknown> {
177
+ if (response.status === 204 || response.status === 304) {
178
+ return undefined;
179
+ }
180
+
181
+ const contentType = response.headers.get("content-type");
182
+
183
+ if (this.isJsonContentType(contentType)) {
184
+ const text = await this.readBody(
185
+ () => response.text(),
186
+ response,
187
+ method,
188
+ url
189
+ );
190
+ if (!text) return undefined;
191
+ try {
192
+ return JSON.parse(text);
193
+ } catch (parseError) {
194
+ throw new ResponseParseError(
195
+ "Failed to parse JSON response",
196
+ response.status,
197
+ text.slice(0, 200),
198
+ {
199
+ cause: parseError instanceof Error ? parseError : undefined,
200
+ }
201
+ );
202
+ }
203
+ }
204
+
205
+ if (this.isTextContentType(contentType) || !contentType) {
206
+ const text = await this.readBody(
207
+ () => response.text(),
208
+ response,
209
+ method,
210
+ url
211
+ );
212
+ if (!text) return undefined;
213
+ return text;
214
+ }
215
+
216
+ return await this.readBody(
217
+ () => response.arrayBuffer(),
218
+ response,
219
+ method,
220
+ url
221
+ );
222
+ }
223
+
224
+ private isTextContentType(contentType: string | null): boolean {
225
+ if (!contentType) return false;
226
+ return contentType.includes("text/");
227
+ }
228
+
229
+ private createNetworkError(
230
+ error: unknown,
231
+ method: string,
232
+ url: string
233
+ ): NetworkError {
234
+ const context = `(${method} ${url})`;
235
+
236
+ if (
237
+ (error instanceof DOMException || error instanceof Error) &&
238
+ error.name === "TimeoutError"
239
+ ) {
240
+ return new NetworkError(
241
+ `Network error: Request timed out ${context}`,
242
+ "TIMEOUT",
243
+ method,
244
+ url,
245
+ { cause: error }
246
+ );
247
+ }
248
+
249
+ if (
250
+ (error instanceof DOMException || error instanceof Error) &&
251
+ error.name === "AbortError"
252
+ ) {
253
+ return new NetworkError(
254
+ `Network error: Request aborted ${context}`,
255
+ "ABORT",
256
+ method,
257
+ url,
258
+ { cause: error }
259
+ );
260
+ }
261
+
262
+ if (error instanceof TypeError) {
263
+ const cause = (error as TypeError & { cause?: { code?: string } }).cause;
264
+ const code = cause?.code;
265
+
266
+ if (code && code in NETWORK_ERROR_MESSAGES) {
267
+ const message = NETWORK_ERROR_MESSAGES[code as NetworkErrorCode];
268
+ return new NetworkError(
269
+ `Network error: ${message} ${context}`,
270
+ code as NetworkErrorCode,
271
+ method,
272
+ url,
273
+ { cause: error }
274
+ );
275
+ }
276
+ }
277
+
278
+ return new NetworkError(
279
+ `Network error: ${error instanceof Error ? error.message : String(error)} ${context}`,
280
+ "UNKNOWN",
281
+ method,
282
+ url,
283
+ { cause: error }
284
+ );
285
+ }
286
+
287
+ private flattenHeaders(
288
+ header: IHttpHeader
289
+ ): Record<string, string> | undefined {
290
+ if (header === undefined) return undefined;
291
+
292
+ const flattened: Record<string, string> = {};
293
+ for (const [key, value] of Object.entries(header)) {
294
+ flattened[key] = Array.isArray(value) ? value.join(", ") : value;
295
+ }
296
+ return flattened;
297
+ }
298
+
299
+ private serializeBody(
300
+ body: unknown
301
+ ): NonNullable<RequestInit["body"]> | undefined {
302
+ if (body === null || body === undefined) return undefined;
303
+ if (typeof body === "string") return body;
304
+ if (this.isNativeBody(body))
305
+ return body as NonNullable<RequestInit["body"]>;
306
+ return JSON.stringify(body);
307
+ }
308
+
309
+ private isNativeBody(body: unknown): boolean {
310
+ return (
311
+ body instanceof Blob ||
312
+ body instanceof ArrayBuffer ||
313
+ body instanceof FormData ||
314
+ body instanceof URLSearchParams ||
315
+ body instanceof ReadableStream ||
316
+ ArrayBuffer.isView(body)
317
+ );
318
+ }
319
+
320
+ private isJsonContentType(contentType: string | null): boolean {
321
+ if (!contentType) return false;
322
+ return (
323
+ contentType.includes("application/json") || contentType.includes("+json")
324
+ );
325
+ }
326
+
327
+ private buildFullUrl(relativePath: string): string {
328
+ const base = this.baseUrl.endsWith("/")
329
+ ? this.baseUrl.slice(0, -1)
330
+ : this.baseUrl;
331
+ const path = relativePath.startsWith("/")
332
+ ? relativePath
333
+ : `/${relativePath}`;
334
+ return `${base}${path}`;
335
+ }
336
+
166
337
  private createPath(path: string, param?: IHttpParam): string {
167
338
  if (!param) {
168
339
  return path;
@@ -172,8 +343,10 @@ export abstract class ApiClient {
172
343
  const result = acc.replace(`:${key}`, encodeURIComponent(value));
173
344
 
174
345
  if (result === acc) {
175
- throw new Error(
176
- `Path parameter '${key}' is not found in path '${path}'`
346
+ throw new PathParameterError(
347
+ `Path parameter '${key}' is not found in path '${path}'`,
348
+ key,
349
+ path
177
350
  );
178
351
  }
179
352
 
@@ -184,9 +357,7 @@ export abstract class ApiClient {
184
357
  private createUrl(path: string, query?: IHttpQuery): string {
185
358
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
186
359
  const queryString = this.buildQueryString(query);
187
- return queryString
188
- ? `${normalizedPath}?${queryString}`
189
- : normalizedPath;
360
+ return queryString ? `${normalizedPath}?${queryString}` : normalizedPath;
190
361
  }
191
362
 
192
363
  private buildQueryString(query?: IHttpQuery): string {
@@ -211,29 +382,4 @@ export abstract class ApiClient {
211
382
  }
212
383
  return params.toString();
213
384
  }
214
-
215
- private createHeader(header: any): any {
216
- return header;
217
- }
218
-
219
- private addMultiValue(
220
- record: Record<string, string | string[]>,
221
- key: string,
222
- value: AxiosHeaderValue
223
- ): void {
224
- const existing = record[key];
225
- const preparedValue = Array.isArray(value)
226
- ? value.map(String)
227
- : [String(value)];
228
- if (existing) {
229
- if (Array.isArray(existing)) {
230
- existing.push(...preparedValue);
231
- } else {
232
- record[key] = [existing, ...preparedValue];
233
- }
234
- } else {
235
- record[key] =
236
- preparedValue.length > 1 ? preparedValue : (preparedValue[0] as string);
237
- }
238
- }
239
385
  }
@@ -0,0 +1,39 @@
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
+ /**
9
+ * Discriminated error codes for network-level failures.
10
+ */
11
+ export type NetworkErrorCode =
12
+ | "TIMEOUT"
13
+ | "ABORT"
14
+ | "ECONNREFUSED"
15
+ | "ECONNRESET"
16
+ | "ENOTFOUND"
17
+ | "ETIMEDOUT"
18
+ | "UNKNOWN";
19
+
20
+ /**
21
+ * Typed error for network-level failures during HTTP requests.
22
+ *
23
+ * Provides a discriminated `code` property for programmatic error handling
24
+ * instead of message string parsing. Thrown by ApiClient when the underlying
25
+ * fetch call fails before receiving a response.
26
+ */
27
+ export class NetworkError extends Error {
28
+ public override readonly name = "NetworkError";
29
+
30
+ public constructor(
31
+ message: string,
32
+ public readonly code: NetworkErrorCode,
33
+ public readonly method: string,
34
+ public readonly url: string,
35
+ options?: ErrorOptions
36
+ ) {
37
+ super(message, options);
38
+ }
39
+ }
@@ -0,0 +1,26 @@
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
+ /**
9
+ * Typed error for path parameter substitution failures.
10
+ *
11
+ * Thrown when a path parameter key does not match any placeholder in the
12
+ * URL path pattern. Exposes `paramName` and `path` properties for
13
+ * programmatic error handling.
14
+ */
15
+ export class PathParameterError extends Error {
16
+ public override readonly name = "PathParameterError";
17
+
18
+ public constructor(
19
+ message: string,
20
+ public readonly paramName: string,
21
+ public readonly path: string,
22
+ options?: ErrorOptions
23
+ ) {
24
+ super(message, options);
25
+ }
26
+ }
@@ -47,8 +47,7 @@ export abstract class RequestCommand<
47
47
  Param extends IHttpParam = IHttpParam | undefined,
48
48
  Query extends IHttpQuery = IHttpQuery | undefined,
49
49
  Body extends IHttpBody = IHttpBody | undefined,
50
- > implements IHttpRequest
51
- {
50
+ > implements IHttpRequest {
52
51
  /** The HTTP method for this request */
53
52
  public readonly method!: HttpMethod;
54
53
  /** The URL path pattern with parameter placeholders (e.g., '/users/:id') */
@@ -0,0 +1,26 @@
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
+ /**
9
+ * Typed error for response body parsing failures.
10
+ *
11
+ * Thrown when a JSON response body cannot be parsed. Provides structured
12
+ * metadata via `statusCode` and `bodyPreview` properties for diagnostics
13
+ * without relying on message string parsing.
14
+ */
15
+ export class ResponseParseError extends Error {
16
+ public override readonly name = "ResponseParseError";
17
+
18
+ public constructor(
19
+ message: string,
20
+ public readonly statusCode: number,
21
+ public readonly bodyPreview: string,
22
+ options?: ErrorOptions
23
+ ) {
24
+ super(message, options);
25
+ }
26
+ }
package/dist/lib/index.ts CHANGED
@@ -6,4 +6,7 @@
6
6
  */
7
7
 
8
8
  export * from "./ApiClient";
9
+ export * from "./NetworkError";
10
+ export * from "./PathParameterError";
9
11
  export * from "./RequestCommand";
12
+ export * from "./ResponseParseError";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rexeus/typeweaver-clients",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
4
4
  "description": "Generates HTTP clients directly from your API definitions. Powered by Typeweaver 🧵✨",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -47,22 +47,20 @@
47
47
  },
48
48
  "homepage": "https://github.com/rexeus/typeweaver#readme",
49
49
  "peerDependencies": {
50
- "axios": "^1.13.0",
51
50
  "zod": "^4.3.0",
52
- "@rexeus/typeweaver-core": "^0.4.2",
53
- "@rexeus/typeweaver-gen": "^0.4.2"
51
+ "@rexeus/typeweaver-core": "^0.5.1",
52
+ "@rexeus/typeweaver-gen": "^0.5.1"
54
53
  },
55
54
  "devDependencies": {
56
55
  "@hono/node-server": "^1.19.7",
57
- "axios": "^1.13.2",
58
56
  "test-utils": "file:../test-utils",
59
57
  "zod": "^4.3.6",
60
- "@rexeus/typeweaver-core": "^0.4.2",
61
- "@rexeus/typeweaver-gen": "^0.4.2"
58
+ "@rexeus/typeweaver-core": "^0.5.1",
59
+ "@rexeus/typeweaver-gen": "^0.5.1"
62
60
  },
63
61
  "dependencies": {
64
62
  "case": "^1.6.3",
65
- "@rexeus/typeweaver-zod-to-ts": "^0.4.2"
63
+ "@rexeus/typeweaver-zod-to-ts": "^0.5.1"
66
64
  },
67
65
  "scripts": {
68
66
  "typecheck": "tsc --noEmit",