@kizunajs/fetch 2.0.0-beta.1 → 2.0.0-beta.10

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/dist/server.cjs CHANGED
@@ -27,6 +27,15 @@ var TypeCollector = class {
27
27
  }
28
28
  };
29
29
  const quote = (value) => JSON.stringify(value);
30
+ /**
31
+ * A literal as the type the JSON carries, so `z.literal(true)` is `true`.
32
+ */
33
+ const literalType = (value) => {
34
+ if (typeof value === "string") return quote(value);
35
+ if (typeof value === "bigint") return `${value}n`;
36
+ if (value === void 0) return "undefined";
37
+ return String(value);
38
+ };
30
39
  const indent$1 = (text, depth = 1) => text.split("\n").map((line) => line.length > 0 ? " ".repeat(depth) + line : line).join("\n");
31
40
  /**
32
41
  * A property name, quoted only when it is not a plain identifier.
@@ -159,24 +168,27 @@ const typeOf = (schema, collector, hint) => {
159
168
  const def = (0, kizunajs_generator.readDef)(schema);
160
169
  if (def.type === "nullable" && def.innerType) return `${typeOf(def.innerType, collector, hint)} | null`;
161
170
  if (def.type === "nullish" && def.innerType) return `${typeOf(def.innerType, collector, hint)} | null`;
162
- if (def.innerType && def.type !== "object") {
163
- const { inner } = (0, kizunajs_generator.unwrapOptionalWrappers)(schema);
164
- if (inner !== schema) return typeOf(inner, collector, hint);
165
- return typeOf(def.innerType, collector, hint);
166
- }
171
+ if (def.innerType && def.type !== "object") return typeOf(def.innerType, collector, hint);
167
172
  if (def.type === "pipe") {
168
173
  const side = def.out ?? def.in;
169
174
  return side ? typeOf(side, collector, hint) : "unknown";
170
175
  }
171
176
  const modelName = (0, kizunajs_generator.readMetaId)(schema);
172
- if (modelName !== void 0 && def.type === "object") {
177
+ if (modelName !== void 0) {
173
178
  if (collector.claim(modelName)) collector.add({
174
179
  name: modelName,
175
180
  description: (0, kizunajs_generator.readMetaDescription)(schema),
176
- body: objectBody(schema, collector, modelName)
181
+ body: structuralType(schema, collector, modelName)
177
182
  });
178
183
  return modelName;
179
184
  }
185
+ return structuralType(schema, collector, hint);
186
+ };
187
+ /**
188
+ * The type a schema describes by its shape, its name already spent by the caller.
189
+ */
190
+ const structuralType = (schema, collector, hint) => {
191
+ const def = (0, kizunajs_generator.readDef)(schema);
180
192
  switch (def.type) {
181
193
  case "string": return "string";
182
194
  case "number":
@@ -192,11 +204,11 @@ const typeOf = (schema, collector, hint) => {
192
204
  case "undefined": return "undefined";
193
205
  case "literal": {
194
206
  const values = def.values ?? [];
195
- return values.length > 0 ? values.map((value) => quote(String(value))).join(" | ") : "never";
207
+ return values.length > 0 ? values.map(literalType).join(" | ") : "never";
196
208
  }
197
209
  case "enum": {
198
210
  const values = Object.values(def.entries ?? {});
199
- return values.length > 0 ? values.map((value) => quote(String(value))).join(" | ") : "never";
211
+ return values.length > 0 ? values.map(literalType).join(" | ") : "never";
200
212
  }
201
213
  case "array": return def.element ? `Array<${typeOf(def.element, collector, `${hint}Item`)}>` : "unknown[]";
202
214
  case "object": return objectBody(schema, collector, hint);
@@ -247,7 +259,7 @@ const exampleCall = (routeKey, route) => {
247
259
  entries.push(`params: {\n${indent(fields.join("\n"))}\n},`);
248
260
  }
249
261
  if (route.query && requiresArgument(route.query)) entries.push(`query: ${sampleObject(route.query)},`);
250
- if (route.body && requiresArgument(route.body)) entries.push(`body: ${sampleValue(route.body)},`);
262
+ if (route.body && !(0, kizunajs_generator.isVoidSchema)(route.body) && requiresArgument(route.body)) entries.push(`body: ${sampleValue(route.body)},`);
251
263
  return `const result = await client.${routeKey}(${entries.length > 0 ? `{\n${indent(entries.join("\n"))}\n}` : ""});`;
252
264
  };
253
265
  /**
@@ -279,7 +291,7 @@ const routeDoc = (routeKey, route) => {
279
291
  lines.push("@example", exampleCall(routeKey, route));
280
292
  return docComment(lines);
281
293
  };
282
- const emitRoute = (routeKey, key, route, collector) => {
294
+ const emitRoute = (routeKey, key, route, collector, namespaceName) => {
283
295
  const namespace = routeKey.split(".").map(kizunajs_generator.toPascalCase).join("");
284
296
  const members = [];
285
297
  const args = [];
@@ -287,19 +299,19 @@ const emitRoute = (routeKey, key, route, collector) => {
287
299
  if (params.length > 0) {
288
300
  const body = route.pathParams ? typeOf(route.pathParams, collector, `${namespace}Params`) : `{\n${indent(params.map((name) => `${name}: string;`).join("\n"))}\n}`;
289
301
  members.push(`export type Params = ${body};`);
290
- args.push(`params: API.${namespace}.Params`);
302
+ args.push(`params: ${namespaceName}.${namespace}.Params`);
291
303
  }
292
304
  if (route.query) {
293
305
  members.push(`export type Query = ${typeOf(route.query, collector, `${namespace}Query`)};`);
294
- args.push(`query?: API.${namespace}.Query`);
306
+ args.push(`query?: ${namespaceName}.${namespace}.Query`);
295
307
  }
296
- if (route.body) {
308
+ if (route.body && !(0, kizunajs_generator.isVoidSchema)(route.body)) {
297
309
  members.push(`export type Body = ${typeOf(route.body, collector, `${namespace}Body`)};`);
298
- args.push(`body: API.${namespace}.Body`);
310
+ args.push(`body: ${namespaceName}.${namespace}.Body`);
299
311
  }
300
312
  if (route.headers) {
301
313
  members.push(`export type Headers = ${typeOf(route.headers, collector, `${namespace}Headers`)};`);
302
- args.push(`headers?: API.${namespace}.Headers`);
314
+ args.push(`headers?: ${namespaceName}.${namespace}.Headers`);
303
315
  } else args.push("headers?: Record<string, string>");
304
316
  args.push("fetchOptions?: RequestInit");
305
317
  const validates = route.body !== void 0 || route.query !== void 0;
@@ -323,13 +335,13 @@ const emitRoute = (routeKey, key, route, collector) => {
323
335
  const streams = Object.values(route.responses).some((response) => (0, kizunajs_generator.isStreamResponse)(response));
324
336
  return {
325
337
  namespace,
326
- signature: `${routeDoc(routeKey, route)}${key}: ClientMethod<'${route.method}', ${streams}, ${argsType}, API.${namespace}.Result>;`,
338
+ signature: `${routeDoc(routeKey, route)}${key}: ClientMethod<'${route.method}', ${streams}, ${argsType}, ${namespaceName}.${namespace}.Result>;`,
327
339
  declaration: `export namespace ${namespace} {\n${indent(members.join("\n\n"))}\n}`,
328
340
  table: `${key}: {\n${indent(tableEntries.map((entry) => `${entry},`).join("\n"))}\n},`
329
341
  };
330
342
  };
331
343
  const isRoute = (value) => !!value && typeof value === "object" && typeof value.method === "string";
332
- const emitTree = (routes, prefix, collector) => {
344
+ const emitTree = (routes, prefix, collector, namespaceName) => {
333
345
  const signatures = [];
334
346
  const tables = [];
335
347
  const declarations = [];
@@ -337,14 +349,14 @@ const emitTree = (routes, prefix, collector) => {
337
349
  const node = routes[key];
338
350
  const routeKey = prefix ? `${prefix}.${key}` : key;
339
351
  if (isRoute(node)) {
340
- const emitted = emitRoute(routeKey, key, node, collector);
352
+ const emitted = emitRoute(routeKey, key, node, collector, namespaceName);
341
353
  signatures.push(emitted.signature);
342
354
  tables.push(emitted.table);
343
355
  declarations.push(emitted.declaration);
344
356
  continue;
345
357
  }
346
358
  if (node && typeof node === "object") {
347
- const group = emitTree(node, routeKey, collector);
359
+ const group = emitTree(node, routeKey, collector, namespaceName);
348
360
  signatures.push(`${key}: {\n${indent(group.signatures)}\n};`);
349
361
  tables.push(`${key}: {\n${indent(group.table)}\n},`);
350
362
  declarations.push(...group.declarations);
@@ -376,9 +388,9 @@ const emitRequestContext = (contract, collector) => {
376
388
  return fields.length > 0 ? `export interface RequestContext {\n${indent(fields.join("\n"))}\n}` : void 0;
377
389
  };
378
390
  const generateFetchClient = (contract, options = {}) => {
379
- const { runtimeModule = "@kizunajs/fetch", regenerateCommand = "kizuna generate", source } = options;
391
+ const { namespace: namespaceName = "API", runtimeModule = "@kizunajs/fetch", regenerateCommand = "kizuna generate", source } = options;
380
392
  const collector = new TypeCollector();
381
- const tree = emitTree(contract.routes, "", collector);
393
+ const tree = emitTree(contract.routes, "", collector, namespaceName);
382
394
  const api = [...collector.all().map((model) => {
383
395
  return `${model.description ? `/**\n * ${model.description}\n */\n` : ""}export type ${model.name} = ${model.body};`;
384
396
  }), ...tree.declarations].join("\n\n");
@@ -394,7 +406,7 @@ ${[
394
406
  */
395
407
  import { createGeneratedClient, type ClientConfig, type ClientMethod, type GeneratedRoutes } from '${runtimeModule}';
396
408
 
397
- export namespace API {
409
+ export namespace ${namespaceName} {
398
410
  ${indent(api)}
399
411
  }
400
412
 
package/dist/server.d.cts CHANGED
@@ -5,6 +5,13 @@ import { ApiDefinition, ClientTarget } from "kizunajs";
5
5
  * What a generated client is called and where its runtime comes from.
6
6
  */
7
7
  interface FetchClientOptions {
8
+ /**
9
+ * Name of the generated namespace holding every model and every route's
10
+ * `Params`, `Query`, `Body`, `Headers` and `Result`.
11
+ *
12
+ * @default 'API'
13
+ */
14
+ namespace?: string;
8
15
  /**
9
16
  * Module the generated file imports its runtime from.
10
17
  *
package/dist/server.d.mts CHANGED
@@ -5,6 +5,13 @@ import { ApiDefinition, ClientTarget } from "kizunajs";
5
5
  * What a generated client is called and where its runtime comes from.
6
6
  */
7
7
  interface FetchClientOptions {
8
+ /**
9
+ * Name of the generated namespace holding every model and every route's
10
+ * `Params`, `Query`, `Body`, `Headers` and `Result`.
11
+ *
12
+ * @default 'API'
13
+ */
14
+ namespace?: string;
8
15
  /**
9
16
  * Module the generated file imports its runtime from.
10
17
  *
package/dist/server.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ValidationErrorSchema } from "kizunajs/schemas";
2
- import { isBinarySchema, isFileSchema, isStreamResponse, readDef, readDeprecation, readDiscriminatedUnion, readMetaDescription, readMetaExamples, readMetaId, readObjectShape, resolveResponseBody, resolveResponseHeaders, streamContentType, toPascalCase, unwrapOptionalWrappers } from "kizunajs/generator";
2
+ import { isBinarySchema, isFileSchema, isStreamResponse, isVoidSchema, readDef, readDeprecation, readDiscriminatedUnion, readMetaDescription, readMetaExamples, readMetaId, readObjectShape, resolveResponseBody, resolveResponseHeaders, streamContentType, toPascalCase, unwrapOptionalWrappers } from "kizunajs/generator";
3
3
  //#region src/zod-to-typescript.ts
4
4
  /**
5
5
  * Collects the named types a walk produces, so a model shared by many routes is
@@ -26,6 +26,15 @@ var TypeCollector = class {
26
26
  }
27
27
  };
28
28
  const quote = (value) => JSON.stringify(value);
29
+ /**
30
+ * A literal as the type the JSON carries, so `z.literal(true)` is `true`.
31
+ */
32
+ const literalType = (value) => {
33
+ if (typeof value === "string") return quote(value);
34
+ if (typeof value === "bigint") return `${value}n`;
35
+ if (value === void 0) return "undefined";
36
+ return String(value);
37
+ };
29
38
  const indent$1 = (text, depth = 1) => text.split("\n").map((line) => line.length > 0 ? " ".repeat(depth) + line : line).join("\n");
30
39
  /**
31
40
  * A property name, quoted only when it is not a plain identifier.
@@ -158,24 +167,27 @@ const typeOf = (schema, collector, hint) => {
158
167
  const def = readDef(schema);
159
168
  if (def.type === "nullable" && def.innerType) return `${typeOf(def.innerType, collector, hint)} | null`;
160
169
  if (def.type === "nullish" && def.innerType) return `${typeOf(def.innerType, collector, hint)} | null`;
161
- if (def.innerType && def.type !== "object") {
162
- const { inner } = unwrapOptionalWrappers(schema);
163
- if (inner !== schema) return typeOf(inner, collector, hint);
164
- return typeOf(def.innerType, collector, hint);
165
- }
170
+ if (def.innerType && def.type !== "object") return typeOf(def.innerType, collector, hint);
166
171
  if (def.type === "pipe") {
167
172
  const side = def.out ?? def.in;
168
173
  return side ? typeOf(side, collector, hint) : "unknown";
169
174
  }
170
175
  const modelName = readMetaId(schema);
171
- if (modelName !== void 0 && def.type === "object") {
176
+ if (modelName !== void 0) {
172
177
  if (collector.claim(modelName)) collector.add({
173
178
  name: modelName,
174
179
  description: readMetaDescription(schema),
175
- body: objectBody(schema, collector, modelName)
180
+ body: structuralType(schema, collector, modelName)
176
181
  });
177
182
  return modelName;
178
183
  }
184
+ return structuralType(schema, collector, hint);
185
+ };
186
+ /**
187
+ * The type a schema describes by its shape, its name already spent by the caller.
188
+ */
189
+ const structuralType = (schema, collector, hint) => {
190
+ const def = readDef(schema);
179
191
  switch (def.type) {
180
192
  case "string": return "string";
181
193
  case "number":
@@ -191,11 +203,11 @@ const typeOf = (schema, collector, hint) => {
191
203
  case "undefined": return "undefined";
192
204
  case "literal": {
193
205
  const values = def.values ?? [];
194
- return values.length > 0 ? values.map((value) => quote(String(value))).join(" | ") : "never";
206
+ return values.length > 0 ? values.map(literalType).join(" | ") : "never";
195
207
  }
196
208
  case "enum": {
197
209
  const values = Object.values(def.entries ?? {});
198
- return values.length > 0 ? values.map((value) => quote(String(value))).join(" | ") : "never";
210
+ return values.length > 0 ? values.map(literalType).join(" | ") : "never";
199
211
  }
200
212
  case "array": return def.element ? `Array<${typeOf(def.element, collector, `${hint}Item`)}>` : "unknown[]";
201
213
  case "object": return objectBody(schema, collector, hint);
@@ -246,7 +258,7 @@ const exampleCall = (routeKey, route) => {
246
258
  entries.push(`params: {\n${indent(fields.join("\n"))}\n},`);
247
259
  }
248
260
  if (route.query && requiresArgument(route.query)) entries.push(`query: ${sampleObject(route.query)},`);
249
- if (route.body && requiresArgument(route.body)) entries.push(`body: ${sampleValue(route.body)},`);
261
+ if (route.body && !isVoidSchema(route.body) && requiresArgument(route.body)) entries.push(`body: ${sampleValue(route.body)},`);
250
262
  return `const result = await client.${routeKey}(${entries.length > 0 ? `{\n${indent(entries.join("\n"))}\n}` : ""});`;
251
263
  };
252
264
  /**
@@ -278,7 +290,7 @@ const routeDoc = (routeKey, route) => {
278
290
  lines.push("@example", exampleCall(routeKey, route));
279
291
  return docComment(lines);
280
292
  };
281
- const emitRoute = (routeKey, key, route, collector) => {
293
+ const emitRoute = (routeKey, key, route, collector, namespaceName) => {
282
294
  const namespace = routeKey.split(".").map(toPascalCase).join("");
283
295
  const members = [];
284
296
  const args = [];
@@ -286,19 +298,19 @@ const emitRoute = (routeKey, key, route, collector) => {
286
298
  if (params.length > 0) {
287
299
  const body = route.pathParams ? typeOf(route.pathParams, collector, `${namespace}Params`) : `{\n${indent(params.map((name) => `${name}: string;`).join("\n"))}\n}`;
288
300
  members.push(`export type Params = ${body};`);
289
- args.push(`params: API.${namespace}.Params`);
301
+ args.push(`params: ${namespaceName}.${namespace}.Params`);
290
302
  }
291
303
  if (route.query) {
292
304
  members.push(`export type Query = ${typeOf(route.query, collector, `${namespace}Query`)};`);
293
- args.push(`query?: API.${namespace}.Query`);
305
+ args.push(`query?: ${namespaceName}.${namespace}.Query`);
294
306
  }
295
- if (route.body) {
307
+ if (route.body && !isVoidSchema(route.body)) {
296
308
  members.push(`export type Body = ${typeOf(route.body, collector, `${namespace}Body`)};`);
297
- args.push(`body: API.${namespace}.Body`);
309
+ args.push(`body: ${namespaceName}.${namespace}.Body`);
298
310
  }
299
311
  if (route.headers) {
300
312
  members.push(`export type Headers = ${typeOf(route.headers, collector, `${namespace}Headers`)};`);
301
- args.push(`headers?: API.${namespace}.Headers`);
313
+ args.push(`headers?: ${namespaceName}.${namespace}.Headers`);
302
314
  } else args.push("headers?: Record<string, string>");
303
315
  args.push("fetchOptions?: RequestInit");
304
316
  const validates = route.body !== void 0 || route.query !== void 0;
@@ -322,13 +334,13 @@ const emitRoute = (routeKey, key, route, collector) => {
322
334
  const streams = Object.values(route.responses).some((response) => isStreamResponse(response));
323
335
  return {
324
336
  namespace,
325
- signature: `${routeDoc(routeKey, route)}${key}: ClientMethod<'${route.method}', ${streams}, ${argsType}, API.${namespace}.Result>;`,
337
+ signature: `${routeDoc(routeKey, route)}${key}: ClientMethod<'${route.method}', ${streams}, ${argsType}, ${namespaceName}.${namespace}.Result>;`,
326
338
  declaration: `export namespace ${namespace} {\n${indent(members.join("\n\n"))}\n}`,
327
339
  table: `${key}: {\n${indent(tableEntries.map((entry) => `${entry},`).join("\n"))}\n},`
328
340
  };
329
341
  };
330
342
  const isRoute = (value) => !!value && typeof value === "object" && typeof value.method === "string";
331
- const emitTree = (routes, prefix, collector) => {
343
+ const emitTree = (routes, prefix, collector, namespaceName) => {
332
344
  const signatures = [];
333
345
  const tables = [];
334
346
  const declarations = [];
@@ -336,14 +348,14 @@ const emitTree = (routes, prefix, collector) => {
336
348
  const node = routes[key];
337
349
  const routeKey = prefix ? `${prefix}.${key}` : key;
338
350
  if (isRoute(node)) {
339
- const emitted = emitRoute(routeKey, key, node, collector);
351
+ const emitted = emitRoute(routeKey, key, node, collector, namespaceName);
340
352
  signatures.push(emitted.signature);
341
353
  tables.push(emitted.table);
342
354
  declarations.push(emitted.declaration);
343
355
  continue;
344
356
  }
345
357
  if (node && typeof node === "object") {
346
- const group = emitTree(node, routeKey, collector);
358
+ const group = emitTree(node, routeKey, collector, namespaceName);
347
359
  signatures.push(`${key}: {\n${indent(group.signatures)}\n};`);
348
360
  tables.push(`${key}: {\n${indent(group.table)}\n},`);
349
361
  declarations.push(...group.declarations);
@@ -375,9 +387,9 @@ const emitRequestContext = (contract, collector) => {
375
387
  return fields.length > 0 ? `export interface RequestContext {\n${indent(fields.join("\n"))}\n}` : void 0;
376
388
  };
377
389
  const generateFetchClient = (contract, options = {}) => {
378
- const { runtimeModule = "@kizunajs/fetch", regenerateCommand = "kizuna generate", source } = options;
390
+ const { namespace: namespaceName = "API", runtimeModule = "@kizunajs/fetch", regenerateCommand = "kizuna generate", source } = options;
379
391
  const collector = new TypeCollector();
380
- const tree = emitTree(contract.routes, "", collector);
392
+ const tree = emitTree(contract.routes, "", collector, namespaceName);
381
393
  const api = [...collector.all().map((model) => {
382
394
  return `${model.description ? `/**\n * ${model.description}\n */\n` : ""}export type ${model.name} = ${model.body};`;
383
395
  }), ...tree.declarations].join("\n\n");
@@ -393,7 +405,7 @@ ${[
393
405
  */
394
406
  import { createGeneratedClient, type ClientConfig, type ClientMethod, type GeneratedRoutes } from '${runtimeModule}';
395
407
 
396
- export namespace API {
408
+ export namespace ${namespaceName} {
397
409
  ${indent(api)}
398
410
  }
399
411
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kizunajs/fetch",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.10",
4
4
  "description": "Typed fetch client for Kizuna.js APIs",
5
5
  "keywords": [
6
6
  "kizunajs",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "peerDependencies": {
70
70
  "zod": "^4.0.0",
71
- "kizunajs": "2.0.0-beta.1"
71
+ "kizunajs": "2.0.0-beta.10"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@types/express": "^5.0.0",
@@ -76,8 +76,8 @@
76
76
  "tsdown": "^0.21.0",
77
77
  "typescript": "^6.0.3",
78
78
  "zod": "^4.0.0",
79
- "kizunajs": "2.0.0-beta.1",
80
- "@kizunajs/express": "2.0.0-beta.1"
79
+ "@kizunajs/express": "2.0.0-beta.10",
80
+ "kizunajs": "2.0.0-beta.10"
81
81
  },
82
82
  "scripts": {
83
83
  "build": "tsdown src/index.ts src/server.ts --format esm,cjs --dts --clean --external kizunajs --external zod",