@firtoz/hono-fetcher 2.3.2 → 2.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firtoz/hono-fetcher",
3
- "version": "2.3.2",
3
+ "version": "2.4.1",
4
4
  "description": "Type-safe Hono API client with full TypeScript inference for routes, params, and payloads",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -23,7 +23,7 @@
23
23
  "README.md"
24
24
  ],
25
25
  "scripts": {
26
- "typecheck": "tsc --noEmit -p ./tsconfig.json",
26
+ "typecheck": "tsgo --noEmit -p ./tsconfig.json",
27
27
  "lint": "biome check --write src",
28
28
  "lint:ci": "biome ci src",
29
29
  "format": "biome format src --write",
@@ -52,8 +52,8 @@
52
52
  "url": "https://github.com/firtoz/fullstack-toolkit/issues"
53
53
  },
54
54
  "peerDependencies": {
55
- "@cloudflare/workers-types": "^4.20251228.0",
56
- "hono": "^4.11.4"
55
+ "@cloudflare/workers-types": "^4.20260329.1",
56
+ "hono": "^4.12.9"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=18.0.0"
@@ -62,9 +62,9 @@
62
62
  "access": "public"
63
63
  },
64
64
  "devDependencies": {
65
- "@hono/node-server": "^1.19.9",
65
+ "@hono/node-server": "^1.19.11",
66
66
  "@hono/zod-validator": "^0.7.6",
67
- "bun-types": "^1.3.6",
68
- "zod": "^4.3.5"
67
+ "bun-types": "^1.3.11",
68
+ "zod": "^4.3.6"
69
69
  }
70
70
  }
@@ -33,14 +33,59 @@ type HasPathParams<T extends string> = T extends `${string}:${string}`
33
33
  ? true
34
34
  : false;
35
35
 
36
+ /**
37
+ * Values allowed in the optional `query` object on fetcher requests.
38
+ * `null` and `undefined` entries are omitted from the serialized query string.
39
+ */
40
+ export type HonoFetcherQueryParamValue = string | number | boolean;
41
+
42
+ export type HonoFetcherQueryParams = Record<
43
+ string,
44
+ HonoFetcherQueryParamValue | null | undefined
45
+ >;
46
+
47
+ function appendQueryString(
48
+ url: string,
49
+ query?: HonoFetcherQueryParams,
50
+ ): string {
51
+ if (!query) {
52
+ return url;
53
+ }
54
+ const searchParams = new URLSearchParams();
55
+ for (const [key, value] of Object.entries(query)) {
56
+ if (value === undefined || value === null) {
57
+ continue;
58
+ }
59
+ searchParams.append(key, String(value));
60
+ }
61
+ const serialized = searchParams.toString();
62
+ if (!serialized) {
63
+ return url;
64
+ }
65
+ const separator = url.includes("?") ? "&" : "?";
66
+ return `${url}${separator}${serialized}`;
67
+ }
68
+
69
+ /**
70
+ * `RequestInit` fields that honoFetcher sets must not be overwritten by spreading `...init` last.
71
+ */
72
+ function restOfRequestInit(
73
+ init: RequestInit,
74
+ ): Omit<RequestInit, "headers" | "body" | "method"> {
75
+ const { headers: _h, body: _b, method: _m, ...rest } = init;
76
+ return rest;
77
+ }
78
+
36
79
  type FetcherParams<SchemaPath extends string> =
37
80
  HasPathParams<SchemaPath> extends true
38
81
  ? {
39
82
  params: ParsePathParams<SchemaPath>;
83
+ query?: HonoFetcherQueryParams;
40
84
  init?: RequestInit;
41
85
  }
42
86
  : {
43
87
  params?: never;
88
+ query?: HonoFetcherQueryParams;
44
89
  init?: RequestInit;
45
90
  };
46
91
 
@@ -136,7 +181,7 @@ const createMethodFetcher = <T extends Hono, M extends HttpMethod>(
136
181
  return (async (request) => {
137
182
  let finalUrl: string = request.url;
138
183
 
139
- const { init = {}, params } = request;
184
+ const { init = {}, params, query } = request;
140
185
 
141
186
  if (params && typeof params === "object") {
142
187
  finalUrl = Object.entries(params).reduce((acc, [key, value]) => {
@@ -144,6 +189,8 @@ const createMethodFetcher = <T extends Hono, M extends HttpMethod>(
144
189
  }, finalUrl);
145
190
  }
146
191
 
192
+ finalUrl = appendQueryString(finalUrl, query);
193
+
147
194
  const requestAsOptionalFormBody = request as {
148
195
  form?: unknown;
149
196
  body?: unknown;
@@ -172,10 +219,10 @@ const createMethodFetcher = <T extends Hono, M extends HttpMethod>(
172
219
 
173
220
  try {
174
221
  return await fetcher(finalUrl, {
222
+ ...restOfRequestInit(init),
175
223
  method: method.toUpperCase(),
176
224
  headers: newHeaders,
177
225
  ...(body ? { body } : {}),
178
- ...init,
179
226
  });
180
227
  } catch (error) {
181
228
  console.error(`Error ${method}ing`, error);
@@ -193,7 +240,7 @@ const createWebSocketFetcher = <T extends Hono>(
193
240
  return (async (request) => {
194
241
  let finalUrl: string = request.url;
195
242
 
196
- const { init = {}, params, config } = request;
243
+ const { init = {}, params, query, config } = request;
197
244
  const autoAccept = config?.autoAccept ?? true; // Default to true
198
245
 
199
246
  if (params && typeof params === "object") {
@@ -202,6 +249,8 @@ const createWebSocketFetcher = <T extends Hono>(
202
249
  }, finalUrl);
203
250
  }
204
251
 
252
+ finalUrl = appendQueryString(finalUrl, query);
253
+
205
254
  const newHeaders = new Headers(
206
255
  init.headers as unknown as ConstructorParameters<typeof Headers>[0],
207
256
  );
@@ -209,9 +258,9 @@ const createWebSocketFetcher = <T extends Hono>(
209
258
 
210
259
  try {
211
260
  const response = await fetcher(finalUrl, {
261
+ ...restOfRequestInit(init),
212
262
  method: "GET",
213
263
  headers: newHeaders,
214
- ...init,
215
264
  });
216
265
 
217
266
  // Auto-accept the WebSocket if configured (default: true)
package/src/index.ts CHANGED
@@ -14,6 +14,8 @@ export {
14
14
  // Core fetcher functionality
15
15
  export {
16
16
  type BaseTypedHonoFetcher,
17
+ type HonoFetcherQueryParamValue,
18
+ type HonoFetcherQueryParams,
17
19
  type HonoSchemaKeys,
18
20
  type HttpMethod,
19
21
  honoFetcher,