@sdk-it/typescript 0.20.0 → 0.22.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/dist/index.js CHANGED
@@ -1,13 +1,22 @@
1
1
  // packages/typescript/src/lib/generate.ts
2
2
  import { template as template2 } from "lodash-es";
3
+ import { readdir } from "node:fs/promises";
3
4
  import { join as join2 } from "node:path";
4
5
  import { npmRunPathEnv } from "npm-run-path";
5
- import { spinalcase as spinalcase3 } from "stringcase";
6
- import { methods, pascalcase as pascalcase3 } from "@sdk-it/core";
6
+ import { camelcase as camelcase4, spinalcase as spinalcase3 } from "stringcase";
7
+ import { methods, pascalcase as pascalcase5, toLitObject as toLitObject2 } from "@sdk-it/core";
7
8
  import {
9
+ createWriterProxy,
8
10
  getFolderExports,
9
11
  writeFiles
10
12
  } from "@sdk-it/core/file-system.js";
13
+ import { toReadme } from "@sdk-it/readme";
14
+ import {
15
+ augmentSpec,
16
+ cleanFiles,
17
+ readWriteMetadata,
18
+ sanitizeTag as sanitizeTag4
19
+ } from "@sdk-it/spec";
11
20
 
12
21
  // packages/typescript/src/lib/client.ts
13
22
  import { toLitObject } from "@sdk-it/core";
@@ -32,11 +41,9 @@ var client_default = (spec, style) => {
32
41
  schema: spec.servers.length ? `z.enum(servers).default(servers[0])` : "z.string()"
33
42
  }
34
43
  };
35
- return `
44
+ return `import z from 'zod';
36
45
  import type { HeadersInit, RequestConfig } from './http/${spec.makeImport("request")}';
37
- import { fetchType, dispatch, parse } from './http/${spec.makeImport("send-request")}';
38
- import z from 'zod';
39
- import type { Endpoints } from './api/${spec.makeImport("endpoints")}';
46
+ import { fetchType, parse } from './http/${spec.makeImport("dispatcher")}';
40
47
  import schemas from './api/${spec.makeImport("schemas")}';
41
48
  import {
42
49
  createBaseUrlInterceptor,
@@ -57,13 +64,18 @@ export class ${spec.name} {
57
64
  this.options = optionsSchema.parse(options);
58
65
  }
59
66
 
60
- async request<E extends keyof Endpoints>(
67
+ async request<const E extends keyof typeof schemas>(
61
68
  endpoint: E,
62
- input: Endpoints[E]['input'],
69
+ input: z.infer<(typeof schemas)[E]['schema']>,
63
70
  options?: { signal?: AbortSignal, headers?: HeadersInit },
64
- ) ${style.errorAsValue ? `: Promise<readonly [Endpoints[E]['output'], Endpoints[E]['error'] | null]>` : `: Promise<Endpoints[E]['output']>`} {
71
+ ) ${style.errorAsValue ? `: Promise<Awaited<ReturnType<(typeof schemas)[E]['dispatch']>>| [never, ParseError<(typeof schemas)[E]['schema']>]>` : `: Promise<Awaited<ReturnType<(typeof schemas)[E]['dispatch']>>>`} {
65
72
  const route = schemas[endpoint];
66
- const result = await dispatch(Object.assign(this.#defaultInputs, input), route, {
73
+ const withDefaultInputs = Object.assign({}, this.#defaultInputs, input);
74
+ const [parsedInput, parseError] = parseInput(route.schema, withDefaultInputs);
75
+ if (parseError) {
76
+ ${style.errorAsValue ? "return [null as never, parseError as never] as const;" : "throw parseError;"}
77
+ }
78
+ const result = await route.dispatch(parsedInput as never, {
67
79
  fetch: this.options.fetch,
68
80
  interceptors: [
69
81
  createHeadersInterceptor(() => this.defaultHeaders, options?.headers ?? {}),
@@ -71,12 +83,12 @@ export class ${spec.name} {
71
83
  ],
72
84
  signal: options?.signal,
73
85
  });
74
- return ${style.errorAsValue ? `result as [Endpoints[E]['output'], Endpoints[E]['error'] | null]` : `result as Endpoints[E]['output']`};
86
+ return result as Awaited<ReturnType<(typeof schemas)[E]['dispatch']>>;
75
87
  }
76
88
 
77
- async prepare<E extends keyof Endpoints>(
89
+ async prepare<const E extends keyof typeof schemas>(
78
90
  endpoint: E,
79
- input: Endpoints[E]['input'],
91
+ input: z.infer<(typeof schemas)[E]['schema']>,
80
92
  options?: { headers?: HeadersInit },
81
93
  ): ${style.errorAsValue ? `Promise<
82
94
  readonly [
@@ -108,8 +120,8 @@ export class ${spec.name} {
108
120
  config = await interceptor.before(config);
109
121
  }
110
122
  }
111
- const prepared = { ...config, parse: (response: Response) => parse(route, response) };
112
- return ${style.errorAsValue ? "[prepared, null as never] as const;" : "prepared"}
123
+ const prepared = { ...config, parse: (response: Response) => parse(route.output, response) as never };
124
+ return ${style.errorAsValue ? "[prepared, null as never] as const;" : "prepared as any"}
113
125
  }
114
126
 
115
127
  get defaultHeaders() {
@@ -132,258 +144,185 @@ export class ${spec.name} {
132
144
  }`;
133
145
  };
134
146
 
135
- // packages/typescript/src/lib/generator.ts
136
- import { merge, template } from "lodash-es";
137
- import { join } from "node:path";
138
- import { camelcase as camelcase3, pascalcase as pascalcase2, spinalcase as spinalcase2 } from "stringcase";
139
- import { followRef as followRef5, isEmpty, isRef as isRef6 } from "@sdk-it/core";
140
-
141
- // packages/spec/dist/lib/operation.js
142
- import { camelcase } from "stringcase";
143
- import { followRef, isRef } from "@sdk-it/core";
144
- var defaults = {
145
- operationId: (operation, path, method) => {
146
- if (operation.operationId) {
147
- return camelcase(operation.operationId);
148
- }
149
- const metadata = operation["x-oaiMeta"];
150
- if (metadata && metadata.name) {
151
- return camelcase(metadata.name);
152
- }
153
- return camelcase(
154
- [method, ...path.replace(/[\\/\\{\\}]/g, " ").split(" ")].filter(Boolean).join(" ").trim()
155
- );
156
- },
157
- tag: (operation, path) => {
158
- return operation.tags?.[0] ? sanitizeTag(operation.tags?.[0]) : determineGenericTag(path, operation);
147
+ // packages/typescript/src/lib/emitters/interface.ts
148
+ import { followRef, isRef, parseRef, pascalcase } from "@sdk-it/core";
149
+ import { isPrimitiveSchema, sanitizeTag } from "@sdk-it/spec";
150
+ var TypeScriptEmitter = class {
151
+ #spec;
152
+ constructor(spec) {
153
+ this.#spec = spec;
159
154
  }
160
- };
161
- function resolveResponses(spec, operation) {
162
- const responses = operation.responses ?? {};
163
- const resolved = {};
164
- for (const status in responses) {
165
- const response = isRef(responses[status]) ? followRef(spec, responses[status].$ref) : responses[status];
166
- resolved[status] = response;
167
- }
168
- return resolved;
169
- }
170
- function forEachOperation(config, callback) {
171
- const result = [];
172
- for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
173
- const { parameters = [], ...methods2 } = pathItem;
174
- const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
175
- for (const [method, operation] of Object.entries(methods2)) {
176
- const formatOperationId = config.operationId ?? defaults.operationId;
177
- const formatTag = config.tag ?? defaults.tag;
178
- const operationName = formatOperationId(operation, fixedPath, method);
179
- const operationTag = formatTag(operation, fixedPath);
180
- const metadata = operation["x-oaiMeta"] ?? {};
181
- result.push(
182
- callback(
183
- {
184
- name: metadata.name,
185
- method,
186
- path: fixedPath,
187
- groupName: operationTag,
188
- tag: operationTag
189
- },
190
- {
191
- ...operation,
192
- parameters: [...parameters, ...operation.parameters ?? []],
193
- operationId: operationName,
194
- responses: resolveResponses(config.spec, operation)
195
- }
196
- )
197
- );
155
+ #stringifyKey = (value) => {
156
+ return `'${value}'`;
157
+ };
158
+ object(schema, required = false) {
159
+ const properties = schema.properties || {};
160
+ const propEntries = Object.entries(properties).map(([key, propSchema]) => {
161
+ const isRequired = (schema.required ?? []).includes(key);
162
+ const tsType = this.handle(propSchema, isRequired);
163
+ return `${this.#stringifyKey(key)}: ${tsType}`;
164
+ });
165
+ if (schema.additionalProperties) {
166
+ if (typeof schema.additionalProperties === "object") {
167
+ const indexType = this.handle(schema.additionalProperties, true);
168
+ propEntries.push(`[key: string]: ${indexType}`);
169
+ } else if (schema.additionalProperties === true) {
170
+ propEntries.push("[key: string]: any");
171
+ }
198
172
  }
173
+ return `${propEntries.length ? `{ ${propEntries.join("; ")} }` : "unknown"}`;
199
174
  }
200
- return result;
201
- }
202
- var reservedKeywords = /* @__PURE__ */ new Set([
203
- "await",
204
- // Reserved in async functions
205
- "break",
206
- "case",
207
- "catch",
208
- "class",
209
- "const",
210
- "continue",
211
- "debugger",
212
- "default",
213
- "delete",
214
- "do",
215
- "else",
216
- "enum",
217
- "export",
218
- "extends",
219
- "false",
220
- "finally",
221
- "for",
222
- "function",
223
- "if",
224
- "implements",
225
- // Strict mode
226
- "import",
227
- "in",
228
- "instanceof",
229
- "interface",
230
- // Strict mode
231
- "let",
232
- // Strict mode
233
- "new",
234
- "null",
235
- "package",
236
- // Strict mode
237
- "private",
238
- // Strict mode
239
- "protected",
240
- // Strict mode
241
- "public",
242
- // Strict mode
243
- "return",
244
- "static",
245
- // Strict mode
246
- "super",
247
- "switch",
248
- "this",
249
- "throw",
250
- "true",
251
- "try",
252
- "typeof",
253
- "var",
254
- "void",
255
- "while",
256
- "with",
257
- "yield",
258
- // Strict mode / Generator functions
259
- // 'arguments' is not technically a reserved word, but it's a special identifier within functions
260
- // and assigning to it or declaring it can cause issues or unexpected behavior.
261
- "arguments"
262
- ]);
263
- function sanitizeTag(camelCasedTag) {
264
- if (/^\d/.test(camelCasedTag)) {
265
- return `_${camelCasedTag}`;
266
- }
267
- return reservedKeywords.has(camelcase(camelCasedTag)) ? `${camelCasedTag}_` : camelCasedTag;
268
- }
269
- function determineGenericTag(pathString, operation) {
270
- const operationId = operation.operationId || "";
271
- const VERSION_REGEX = /^[vV]\d+$/;
272
- const commonVerbs = /* @__PURE__ */ new Set([
273
- // Verbs to potentially strip from operationId prefix
274
- "get",
275
- "list",
276
- "create",
277
- "update",
278
- "delete",
279
- "post",
280
- "put",
281
- "patch",
282
- "do",
283
- "send",
284
- "add",
285
- "remove",
286
- "set",
287
- "find",
288
- "search",
289
- "check",
290
- "make"
291
- ]);
292
- const segments = pathString.split("/").filter(Boolean);
293
- const potentialCandidates = segments.filter(
294
- (segment) => segment && !segment.startsWith("{") && !segment.endsWith("}") && !VERSION_REGEX.test(segment)
295
- );
296
- for (let i = potentialCandidates.length - 1; i >= 0; i--) {
297
- const segment = potentialCandidates[i];
298
- if (!segment.startsWith("@")) {
299
- return sanitizeTag(camelcase(segment));
300
- }
301
- }
302
- const canFallbackToPathSegment = potentialCandidates.length > 0;
303
- if (operationId) {
304
- const lowerOpId = operationId.toLowerCase();
305
- const parts = operationId.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").replace(/([a-zA-Z])(\d)/g, "$1_$2").replace(/(\d)([a-zA-Z])/g, "$1_$2").toLowerCase().split(/[_-\s]+/);
306
- const validParts = parts.filter(Boolean);
307
- if (commonVerbs.has(lowerOpId) && validParts.length === 1 && canFallbackToPathSegment) {
308
- } else if (validParts.length > 0) {
309
- const firstPart = validParts[0];
310
- const isFirstPartVerb = commonVerbs.has(firstPart);
311
- if (isFirstPartVerb && validParts.length > 1) {
312
- const verbPrefixLength = firstPart.length;
313
- let nextPartStartIndex = -1;
314
- if (operationId.length > verbPrefixLength) {
315
- const charAfterPrefix = operationId[verbPrefixLength];
316
- if (charAfterPrefix >= "A" && charAfterPrefix <= "Z") {
317
- nextPartStartIndex = verbPrefixLength;
318
- } else if (charAfterPrefix >= "0" && charAfterPrefix <= "9") {
319
- nextPartStartIndex = verbPrefixLength;
320
- } else if (["_", "-"].includes(charAfterPrefix)) {
321
- nextPartStartIndex = verbPrefixLength + 1;
322
- } else {
323
- const match = operationId.substring(verbPrefixLength).match(/[A-Z0-9]/);
324
- if (match && match.index !== void 0) {
325
- nextPartStartIndex = verbPrefixLength + match.index;
326
- }
327
- if (nextPartStartIndex === -1 && operationId.length > verbPrefixLength) {
328
- nextPartStartIndex = verbPrefixLength;
329
- }
330
- }
331
- }
332
- if (nextPartStartIndex !== -1 && nextPartStartIndex < operationId.length) {
333
- const remainingOriginalSubstring = operationId.substring(nextPartStartIndex);
334
- const potentialTag = camelcase(remainingOriginalSubstring);
335
- if (potentialTag) {
336
- return sanitizeTag(potentialTag);
337
- }
338
- }
339
- const potentialTagJoined = camelcase(validParts.slice(1).join("_"));
340
- if (potentialTagJoined) {
341
- return sanitizeTag(potentialTagJoined);
342
- }
343
- }
344
- const potentialTagFull = camelcase(operationId);
345
- if (potentialTagFull) {
346
- const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;
347
- if (!(isResultSingleVerb && canFallbackToPathSegment)) {
348
- if (potentialTagFull.length > 0) {
349
- return sanitizeTag(potentialTagFull);
350
- }
351
- }
352
- }
353
- const firstPartCamel = camelcase(firstPart);
354
- if (firstPartCamel) {
355
- const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);
356
- if (!isFirstPartCamelVerb || validParts.length === 1 || !canFallbackToPathSegment) {
357
- return sanitizeTag(firstPartCamel);
358
- }
359
- }
360
- if (isFirstPartVerb && validParts.length > 1 && validParts[1] && canFallbackToPathSegment) {
361
- const secondPartCamel = camelcase(validParts[1]);
362
- if (secondPartCamel) {
363
- return sanitizeTag(secondPartCamel);
364
- }
365
- }
175
+ /**
176
+ * Handle arrays (items could be a single schema or a tuple)
177
+ */
178
+ #array(schema, required = false) {
179
+ const { items } = schema;
180
+ if (!items) {
181
+ return "any[]";
366
182
  }
183
+ if (Array.isArray(items)) {
184
+ const tupleItems = items.map((sub) => this.handle(sub, true));
185
+ return `[${tupleItems.join(", ")}]`;
186
+ }
187
+ const itemsType = this.handle(items, true);
188
+ return itemsType.length > 1 ? `(${itemsType})[]` : `${itemsType}[]`;
367
189
  }
368
- if (potentialCandidates.length > 0) {
369
- let firstCandidate = potentialCandidates[0];
370
- if (firstCandidate.startsWith("@")) {
371
- firstCandidate = firstCandidate.substring(1);
190
+ /**
191
+ * Convert a basic type (string | number | boolean | object | array, etc.) to TypeScript
192
+ */
193
+ normal(type, schema, required = false) {
194
+ switch (type) {
195
+ case "string":
196
+ return this.string(schema, required);
197
+ case "number":
198
+ case "integer":
199
+ return this.number(schema, required);
200
+ case "boolean":
201
+ return appendOptional("boolean", required);
202
+ case "object":
203
+ return this.object(schema, required);
204
+ case "array":
205
+ return this.#array(schema, required);
206
+ case "null":
207
+ return "null";
208
+ default:
209
+ console.warn(`Unknown type: ${type}`);
210
+ return appendOptional("any", required);
372
211
  }
373
- if (firstCandidate) {
374
- return sanitizeTag(camelcase(firstCandidate));
212
+ }
213
+ #ref($ref, required) {
214
+ const schemaName = pascalcase(sanitizeTag(parseRef($ref).model));
215
+ const schema = followRef(this.#spec, $ref);
216
+ if (isPrimitiveSchema(schema)) {
217
+ return this.handle(schema, required);
375
218
  }
219
+ return `models.${appendOptional(schemaName, required)}`;
376
220
  }
377
- console.warn(
378
- `Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`
379
- );
380
- return "unknown";
221
+ allOf(schemas) {
222
+ const allOfTypes = schemas.map((sub) => this.handle(sub, true));
223
+ return allOfTypes.length > 1 ? `${allOfTypes.join(" & ")}` : allOfTypes[0];
224
+ }
225
+ oneOf(schemas, required) {
226
+ const oneOfTypes = schemas.map((sub) => this.handle(sub, true));
227
+ return appendOptional(
228
+ oneOfTypes.length > 1 ? `${oneOfTypes.join(" | ")}` : oneOfTypes[0],
229
+ required
230
+ );
231
+ }
232
+ anyOf(schemas, required) {
233
+ return this.oneOf(schemas, required);
234
+ }
235
+ enum(values, required) {
236
+ const enumValues = values.map((val) => typeof val === "string" ? `'${val}'` : `${val}`).join(" | ");
237
+ return appendOptional(enumValues, required);
238
+ }
239
+ /**
240
+ * Handle string type with formats
241
+ */
242
+ string(schema, required) {
243
+ let type;
244
+ if (schema.contentEncoding === "binary") {
245
+ return appendOptional("Blob", required);
246
+ }
247
+ switch (schema.format) {
248
+ case "date-time":
249
+ case "datetime":
250
+ case "date":
251
+ type = "Date";
252
+ break;
253
+ case "binary":
254
+ case "byte":
255
+ type = "Blob";
256
+ break;
257
+ case "int64":
258
+ type = "bigint";
259
+ break;
260
+ default:
261
+ type = "string";
262
+ }
263
+ return appendOptional(type, required);
264
+ }
265
+ /**
266
+ * Handle number/integer types with formats
267
+ */
268
+ number(schema, required) {
269
+ const type = schema.format === "int64" ? "bigint" : "number";
270
+ return appendOptional(type, required);
271
+ }
272
+ handle(schema, required) {
273
+ if (isRef(schema)) {
274
+ return this.#ref(schema.$ref, required);
275
+ }
276
+ if (schema.allOf && Array.isArray(schema.allOf)) {
277
+ return this.allOf(schema.allOf);
278
+ }
279
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
280
+ return this.anyOf(schema.anyOf, required);
281
+ }
282
+ if (schema.oneOf && Array.isArray(schema.oneOf)) {
283
+ return this.oneOf(schema.oneOf, required);
284
+ }
285
+ if (schema.enum && Array.isArray(schema.enum)) {
286
+ return this.enum(schema.enum, required);
287
+ }
288
+ if (schema.const) {
289
+ return this.enum([schema.const], true);
290
+ }
291
+ const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
292
+ if (!types.length) {
293
+ if ("properties" in schema) {
294
+ return this.object(schema, required);
295
+ }
296
+ return appendOptional("any", required);
297
+ }
298
+ if (types.length > 1) {
299
+ const realTypes = types.filter((t) => t !== "null");
300
+ if (realTypes.length === 1 && types.includes("null")) {
301
+ const tsType = this.normal(realTypes[0], schema, false);
302
+ return appendOptional(`${tsType} | null`, required);
303
+ }
304
+ const typeResults = types.map((t) => this.normal(t, schema, false));
305
+ return appendOptional(typeResults.join(" | "), required);
306
+ }
307
+ return this.normal(types[0], schema, required);
308
+ }
309
+ };
310
+ function appendOptional(type, isRequired) {
311
+ return isRequired ? type : `${type} | undefined`;
381
312
  }
382
313
 
314
+ // packages/typescript/src/lib/generator.ts
315
+ import { merge, template } from "lodash-es";
316
+ import { join } from "node:path";
317
+ import { camelcase as camelcase2, spinalcase } from "stringcase";
318
+ import { followRef as followRef4, isEmpty as isEmpty2, isRef as isRef4, resolveRef } from "@sdk-it/core";
319
+ import { forEachOperation } from "@sdk-it/spec";
320
+
383
321
  // packages/typescript/src/lib/emitters/zod.ts
384
- import { cleanRef, followRef as followRef2, isRef as isRef2 } from "@sdk-it/core";
385
- var ZodDeserialzer = class {
386
- generatedRefs = /* @__PURE__ */ new Set();
322
+ import { followRef as followRef2, isRef as isRef2, parseRef as parseRef2, pascalcase as pascalcase2 } from "@sdk-it/core";
323
+ import { isPrimitiveSchema as isPrimitiveSchema2, sanitizeTag as sanitizeTag2 } from "@sdk-it/spec";
324
+ var ZodEmitter = class {
325
+ #generatedRefs = /* @__PURE__ */ new Set();
387
326
  #spec;
388
327
  #onRef;
389
328
  constructor(spec, onRef) {
@@ -410,25 +349,21 @@ var ZodDeserialzer = class {
410
349
  }
411
350
  return `z.object({${propEntries.join(", ")}})${additionalProps}`;
412
351
  }
413
- /**
414
- * Handle arrays (items could be a single schema or a tuple (array of schemas)).
415
- * In JSON Schema 2020-12, `items` can be an array → tuple style.
416
- */
417
- array(schema, required = false) {
352
+ #array(schema, required = false) {
418
353
  const { items } = schema;
419
354
  if (!items) {
420
- return `z.array(z.unknown())${appendOptional(required)}`;
355
+ return `z.array(z.unknown())${appendOptional2(required)}`;
421
356
  }
422
357
  if (Array.isArray(items)) {
423
358
  const tupleItems = items.map((sub) => this.handle(sub, true));
424
359
  const base = `z.tuple([${tupleItems.join(", ")}])`;
425
- return `${base}${appendOptional(required)}`;
360
+ return `${base}${appendOptional2(required)}`;
426
361
  }
427
362
  const itemsSchema = this.handle(items, true);
428
- return `z.array(${itemsSchema})${appendOptional(required)}`;
363
+ return `z.array(${itemsSchema})${this.#suffixes(JSON.stringify(schema.default), required, false)}`;
429
364
  }
430
365
  #suffixes = (defaultValue, required, nullable) => {
431
- return `${nullable ? ".nullable()" : ""}${appendDefault(defaultValue)}${appendOptional(required)}`;
366
+ return `${nullable ? ".nullable()" : ""}${appendDefault(defaultValue)}${appendOptional2(required)}`;
432
367
  };
433
368
  /**
434
369
  * Convert a basic type (string | number | boolean | object | array, etc.) to Zod.
@@ -448,55 +383,58 @@ var ZodDeserialzer = class {
448
383
  case "object":
449
384
  return `${this.object(schema)}${this.#suffixes(JSON.stringify(schema.default), required, nullable)}`;
450
385
  case "array":
451
- return this.array(schema, required);
386
+ return this.#array(schema, required);
452
387
  case "null":
453
- return `z.null()${appendOptional(required)}`;
388
+ return `z.null()${appendOptional2(required)}`;
454
389
  default:
455
- return `z.unknown()${appendOptional(required)}`;
390
+ return `z.unknown()${appendOptional2(required)}`;
456
391
  }
457
392
  }
458
- ref($ref, required) {
459
- const schemaName = cleanRef($ref).split("/").pop();
460
- if (this.generatedRefs.has(schemaName)) {
393
+ #ref($ref, required) {
394
+ const schemaName = pascalcase2(sanitizeTag2(parseRef2($ref).model));
395
+ const schema = followRef2(this.#spec, $ref);
396
+ if (isPrimitiveSchema2(schema)) {
397
+ const result = this.handle(schema, required);
398
+ this.#onRef?.(schemaName, result);
399
+ return result;
400
+ }
401
+ if (this.#generatedRefs.has(schemaName)) {
461
402
  return schemaName;
462
403
  }
463
- this.generatedRefs.add(schemaName);
464
- this.#onRef?.(
465
- schemaName,
466
- this.handle(followRef2(this.#spec, $ref), required)
467
- );
404
+ this.#generatedRefs.add(schemaName);
405
+ this.#onRef?.(schemaName, this.handle(schema, required));
468
406
  return schemaName;
469
407
  }
408
+ #toIntersection(schemas) {
409
+ const [left, ...right] = schemas;
410
+ if (!right.length) {
411
+ return left;
412
+ }
413
+ return `z.intersection(${left}, ${this.#toIntersection(right)})`;
414
+ }
470
415
  allOf(schemas, required) {
471
416
  const allOfSchemas = schemas.map((sub) => this.handle(sub, true));
472
417
  if (allOfSchemas.length === 0) {
473
418
  return `z.unknown()`;
474
419
  }
475
420
  if (allOfSchemas.length === 1) {
476
- return `${allOfSchemas[0]}${appendOptional(required)}`;
421
+ return `${allOfSchemas[0]}${appendOptional2(required)}`;
477
422
  }
478
- return `${this.#toIntersection(allOfSchemas)}${appendOptional(required)}`;
479
- }
480
- #toIntersection(schemas) {
481
- const [left, ...right] = schemas;
482
- if (!right.length) {
483
- return left;
484
- }
485
- return `z.intersection(${left}, ${this.#toIntersection(right)})`;
423
+ return `${this.#toIntersection(allOfSchemas)}${appendOptional2(required)}`;
486
424
  }
487
425
  anyOf(schemas, required) {
488
426
  const anyOfSchemas = schemas.map((sub) => this.handle(sub, true));
489
427
  if (anyOfSchemas.length === 1) {
490
- return `${anyOfSchemas[0]}${appendOptional(required)}`;
428
+ return `${anyOfSchemas[0]}${appendOptional2(required)}`;
491
429
  }
492
- return `z.union([${anyOfSchemas.join(", ")}])${appendOptional(required)}`;
430
+ return `z.union([${anyOfSchemas.join(", ")}])${appendOptional2(required)}`;
493
431
  }
494
432
  oneOf(schemas, required) {
495
433
  const oneOfSchemas = schemas.map((sub) => this.handle(sub, true));
496
434
  if (oneOfSchemas.length === 1) {
497
- return `${oneOfSchemas[0]}${appendOptional(required)}`;
435
+ return `${oneOfSchemas[0]}${appendOptional2(required)}`;
498
436
  }
499
- return `z.union([${oneOfSchemas.join(", ")}])${appendOptional(required)}`;
437
+ return `z.union([${oneOfSchemas.join(", ")}])${appendOptional2(required)}`;
500
438
  }
501
439
  enum(type, values) {
502
440
  if (values.length === 1) {
@@ -594,7 +532,7 @@ var ZodDeserialzer = class {
594
532
  }
595
533
  handle(schema, required) {
596
534
  if (isRef2(schema)) {
597
- return `${this.ref(schema.$ref, true)}${appendOptional(required)}`;
535
+ return `${this.#ref(schema.$ref, true)}${appendOptional2(required)}`;
598
536
  }
599
537
  if (schema.allOf && Array.isArray(schema.allOf)) {
600
538
  return this.allOf(schema.allOf ?? [], required);
@@ -612,7 +550,7 @@ var ZodDeserialzer = class {
612
550
  }
613
551
  const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
614
552
  if (!types.length) {
615
- return `z.unknown()${appendOptional(required)}`;
553
+ return `z.unknown()${appendOptional2(required)}`;
616
554
  }
617
555
  if ("nullable" in schema && schema.nullable) {
618
556
  types.push("null");
@@ -625,12 +563,12 @@ var ZodDeserialzer = class {
625
563
  return this.normal(realTypes[0], schema, required, true);
626
564
  }
627
565
  const subSchemas = types.map((t) => this.normal(t, schema, false));
628
- return `z.union([${subSchemas.join(", ")}])${appendOptional(required)}`;
566
+ return `z.union([${subSchemas.join(", ")}])${appendOptional2(required)}`;
629
567
  }
630
568
  return this.normal(types[0], schema, required, false);
631
569
  }
632
570
  };
633
- function appendOptional(isRequired) {
571
+ function appendOptional2(isRequired) {
634
572
  return isRequired ? "" : ".optional()";
635
573
  }
636
574
  function appendDefault(defaultValue) {
@@ -638,201 +576,46 @@ function appendDefault(defaultValue) {
638
576
  }
639
577
 
640
578
  // packages/typescript/src/lib/sdk.ts
641
- import { get } from "lodash-es";
642
- import { camelcase as camelcase2, pascalcase, spinalcase } from "stringcase";
643
- import { followRef as followRef4, isRef as isRef5, toLitObject as toLitObject2 } from "@sdk-it/core";
644
-
645
- // packages/typescript/src/lib/emitters/interface.ts
646
- import { cleanRef as cleanRef2, followRef as followRef3, isRef as isRef3 } from "@sdk-it/core";
647
- var TypeScriptDeserialzer = class {
648
- generatedRefs = /* @__PURE__ */ new Set();
649
- #spec;
650
- #onRef;
651
- constructor(spec, onRef) {
652
- this.#spec = spec;
653
- this.#onRef = onRef;
654
- }
655
- #stringifyKey = (value) => {
656
- return `'${value}'`;
657
- };
658
- #isInternal = (schema) => {
659
- return isRef3(schema) ? false : !!schema["x-internal"];
660
- };
661
- /**
662
- * Handle objects (properties)
663
- */
664
- object(schema, required = false) {
665
- const properties = schema.properties || {};
666
- const propEntries = Object.entries(properties).map(([key, propSchema]) => {
667
- const isRequired = (schema.required ?? []).includes(key);
668
- const tsType = this.handle(propSchema, isRequired);
669
- return `${this.#isInternal(propSchema) ? key : this.#stringifyKey(key)}: ${tsType}`;
670
- });
671
- if (schema.additionalProperties) {
672
- if (typeof schema.additionalProperties === "object") {
673
- const indexType = this.handle(schema.additionalProperties, true);
674
- propEntries.push(`[key: string]: ${indexType}`);
675
- } else if (schema.additionalProperties === true) {
676
- propEntries.push("[key: string]: any");
677
- }
678
- }
679
- return `{ ${propEntries.join("; ")} }`;
680
- }
681
- /**
682
- * Handle arrays (items could be a single schema or a tuple)
683
- */
684
- array(schema, required = false) {
685
- const { items } = schema;
686
- if (!items) {
687
- return "any[]";
688
- }
689
- if (Array.isArray(items)) {
690
- const tupleItems = items.map((sub) => this.handle(sub, true));
691
- return `[${tupleItems.join(", ")}]`;
692
- }
693
- const itemsType = this.handle(items, true);
694
- return `${itemsType}[]`;
695
- }
696
- /**
697
- * Convert a basic type (string | number | boolean | object | array, etc.) to TypeScript
698
- */
699
- normal(type, schema, required = false) {
700
- switch (type) {
701
- case "string":
702
- return this.string(schema, required);
703
- case "number":
704
- case "integer":
705
- return this.number(schema, required);
706
- case "boolean":
707
- return appendOptional2("boolean", required);
708
- case "object":
709
- return this.object(schema, required);
710
- case "array":
711
- return this.array(schema, required);
712
- case "null":
713
- return "null";
714
- default:
715
- console.warn(`Unknown type: ${type}`);
716
- return appendOptional2("any", required);
717
- }
718
- }
719
- ref($ref, required) {
720
- const schemaName = cleanRef2($ref).split("/").pop();
721
- if (this.generatedRefs.has(schemaName)) {
722
- return schemaName;
723
- }
724
- this.generatedRefs.add(schemaName);
725
- this.#onRef?.(
726
- schemaName,
727
- this.handle(followRef3(this.#spec, $ref), required)
728
- );
729
- return appendOptional2(schemaName, required);
730
- }
731
- allOf(schemas) {
732
- const allOfTypes = schemas.map((sub) => this.handle(sub, true));
733
- return allOfTypes.length > 1 ? `${allOfTypes.join(" & ")}` : allOfTypes[0];
734
- }
735
- anyOf(schemas, required) {
736
- const anyOfTypes = schemas.map((sub) => this.handle(sub, true));
737
- return appendOptional2(
738
- anyOfTypes.length > 1 ? `${anyOfTypes.join(" | ")}` : anyOfTypes[0],
739
- required
740
- );
741
- }
742
- oneOf(schemas, required) {
743
- const oneOfTypes = schemas.map((sub) => {
744
- return this.handle(sub, false);
745
- });
746
- return appendOptional2(
747
- oneOfTypes.length > 1 ? `${oneOfTypes.join(" | ")}` : oneOfTypes[0],
748
- required
749
- );
750
- }
751
- enum(values, required) {
752
- const enumValues = values.map((val) => typeof val === "string" ? `'${val}'` : `${val}`).join(" | ");
753
- return appendOptional2(enumValues, required);
754
- }
755
- /**
756
- * Handle string type with formats
757
- */
758
- string(schema, required) {
759
- let type;
760
- if (schema.contentEncoding === "binary") {
761
- return appendOptional2("Blob", required);
762
- }
763
- switch (schema.format) {
764
- case "date-time":
765
- case "datetime":
766
- case "date":
767
- type = "Date";
768
- break;
769
- case "binary":
770
- case "byte":
771
- type = "Blob";
772
- break;
773
- case "int64":
774
- type = "bigint";
775
- break;
776
- default:
777
- type = "string";
778
- }
779
- return appendOptional2(type, required);
780
- }
781
- /**
782
- * Handle number/integer types with formats
783
- */
784
- number(schema, required) {
785
- const type = schema.format === "int64" ? "bigint" : "number";
786
- return appendOptional2(type, required);
787
- }
788
- handle(schema, required) {
789
- if (isRef3(schema)) {
790
- return this.ref(schema.$ref, required);
791
- }
792
- if (schema.allOf && Array.isArray(schema.allOf)) {
793
- return this.allOf(schema.allOf);
794
- }
795
- if (schema.anyOf && Array.isArray(schema.anyOf)) {
796
- return this.anyOf(schema.anyOf, required);
797
- }
798
- if (schema.oneOf && Array.isArray(schema.oneOf)) {
799
- return this.oneOf(schema.oneOf, required);
800
- }
801
- if (schema.enum && Array.isArray(schema.enum)) {
802
- return this.enum(schema.enum, required);
803
- }
804
- if (schema.const) {
805
- if (schema["x-internal"]) {
806
- return `${schema.const}`;
807
- }
808
- return this.enum([schema.const], required);
809
- }
810
- const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
811
- if (!types.length) {
812
- if ("properties" in schema) {
813
- return this.object(schema, required);
814
- }
815
- return appendOptional2("any", required);
816
- }
817
- if (types.length > 1) {
818
- const realTypes = types.filter((t) => t !== "null");
819
- if (realTypes.length === 1 && types.includes("null")) {
820
- const tsType = this.normal(realTypes[0], schema, false);
821
- return appendOptional2(`${tsType} | null`, required);
822
- }
823
- const typeResults = types.map((t) => this.normal(t, schema, false));
824
- return appendOptional2(typeResults.join(" | "), required);
825
- }
826
- return this.normal(types[0], schema, required);
827
- }
579
+ import { camelcase } from "stringcase";
580
+ import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
581
+ import {
582
+ isErrorStatusCode,
583
+ isStreamingContentType,
584
+ isSuccessStatusCode,
585
+ isTextContentType,
586
+ parseJsonContentType,
587
+ sanitizeTag as sanitizeTag3
588
+ } from "@sdk-it/spec";
589
+
590
+ // packages/typescript/src/lib/status-map.ts
591
+ var status_map_default = {
592
+ "200": "Ok",
593
+ "201": "Created",
594
+ "202": "Accepted",
595
+ "204": "NoContent",
596
+ "400": "BadRequest",
597
+ "401": "Unauthorized",
598
+ "402": "PaymentRequired",
599
+ "403": "Forbidden",
600
+ "404": "NotFound",
601
+ "405": "MethodNotAllowed",
602
+ "406": "NotAcceptable",
603
+ "409": "Conflict",
604
+ "412": "PreconditionFailed",
605
+ "413": "PayloadTooLarge",
606
+ "410": "Gone",
607
+ "422": "UnprocessableEntity",
608
+ "429": "TooManyRequests",
609
+ "500": "InternalServerError",
610
+ "501": "NotImplemented",
611
+ "502": "BadGateway",
612
+ "503": "ServiceUnavailable",
613
+ "504": "GatewayTimeout"
828
614
  };
829
- function appendOptional2(type, isRequired) {
830
- return isRequired ? type : `${type} | undefined`;
831
- }
832
615
 
833
616
  // packages/typescript/src/lib/utils.ts
834
- import { isRef as isRef4, removeDuplicates } from "@sdk-it/core";
835
- function securityToOptions(security2, securitySchemes, staticIn) {
617
+ import { followRef as followRef3, isRef as isRef3, removeDuplicates } from "@sdk-it/core";
618
+ function securityToOptions(spec, security2, securitySchemes, staticIn) {
836
619
  securitySchemes ??= {};
837
620
  const options = {};
838
621
  for (const it of security2) {
@@ -840,10 +623,7 @@ function securityToOptions(security2, securitySchemes, staticIn) {
840
623
  if (!name) {
841
624
  continue;
842
625
  }
843
- const schema = securitySchemes[name];
844
- if (isRef4(schema)) {
845
- throw new Error(`Ref security schemas are not supported`);
846
- }
626
+ const schema = isRef3(securitySchemes[name]) ? followRef3(spec, securitySchemes[name].$ref) : securitySchemes[name];
847
627
  if (schema.type === "http") {
848
628
  options["authorization"] = {
849
629
  in: staticIn ?? "header",
@@ -901,73 +681,11 @@ function importsToString(...imports) {
901
681
  throw new Error(`Invalid import ${JSON.stringify(it)}`);
902
682
  });
903
683
  }
904
- function exclude(list, exclude2) {
905
- return list.filter((it) => !exclude2.includes(it));
906
- }
907
- function useImports(content, ...imports) {
908
- const output = [];
909
- for (const it of mergeImports(...imports)) {
910
- const singleImport = it.defaultImport ?? it.namespaceImport;
911
- if (singleImport && content.includes(singleImport)) {
912
- output.push(importsToString(it).join("\n"));
913
- } else if (it.namedImports.length) {
914
- for (const namedImport of it.namedImports) {
915
- if (content.includes(namedImport.name)) {
916
- output.push(importsToString(it).join("\n"));
917
- }
918
- }
919
- }
920
- }
921
- return output;
922
- }
923
684
 
924
685
  // packages/typescript/src/lib/sdk.ts
925
- function generateInputs(operationsSet, commonZod, makeImport) {
926
- const commonImports = commonZod.keys().toArray();
927
- const inputs = {};
928
- for (const [name, operations] of Object.entries(operationsSet)) {
929
- const output = [];
930
- const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
931
- for (const operation of operations) {
932
- const schemaName = camelcase2(`${operation.name} schema`);
933
- const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
934
- const inputContent = schema;
935
- for (const schema2 of commonImports) {
936
- if (inputContent.includes(schema2)) {
937
- imports.add(
938
- `import { ${schema2} } from './schemas/${makeImport(spinalcase(schema2))}';`
939
- );
940
- }
941
- }
942
- output.push(inputContent);
943
- }
944
- inputs[`inputs/${spinalcase(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
945
- }
946
- const schemas = commonZod.entries().reduce((acc, [name, schema]) => {
947
- const output = [`import { z } from 'zod';`];
948
- const content = `export const ${name} = ${schema};`;
949
- for (const schema2 of commonImports) {
950
- const preciseMatch = new RegExp(`\\b${schema2}\\b`);
951
- if (preciseMatch.test(content) && schema2 !== name) {
952
- output.push(
953
- `import { ${schema2} } from './${makeImport(spinalcase(schema2))}';`
954
- );
955
- }
956
- }
957
- output.push(content);
958
- return [
959
- [`inputs/schemas/${spinalcase(name)}.ts`, output.join("\n")],
960
- ...acc
961
- ];
962
- }, []);
963
- return {
964
- ...Object.fromEntries(schemas),
965
- ...inputs
966
- };
967
- }
968
686
  function toEndpoint(groupName, spec, specOperation, operation, utils) {
969
- const schemaName = camelcase2(`${operation.name} schema`);
970
- const schemaRef = `${camelcase2(groupName)}.${schemaName}`;
687
+ const schemaName = camelcase(`${operation.name} schema`);
688
+ const schemaRef = `${camelcase(groupName)}.${schemaName}`;
971
689
  const inputHeaders = [];
972
690
  const inputQuery = [];
973
691
  const inputBody = [];
@@ -995,20 +713,13 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
995
713
  }
996
714
  specOperation.responses ??= {};
997
715
  const outputs = [];
998
- const statusesCount = Object.keys(specOperation.responses).filter((status) => {
999
- const statusCode = +status;
1000
- return statusCode >= 200 && statusCode < 300;
1001
- }).length > 1;
1002
716
  for (const status in specOperation.responses) {
1003
- const response = isRef5(specOperation.responses[status]) ? followRef4(spec, specOperation.responses[status].$ref) : specOperation.responses[status];
1004
717
  const handled = handleResponse(
1005
718
  spec,
1006
719
  operation.name,
1007
720
  status,
1008
- response,
1009
- utils,
1010
- true
1011
- // statusesCount,
721
+ specOperation.responses[status],
722
+ utils
1012
723
  );
1013
724
  responses.push(handled);
1014
725
  outputs.push(...handled.outputs);
@@ -1019,49 +730,112 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
1019
730
  if (addTypeParser && type !== "json") {
1020
731
  typePrefix = `${type} `;
1021
732
  }
1022
- const endpoint = `${typePrefix}${operation.trigger.method.toUpperCase()} ${operation.trigger.path}`;
733
+ const endpoint = `${typePrefix}${operation.method.toUpperCase()} ${operation.path}`;
1023
734
  schemas.push(
1024
735
  `"${endpoint}": {
1025
736
  schema: ${schemaRef}${addTypeParser ? `.${type}` : ""},
1026
737
  output:[${outputs.join(",")}],
1027
738
  toRequest(input: z.infer<typeof ${schemaRef}${addTypeParser ? `.${type}` : ""}>) {
1028
- const endpoint = '${endpoint}';
1029
- return toRequest(endpoint, ${operation.outgoingContentType || "nobody"}(input, {
1030
- inputHeaders: [${inputHeaders}],
1031
- inputQuery: [${inputQuery}],
1032
- inputBody: [${inputBody}],
1033
- inputParams: [${inputParams}],
1034
- }));
1035
- },
1036
- }`
739
+ return toRequest('${endpoint}', ${operation.outgoingContentType || "empty"}(input, {
740
+ inputHeaders: [${inputHeaders}],
741
+ inputQuery: [${inputQuery}],
742
+ inputBody: [${inputBody}],
743
+ inputParams: [${inputParams}],
744
+ }));},
745
+ async dispatch(input: z.infer<typeof ${schemaRef}${addTypeParser ? `.${type}` : ""}>,options: {
746
+ signal?: AbortSignal;
747
+ interceptors: Interceptor[];
748
+ fetch: z.infer<typeof fetchType>;
749
+ })${specOperation["x-pagination"] ? paginationOperation(specOperation, utils.style) : normalOperation(utils.style)}`
1037
750
  );
1038
751
  }
1039
752
  return { responses, schemas };
1040
753
  }
1041
- var statusCodeToResponseMap = {
1042
- "200": "Ok",
1043
- "201": "Created",
1044
- "202": "Accepted",
1045
- "204": "NoContent",
1046
- "400": "BadRequest",
1047
- "401": "Unauthorized",
1048
- "402": "PaymentRequired",
1049
- "403": "Forbidden",
1050
- "404": "NotFound",
1051
- "405": "MethodNotAllowed",
1052
- "406": "NotAcceptable",
1053
- "409": "Conflict",
1054
- "413": "PayloadTooLarge",
1055
- "410": "Gone",
1056
- "422": "UnprocessableEntity",
1057
- "429": "TooManyRequests",
1058
- "500": "InternalServerError",
1059
- "501": "NotImplemented",
1060
- "502": "BadGateway",
1061
- "503": "ServiceUnavailable",
1062
- "504": "GatewayTimeout"
1063
- };
1064
- function handleResponse(spec, operationName, status, response, utils, numbered) {
754
+ function normalOperation(style) {
755
+ return `{
756
+ const dispatcher = new Dispatcher(options.interceptors, options.fetch);
757
+ const result = await dispatcher.send(this.toRequest(input), this.output);
758
+ return ${style?.outputType === "status" ? "result" : style?.errorAsValue ? `result` : "result.data;"}
759
+ },
760
+ }`;
761
+ }
762
+ function paginationOperation(operation, style) {
763
+ const pagination = operation["x-pagination"];
764
+ const data = `${style?.errorAsValue ? `result[0]${style.outputType === "status" ? "" : ""}` : `${style?.outputType === "default" ? "result.data" : "result.data"}`}`;
765
+ const returnValue = `${style?.errorAsValue ? `[${style?.outputType === "status" ? "new http.Ok(pagination)" : "pagination"}, null]` : `${style?.outputType === "status" ? "new http.Ok(pagination);" : "pagination"}`}`;
766
+ if (pagination.type === "offset") {
767
+ const sameInputNames = pagination.limitParamName === "limit" && pagination.offsetParamName === "offset";
768
+ const initialParams = sameInputNames ? "input" : `{...input, limit: input.${pagination.limitParamName}, offset: input.${pagination.offsetParamName}}`;
769
+ const nextPageParams = sameInputNames ? "...nextPageParams" : `${pagination.offsetParamName}: nextPageParams.offset, ${pagination.limitParamName}: nextPageParams.limit`;
770
+ const logic = `const pagination = new OffsetPagination(${initialParams}, async (nextPageParams) => {
771
+ const dispatcher = new Dispatcher(options.interceptors, options.fetch);
772
+ const result = await dispatcher.send(
773
+ this.toRequest({...input, ${nextPageParams}}),
774
+ this.output,
775
+ );
776
+ return {
777
+ data: ${data}.${pagination.items},
778
+ meta: {
779
+ hasMore: Boolean(${data}.${pagination.hasMore}),
780
+ },
781
+ };
782
+ });
783
+ await pagination.getNextPage();
784
+ return ${returnValue}
785
+ `;
786
+ return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
787
+ }
788
+ if (pagination.type === "cursor") {
789
+ const sameInputNames = pagination.cursorParamName === "cursor";
790
+ const initialParams = sameInputNames ? "input" : `{...input, cursor: input.${pagination.cursorParamName}}`;
791
+ const nextPageParams = sameInputNames ? "...nextPageParams" : `${pagination.cursorParamName}: nextPageParams.cursor`;
792
+ const logic = `
793
+ const pagination = new CursorPagination(${initialParams}, async (nextPageParams) => {
794
+ const dispatcher = new Dispatcher(options.interceptors, options.fetch);
795
+ const result = await dispatcher.send(
796
+ this.toRequest({...input, ${nextPageParams}}),
797
+ this.output,
798
+ );
799
+ ${style?.errorAsValue ? `if (result[1]) {throw result[1];}` : ""}
800
+ return {
801
+ data: ${data}.${pagination.items},
802
+ meta: {
803
+ hasMore: Boolean(${data}.${pagination.hasMore}),
804
+ },
805
+ };
806
+ });
807
+ await pagination.getNextPage();
808
+ return ${returnValue}
809
+ `;
810
+ return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
811
+ }
812
+ if (pagination.type === "page") {
813
+ const sameInputNames = pagination.pageNumberParamName === "page" && pagination.pageSizeParamName === "pageSize";
814
+ const initialParams = sameInputNames ? "input" : `{...input, page: input.${pagination.pageNumberParamName}, pageSize: input.${pagination.pageSizeParamName}}`;
815
+ const nextPageParams = sameInputNames ? "...nextPageParams" : `${pagination.pageNumberParamName}: nextPageParams.page, ${pagination.pageSizeParamName}: nextPageParams.pageSize`;
816
+ const logic = `
817
+ const pagination = new Pagination(${initialParams}, async (nextPageParams) => {
818
+ const dispatcher = new Dispatcher(options.interceptors, options.fetch);
819
+ const result = await dispatcher.send(
820
+ this.toRequest({...input, ${nextPageParams}}),
821
+ this.output,
822
+ );
823
+ ${style?.errorAsValue ? `if (result[1]) {throw result[1];}` : ""}
824
+ return {
825
+ data: ${data}.${pagination.items},
826
+ meta: {
827
+ hasMore: Boolean(${data}.${pagination.hasMore}),
828
+ },
829
+ };
830
+ });
831
+ await pagination.getNextPage();
832
+ return ${returnValue}
833
+ `;
834
+ return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
835
+ }
836
+ return normalOperation(style);
837
+ }
838
+ function handleResponse(spec, operationName, status, response, utils) {
1065
839
  const schemas = {};
1066
840
  const imports = {};
1067
841
  const endpointImports = {
@@ -1075,89 +849,94 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
1075
849
  };
1076
850
  const responses = [];
1077
851
  const outputs = [];
1078
- const typeScriptDeserialzer = new TypeScriptDeserialzer(
1079
- spec,
1080
- (schemaName, zod) => {
1081
- schemas[schemaName] = zod;
1082
- imports[schemaName] = {
1083
- defaultImport: void 0,
1084
- isTypeOnly: true,
1085
- moduleSpecifier: `../models/${utils.makeImport(schemaName)}`,
1086
- namedImports: [{ isTypeOnly: true, name: schemaName }],
1087
- namespaceImport: void 0
852
+ const typeScriptDeserialzer = new TypeScriptEmitter(spec);
853
+ const statusCode = +status;
854
+ const statusName = `http.${status_map_default[status] || "APIResponse"}`;
855
+ const interfaceName = pascalcase3(sanitizeTag3(response["x-response-name"]));
856
+ let parser = "buffered";
857
+ if (isEmpty(response.content)) {
858
+ responses.push({
859
+ name: interfaceName,
860
+ schema: "void",
861
+ description: response.description
862
+ });
863
+ } else {
864
+ const contentTypeResult = fromContentType(
865
+ spec,
866
+ typeScriptDeserialzer,
867
+ response
868
+ );
869
+ if (!contentTypeResult) {
870
+ throw new Error(
871
+ `No recognizable content type for response ${status} in operation ${operationName}`
872
+ );
873
+ }
874
+ parser = contentTypeResult.parser;
875
+ const responseSchema = contentTypeResult.responseSchema;
876
+ responses.push({
877
+ name: interfaceName,
878
+ schema: responseSchema,
879
+ description: response.description
880
+ });
881
+ if (isErrorStatusCode(statusCode)) {
882
+ endpointImports[status_map_default[status] ?? "APIError"] = {
883
+ moduleSpecifier: utils.makeImport("../http/response"),
884
+ namedImports: [{ name: status_map_default[status] ?? "APIError" }]
1088
885
  };
886
+ } else if (isSuccessStatusCode(statusCode)) {
1089
887
  }
1090
- );
1091
- const statusCode = +status;
1092
- const parser = (response.headers ?? {})["Transfer-Encoding"] ? "chunked" : "buffered";
1093
- const statusName = `http.${statusCodeToResponseMap[status] || "APIResponse"}`;
1094
- const interfaceName = pascalcase(
1095
- operationName + ` output${numbered ? status : ""}`
1096
- );
888
+ }
1097
889
  if (statusCode === 204) {
1098
890
  outputs.push(statusName);
1099
891
  } else {
1100
892
  if (status.endsWith("XX")) {
1101
- outputs.push(`http.APIError<${interfaceName}>`);
893
+ outputs.push(`http.APIError<outputs.${interfaceName}>`);
1102
894
  } else {
1103
895
  outputs.push(
1104
- parser !== "buffered" ? `{type: ${statusName}<${interfaceName}>, parser: ${parser}}` : `${statusName}<${interfaceName}>`
896
+ parser !== "buffered" ? `{type: ${statusName}<outputs.${interfaceName}>, parser: ${parser}}` : `${statusName}<outputs.${interfaceName}>`
1105
897
  );
1106
898
  }
1107
899
  }
1108
- const responseContent = get(response, ["content"]);
1109
- const isJson = responseContent && responseContent["application/json"];
1110
- let responseSchema = parser === "chunked" ? "ReadableStream" : "void";
1111
- if (isJson) {
1112
- const schema = responseContent["application/json"].schema;
1113
- const isObject = !isRef5(schema) && schema.type === "object";
1114
- if (isObject && schema.properties) {
1115
- schema.properties["[http.KIND]"] = {
1116
- "x-internal": true,
1117
- const: `typeof ${statusName}.kind`,
1118
- type: "string"
900
+ return { schemas, imports, endpointImports, responses, outputs };
901
+ }
902
+ function fromContentType(spec, typeScriptDeserialzer, response) {
903
+ if ((response.headers ?? {})["Transfer-Encoding"]) {
904
+ return streamedOutput();
905
+ }
906
+ for (const type in response.content) {
907
+ if (isStreamingContentType(type)) {
908
+ return streamedOutput();
909
+ }
910
+ if (parseJsonContentType(type)) {
911
+ return {
912
+ parser: "buffered",
913
+ responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "void"
914
+ };
915
+ }
916
+ if (isTextContentType(type)) {
917
+ return {
918
+ parser: "buffered",
919
+ responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "void"
1119
920
  };
1120
- schema.required ??= [];
1121
- schema.required.push("[http.KIND]");
1122
921
  }
1123
- responseSchema = typeScriptDeserialzer.handle(schema, true);
1124
- }
1125
- responses.push({
1126
- name: interfaceName,
1127
- schema: responseSchema,
1128
- description: response.description
1129
- });
1130
- const statusGroup = +status.slice(0, 1);
1131
- if (statusCode >= 400 || statusGroup >= 4) {
1132
- endpointImports[statusCodeToResponseMap[status] ?? "APIError"] = {
1133
- moduleSpecifier: utils.makeImport("../http/response"),
1134
- namedImports: [{ name: statusCodeToResponseMap[status] ?? "APIError" }]
1135
- };
1136
- endpointImports[interfaceName] = {
1137
- isTypeOnly: true,
1138
- moduleSpecifier: `../outputs/${utils.makeImport(spinalcase(operationName))}`,
1139
- namedImports: [{ isTypeOnly: true, name: interfaceName }]
1140
- };
1141
- } else if (statusCode >= 200 && statusCode < 300 || statusCode >= 2 || statusGroup <= 3) {
1142
- endpointImports[interfaceName] = {
1143
- defaultImport: void 0,
1144
- isTypeOnly: true,
1145
- moduleSpecifier: `../outputs/${utils.makeImport(spinalcase(operationName))}`,
1146
- namedImports: [{ isTypeOnly: true, name: interfaceName }],
1147
- namespaceImport: void 0
1148
- };
1149
922
  }
1150
- return { schemas, imports, endpointImports, responses, outputs };
923
+ return streamedOutput();
924
+ }
925
+ function streamedOutput() {
926
+ return {
927
+ parser: "chunked",
928
+ responseSchema: "ReadableStream"
929
+ };
1151
930
  }
1152
931
 
1153
932
  // packages/typescript/src/lib/styles/github/endpoints.txt
1154
- var endpoints_default = "type Output<T extends OutputType> = T extends {\n parser: Parser;\n type: Type<unknown>;\n}\n ? InstanceType<T['type']>\n : T extends Type<unknown>\n ? InstanceType<T>\n : never;\n\ntype Unionize<T> = T extends [infer Single extends OutputType]\n ? Output<Single>\n : T extends readonly [...infer Tuple extends OutputType[]]\n ? { [I in keyof Tuple]: Output<Tuple[I]> }[number]\n : never;\n\ntype EndpointOutput<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n SuccessfulResponse\n>;\n\ntype EndpointError<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n ProblematicResponse\n>;\n\nexport type Endpoints = {\n [K in keyof typeof schemas]: {\n input: z.infer<(typeof schemas)[K]['schema']>;\n output: <% if (outputType === 'default') { %>EndpointOutput<K>['data']<% } else { %>EndpointOutput<K><% } %>;\n error: EndpointError<K> | ParseError<(typeof schemas)[K]['schema']>;\n };\n};";
933
+ var endpoints_default = "type EndpointOutput<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n SuccessfulResponse\n>;\n\ntype EndpointError<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n ProblematicResponse\n>;\n\nexport type Endpoints = {\n [K in keyof typeof schemas]: {\n input: z.infer<(typeof schemas)[K]['schema']>;\n output: <% if (outputType === 'default') { %>EndpointOutput<K>['data']<% } else { %>EndpointOutput<K><% } %>;\n error: EndpointError<K> | ParseError<(typeof schemas)[K]['schema']>;\n };\n};";
1155
934
 
1156
935
  // packages/typescript/src/lib/generator.ts
1157
936
  function generateCode(config) {
1158
937
  const commonZod = /* @__PURE__ */ new Map();
1159
938
  const commonZodImports = [];
1160
- const zodDeserialzer = new ZodDeserialzer(config.spec, (model, schema) => {
939
+ const zodDeserialzer = new ZodEmitter(config.spec, (model, schema) => {
1161
940
  commonZod.set(model, schema);
1162
941
  commonZodImports.push({
1163
942
  defaultImport: void 0,
@@ -1168,20 +947,18 @@ function generateCode(config) {
1168
947
  });
1169
948
  });
1170
949
  const groups = {};
1171
- const outputs = {};
1172
950
  const endpoints = {};
1173
- forEachOperation(config, (entry, operation) => {
951
+ forEachOperation(config.spec, (entry, operation) => {
1174
952
  console.log(`Processing ${entry.method} ${entry.path}`);
1175
953
  groups[entry.groupName] ??= [];
1176
954
  endpoints[entry.groupName] ??= [];
1177
955
  const inputs = {};
1178
956
  const additionalProperties = {};
1179
- for (const param of operation.parameters ?? []) {
1180
- if (isRef6(param)) {
1181
- throw new Error(`Found reference in parameter ${param.$ref}`);
1182
- }
957
+ for (const param of operation.parameters) {
1183
958
  if (!param.schema) {
1184
- throw new Error(`Schema not found for parameter ${param.name}`);
959
+ param.schema = {
960
+ type: "string"
961
+ };
1185
962
  }
1186
963
  inputs[param.name] = {
1187
964
  in: param.in,
@@ -1189,9 +966,12 @@ function generateCode(config) {
1189
966
  };
1190
967
  additionalProperties[param.name] = param;
1191
968
  }
1192
- const security2 = operation.security ?? [];
1193
969
  const securitySchemes = config.spec.components?.securitySchemes ?? {};
1194
- const securityOptions = securityToOptions(security2, securitySchemes);
970
+ const securityOptions = securityToOptions(
971
+ config.spec,
972
+ operation.security ?? [],
973
+ securitySchemes
974
+ );
1195
975
  Object.assign(inputs, securityOptions);
1196
976
  Object.entries(securityOptions).forEach(([name, value]) => {
1197
977
  additionalProperties[name] = {
@@ -1215,65 +995,43 @@ function generateCode(config) {
1215
995
  "application/xml": "xml",
1216
996
  "text/plain": "text"
1217
997
  };
1218
- let outgoingContentType;
1219
- if (!isEmpty(operation.requestBody)) {
1220
- const requestBody = isRef6(operation.requestBody) ? followRef5(config.spec, operation.requestBody.$ref) : operation.requestBody;
1221
- for (const type in requestBody.content) {
1222
- const ctSchema = isRef6(requestBody.content[type].schema) ? followRef5(config.spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
1223
- if (!ctSchema) {
1224
- console.warn(
1225
- `Schema not found for ${type} in ${entry.method} ${entry.path}`
1226
- );
1227
- continue;
1228
- }
1229
- let objectSchema = ctSchema;
998
+ let outgoingContentType = "empty";
999
+ for (const type in operation.requestBody.content) {
1000
+ let objectSchema = resolveRef(
1001
+ config.spec,
1002
+ operation.requestBody.content[type].schema
1003
+ );
1004
+ if (type === "application/empty") {
1005
+ objectSchema = {
1006
+ type: "object",
1007
+ // properties: objectSchema['x-properties'],
1008
+ additionalProperties: isEmpty2(objectSchema["x-properties"])
1009
+ };
1010
+ } else {
1230
1011
  if (objectSchema.type !== "object") {
1231
1012
  objectSchema = {
1232
1013
  type: "object",
1233
- required: [requestBody.required ? "$body" : ""],
1014
+ required: [operation.requestBody.required ? "$body" : ""],
1234
1015
  properties: {
1235
- $body: ctSchema
1016
+ $body: objectSchema
1017
+ // ...objectSchema['x-properties'],
1236
1018
  }
1237
1019
  };
1238
1020
  }
1239
- const schema = merge({}, objectSchema, {
1240
- required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
1241
- properties: Object.entries(additionalProperties).reduce(
1242
- (acc, [, p]) => ({
1243
- ...acc,
1244
- [p.name]: p.schema
1245
- }),
1246
- {}
1247
- )
1248
- });
1249
- Object.assign(inputs, bodyInputs(config, objectSchema));
1250
- schemas[shortContenTypeMap[type]] = zodDeserialzer.handle(schema, true);
1251
- }
1252
- if (requestBody.content["application/json"]) {
1253
- outgoingContentType = "json";
1254
- } else if (requestBody.content["application/x-www-form-urlencoded"]) {
1255
- outgoingContentType = "urlencoded";
1256
- } else if (requestBody.content["multipart/form-data"]) {
1257
- outgoingContentType = "formdata";
1258
- } else {
1259
- outgoingContentType = "json";
1260
1021
  }
1261
- } else {
1262
- const properties = Object.entries(additionalProperties).reduce(
1263
- (acc, [, p]) => ({
1264
- ...acc,
1265
- [p.name]: p.schema
1266
- }),
1267
- {}
1268
- );
1269
- schemas[shortContenTypeMap["application/json"]] = zodDeserialzer.handle(
1270
- {
1271
- type: "object",
1272
- required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
1273
- properties
1274
- },
1275
- true
1276
- );
1022
+ const schema = merge({}, objectSchema, {
1023
+ required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
1024
+ properties: Object.entries(additionalProperties).reduce((acc, [, p]) => ({ ...acc, [p.name]: p.schema }), {})
1025
+ });
1026
+ Object.assign(inputs, bodyInputs(config.spec, objectSchema));
1027
+ schemas[shortContenTypeMap[type]] = zodDeserialzer.handle(schema, true);
1028
+ }
1029
+ if (operation.requestBody.content["application/json"]) {
1030
+ outgoingContentType = "json";
1031
+ } else if (operation.requestBody.content["application/x-www-form-urlencoded"]) {
1032
+ outgoingContentType = "urlencoded";
1033
+ } else if (operation.requestBody.content["multipart/form-data"]) {
1034
+ outgoingContentType = "formdata";
1277
1035
  }
1278
1036
  const endpoint = toEndpoint(
1279
1037
  entry.groupName,
@@ -1282,79 +1040,30 @@ function generateCode(config) {
1282
1040
  {
1283
1041
  outgoingContentType,
1284
1042
  name: operation.operationId,
1285
- type: "http",
1286
- trigger: entry,
1043
+ method: entry.method,
1044
+ path: entry.path,
1287
1045
  schemas,
1288
1046
  inputs
1289
1047
  },
1290
- { makeImport: config.makeImport }
1291
- );
1292
- const output = [
1293
- `import z from 'zod';`,
1294
- `import type * as http from '../http';`
1295
- ];
1296
- const responses = endpoint.responses.flatMap((it) => it.responses);
1297
- const responsesImports = endpoint.responses.flatMap(
1298
- (it) => Object.values(it.imports)
1048
+ { makeImport: config.makeImport, style: config.style }
1299
1049
  );
1300
- if (responses.length) {
1301
- output.push(
1302
- ...responses.map(
1303
- (it) => `${it.description ? `
1304
- /**
1305
- * ${it.description}
1306
- */
1307
- ` : ""} export type ${it.name} = ${it.schema};`
1308
- )
1309
- );
1310
- } else {
1311
- output.push(
1312
- `export type ${pascalcase2(operation.operationId + " output")} = void;`
1313
- );
1314
- }
1315
- output.unshift(...useImports(output.join(""), ...responsesImports));
1316
- outputs[`${spinalcase2(operation.operationId)}.ts`] = output.join("\n");
1317
1050
  endpoints[entry.groupName].push(endpoint);
1318
1051
  groups[entry.groupName].push({
1319
1052
  name: operation.operationId,
1320
- type: "http",
1321
1053
  inputs,
1322
1054
  outgoingContentType,
1323
1055
  schemas,
1324
- trigger: entry
1056
+ method: entry.method,
1057
+ path: entry.path
1325
1058
  });
1326
1059
  });
1327
- const commonSchemas = Object.values(endpoints).reduce(
1328
- (acc, endpoint) => ({
1329
- ...acc,
1330
- ...endpoint.reduce(
1331
- (acc2, { responses }) => ({
1332
- ...acc2,
1333
- ...responses.reduce(
1334
- (acc3, it) => ({ ...acc3, ...it.schemas }),
1335
- {}
1336
- )
1337
- }),
1338
- {}
1339
- )
1340
- }),
1341
- {}
1342
- );
1343
1060
  const allSchemas = Object.keys(endpoints).map((it) => ({
1344
- import: `import ${camelcase3(it)} from './${config.makeImport(spinalcase2(it))}';`,
1345
- use: ` ...${camelcase3(it)}`
1061
+ import: `import ${camelcase2(it)} from './${config.makeImport(spinalcase(it))}';`,
1062
+ use: ` ...${camelcase2(it)}`
1346
1063
  }));
1347
- const imports = [
1348
- 'import z from "zod";',
1349
- `import type { ParseError } from '${config.makeImport("../http/parser")}';`,
1350
- `import type { ServerError } from '${config.makeImport("../http/response")}';`,
1351
- `import type { OutputType, Parser, Type } from '../http/send-request.ts';`
1352
- ];
1353
1064
  return {
1354
1065
  groups,
1355
- commonSchemas,
1356
1066
  commonZod,
1357
- outputs,
1358
1067
  endpoints: {
1359
1068
  [join("api", "endpoints.ts")]: `
1360
1069
 
@@ -1364,12 +1073,9 @@ import type { ParseError } from '${config.makeImport("../http/parser")}';
1364
1073
  import type { ProblematicResponse, SuccessfulResponse } from '${config.makeImport(
1365
1074
  "../http/response"
1366
1075
  )}';
1367
- import type { OutputType, Parser, Type } from '${config.makeImport(
1368
- "../http/send-request"
1369
- )}';
1370
1076
 
1371
1077
  import schemas from '${config.makeImport("./schemas")}';
1372
-
1078
+ import type { Unionize } from '${config.makeImport("../http/dispatcher")}';
1373
1079
  ${template(endpoints_default)({ outputType: config.style?.outputType })}`,
1374
1080
  [`${join("api", "schemas.ts")}`]: `${allSchemas.map((it) => it.import).join("\n")}
1375
1081
  import { KIND } from "${config.makeImport("../http/index")}";
@@ -1391,14 +1097,18 @@ ${allSchemas.map((it) => it.use).join(",\n")}
1391
1097
  );
1392
1098
  return [
1393
1099
  [
1394
- join("api", `${spinalcase2(name)}.ts`),
1100
+ join("api", `${spinalcase(name)}.ts`),
1395
1101
  `${[
1396
1102
  ...imps,
1397
1103
  `import z from 'zod';`,
1398
1104
  `import * as http from '${config.makeImport("../http/response")}';`,
1399
- `import { toRequest, json, urlencoded, nobody, formdata, createUrl } from '${config.makeImport("../http/request")}';`,
1105
+ `import * as outputs from '${config.makeImport("../outputs/index")}';`,
1106
+ `import { toRequest, json, urlencoded, empty, formdata, createUrl, type HeadersInit } from '${config.makeImport("../http/request")}';`,
1400
1107
  `import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
1401
- `import * as ${camelcase3(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`
1108
+ `import * as ${camelcase2(name)} from '../inputs/${config.makeImport(spinalcase(name))}';`,
1109
+ `import { createBaseUrlInterceptor, createHeadersInterceptor, type Interceptor } from '${config.makeImport("../http/interceptors")}';`,
1110
+ `import { Dispatcher, fetchType, type InstanceType } from '${config.makeImport("../http/dispatcher")}';`,
1111
+ `import { Pagination, OffsetPagination, CursorPagination } from "${config.makeImport("../pagination/index")}";`
1402
1112
  ].join(
1403
1113
  "\n"
1404
1114
  )}
@@ -1413,8 +1123,8 @@ ${endpoint.flatMap((it) => it.schemas).join(",\n")}
1413
1123
  };
1414
1124
  }
1415
1125
  function toProps(spec, schemaOrRef, aggregator = []) {
1416
- if (isRef6(schemaOrRef)) {
1417
- const schema = followRef5(spec, schemaOrRef.$ref);
1126
+ if (isRef4(schemaOrRef)) {
1127
+ const schema = followRef4(spec, schemaOrRef.$ref);
1418
1128
  return toProps(spec, schema, aggregator);
1419
1129
  } else if (schemaOrRef.type === "object") {
1420
1130
  for (const [name] of Object.entries(schemaOrRef.properties ?? {})) {
@@ -1443,9 +1153,9 @@ function toProps(spec, schemaOrRef, aggregator = []) {
1443
1153
  console.warn("Unknown schema in body", schemaOrRef);
1444
1154
  return void 0;
1445
1155
  }
1446
- function bodyInputs(config, ctSchema) {
1156
+ function bodyInputs(spec, ctSchema) {
1447
1157
  const props = [];
1448
- toProps(config.spec, ctSchema, props);
1158
+ toProps(spec, ctSchema, props);
1449
1159
  return props.reduce(
1450
1160
  (acc, prop) => ({
1451
1161
  ...acc,
@@ -1458,6 +1168,9 @@ function bodyInputs(config, ctSchema) {
1458
1168
  );
1459
1169
  }
1460
1170
 
1171
+ // packages/typescript/src/lib/http/dispatcher.txt
1172
+ var dispatcher_default = "export type Unionize<T> = T extends [infer Single extends OutputType]\n ? InstanceType<Single>\n : T extends readonly [...infer Tuple extends OutputType[]]\n ? { [I in keyof Tuple]: InstanceType<Tuple[I]> }[number]\n : never;\n\nexport type InstanceType<T> =\n T extends Type<infer U>\n ? U\n : T extends { type: Type<infer U> }\n ? U\n : T extends Array<unknown>\n ? Unionize<T>\n : never;\n\nexport interface Type<T> {\n new (...args: any[]): T;\n}\nexport type Parser = (\n response: Response,\n) => Promise<unknown> | ReadableStream<any>;\nexport type OutputType =\n | Type<APIResponse>\n | { parser: Parser; type: Type<APIResponse> };\n\nexport const fetchType = z\n .function()\n .args(z.instanceof(Request))\n .returns(z.promise(z.instanceof(Response)))\n .optional();\n\nexport async function parse<T extends OutputType[]>(\n outputs: T,\n response: Response,\n) <% if(!throwError) { %>\n: Promise<\n [\n Extract<InstanceType<T>, SuccessfulResponse>['data'],\n Extract<InstanceType<T>, ProblematicResponse>['data'],\n ]\n>\n <% } %>\n\n\n\n {\n let output: typeof APIResponse | null = null;\n let parser: Parser = buffered;\n for (const outputType of outputs) {\n if ('parser' in outputType) {\n parser = outputType.parser;\n if (isTypeOf(outputType.type, APIResponse)) {\n if (response.status === outputType.type.status) {\n output = outputType.type;\n break;\n }\n }\n } else if (isTypeOf(outputType, APIResponse)) {\n if (response.status === outputType.status) {\n output = outputType;\n break;\n }\n }\n }\n\n\n if (response.ok) {\n const apiresponse = (output || APIResponse).create(\n response.status,\n await parser(response),\n );\n <% if(throwError) { %>\n return <% if (outputType === 'default') { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse><% } else { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse>;<% } %>;\n <% } else { %>\n return [<% if (outputType === 'default') { %>apiresponse.data as Extract<InstanceType<T>, SuccessfulResponse>['data']<% } else { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse><% } %>, null] as const;\n <% } %>\n }\n<% if(throwError) { %>\n throw (output || APIError).create(\n response.status,\n await parser(response),\n );\n<% } else { %>\n const data = (output || APIError).create(\n response.status,\n await parser(response),\n );\n return [null, data] as const;\n<% } %>\n}\n\nexport function isTypeOf<T extends Type<APIResponse>>(\n instance: any,\n baseType: T,\n): instance is T {\n if (instance === baseType) {\n return true;\n }\n const prototype = Object.getPrototypeOf(instance);\n if (prototype === null) {\n return false;\n }\n return isTypeOf(prototype, baseType);\n}\n\nexport class Dispatcher {\n #interceptors: Interceptor[] = [];\n #fetch: z.infer<typeof fetchType>;\n constructor(interceptors: Interceptor[], fetch?: z.infer<typeof fetchType>) {\n this.#interceptors = interceptors;\n this.#fetch = fetch;\n }\n\n async send<T extends OutputType[]>(\n config: RequestConfig,\n outputs: T,\n signal?: AbortSignal,\n ) {\n for (const interceptor of this.#interceptors) {\n if (interceptor.before) {\n config = await interceptor.before(config);\n }\n }\n\n let response = await (this.#fetch ?? fetch)(\n new Request(config.url, config.init),\n {\n ...config.init,\n signal: signal,\n },\n );\n\n for (let i = this.#interceptors.length - 1; i >= 0; i--) {\n const interceptor = this.#interceptors[i];\n if (interceptor.after) {\n response = await interceptor.after(response.clone());\n }\n }\n\n return await parse(outputs, response);\n }\n}\n";
1173
+
1461
1174
  // packages/typescript/src/lib/http/interceptors.txt
1462
1175
  var interceptors_default = "export interface Interceptor {\n before?: (config: RequestConfig) => Promise<RequestConfig> | RequestConfig;\n after?: (response: Response) => Promise<Response> | Response;\n}\n\nexport const createHeadersInterceptor = (\n defaultHeaders: () => Record<string, string | undefined>,\n requestHeaders: HeadersInit,\n):Interceptor => {\n return {\n before({init, url}) {\n // Priority Levels\n // 1. Headers Input\n // 2. Request Headers\n // 3. Default Headers\n const headers = defaultHeaders();\n\n for (const [key, value] of new Headers(requestHeaders)) {\n // Only set the header if it doesn't already exist and has a value\n // even though these headers are passed at operation level\n // still they are lower priority compared to the headers input\n if (value !== undefined && !init.headers.has(key)) {\n init.headers.set(key, value);\n }\n }\n\n for (const [key, value] of Object.entries(headers)) {\n // Only set the header if it doesn't already exist and has a value\n if (value !== undefined && !init.headers.has(key)) {\n init.headers.set(key, value);\n }\n }\n\n return {init, url};\n },\n };\n};\n\nexport const createBaseUrlInterceptor = (\n getBaseUrl: () => string,\n): Interceptor => {\n return {\n before({ init, url }) {\n const baseUrl = getBaseUrl();\n if (url.protocol === 'local:') {\n return {\n init,\n url: new URL(url.href.replace('local://', baseUrl))\n };\n }\n return { init, url };\n },\n };\n};\n\nexport const logInterceptor: Interceptor = {\n before({ url, init }) {\n console.log('Request:', { url, init });\n return { url, init };\n },\n after(response) {\n console.log('Response:', response);\n return response;\n },\n};\n\n/**\n * Creates an interceptor that logs detailed information about requests and responses.\n * @param options Configuration options for the logger\n * @returns An interceptor object with before and after handlers\n */\nexport const createDetailedLogInterceptor = (options?: {\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n includeRequestBody?: boolean;\n includeResponseBody?: boolean;\n}) => {\n const logLevel = options?.logLevel || 'info';\n const includeRequestBody = options?.includeRequestBody || false;\n const includeResponseBody = options?.includeResponseBody || false;\n\n return {\n async before(request: Request) {\n const logData = {\n url: request.url,\n method: request.method,\n contentType: request.headers.get('Content-Type'),\n headers: Object.fromEntries([...request.headers.entries()]),\n };\n\n console[logLevel]('\u{1F680} Outgoing Request:', logData);\n\n if (includeRequestBody) {\n try {\n // Clone the request to avoid consuming the body stream\n const clonedRequest = request.clone();\n if (clonedRequest.headers.get('Content-Type')?.includes('application/json')) {\n const body = await clonedRequest.json().catch(() => null);\n console[logLevel]('Request Body:', body);\n } else {\n const body = await clonedRequest.text().catch(() => null);\n console[logLevel]('Request Body:', body);\n }\n } catch (error) {\n console.error('Could not log request body:', error);\n }\n }\n\n return request;\n },\n\n async after(response: Response) {\n const logData = {\n status: response.status,\n statusText: response.statusText,\n url: response.url,\n headers: Object.fromEntries([...response.headers.entries()]),\n };\n\n console[logLevel]('\u{1F4E5} Incoming Response:', logData);\n\n if (includeResponseBody && response.body) {\n try {\n // Clone the response to avoid consuming the body stream\n const clonedResponse = response.clone();\n if (clonedResponse.headers.get('Content-Type')?.includes('application/json')) {\n const body = await clonedResponse.json().catch(() => null);\n console[logLevel]('Response Body:', body);\n } else {\n const body = await clonedResponse.text().catch(() => null);\n if (body) {\n console[logLevel]('Response Body:', body.substring(0, 500) + (body.length > 500 ? '...' : ''));\n } else {\n console[logLevel]('No response body');\n }\n }\n } catch (error) {\n console.error('Could not log response body:', error);\n }\n }\n\n return response;\n },\n };\n};\n";
1463
1176
 
@@ -1468,7 +1181,7 @@ var parse_response_default = 'import { parse } from "fast-content-type-parse";\n
1468
1181
  var parser_default = "import { z } from 'zod';\n\nexport class ParseError<T extends z.ZodType<any, any, any>> {\n public data: z.typeToFlattenedError<T, z.ZodIssue>;\n constructor(data: z.typeToFlattenedError<T, z.ZodIssue>) {\n this.data = data;\n }\n}\n\nexport function parseInput<T extends z.ZodType<any, any, any>>(\n schema: T,\n input: unknown,\n) {\n const result = schema.safeParse(input);\n if (!result.success) {\n const error = result.error.flatten((issue) => issue);\n return [null, new ParseError(error)];\n }\n return [result.data as z.infer<T>, null];\n}\n";
1469
1182
 
1470
1183
  // packages/typescript/src/lib/http/request.txt
1471
- var request_default = "type Init = Omit<RequestInit, 'headers'> & { headers: Headers; };\nexport type RequestConfig = { init: Init; url: URL };\nexport type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\nexport type ContentType = 'xml' | 'json' | 'urlencoded' | 'multipart' | 'formdata';\nexport type HeadersInit = [string, string][] | Record<string, string>;\nexport type Endpoint =\n | `${ContentType} ${Method} ${string}`\n | `${Method} ${string}`;\n\nexport type BodyInit =\n | ArrayBuffer\n | Blob\n | FormData\n | URLSearchParams\n | null\n | string;\n\nexport function createUrl(path: string, query: URLSearchParams) {\n const url = new URL(path, `local://`);\n url.search = query.toString();\n return url;\n}\n\nfunction template(\n templateString: string,\n templateVariables: Record<string, any>,\n): string {\n const nargs = /{([0-9a-zA-Z_]+)}/g;\n return templateString.replace(nargs, (match, key: string, index: number) => {\n // Handle escaped double braces\n if (\n templateString[index - 1] === '{' &&\n templateString[index + match.length] === '}'\n ) {\n return key;\n }\n\n const result = key in templateVariables ? templateVariables[key] : null;\n return result === null || result === undefined ? '' : String(result);\n });\n}\n\ntype Input = Record<string, any>;\ntype Props = {\n inputHeaders: string[];\n inputQuery: string[];\n inputBody: string[];\n inputParams: string[];\n};\n\nabstract class Serializer {\n protected input: Input;\n protected props: Props;\n\n constructor(\n input: Input,\n props: Props,\n ) {\n this.input = input;\n this.props = props;\n }\n\n abstract getBody(): BodyInit | null;\n abstract getHeaders(): Record<string, string>;\n serialize(): Serialized {\n const headers = new Headers({});\n for (const header of this.props.inputHeaders) {\n headers.set(header, this.input[header]);\n }\n\n const query = new URLSearchParams();\n for (const key of this.props.inputQuery) {\n const value = this.input[key];\n if (value !== undefined) {\n query.set(key, String(value));\n }\n }\n\n const params = this.props.inputParams.reduce<Record<string, any>>(\n (acc, key) => {\n acc[key] = this.input[key];\n return acc;\n },\n {},\n );\n\n return {\n body: this.getBody(),\n query,\n params,\n headers: this.getHeaders(),\n };\n }\n}\n\ninterface Serialized {\n body: BodyInit | null;\n query: URLSearchParams;\n params: Record<string, any>;\n headers: Record<string, string>;\n}\n\nclass JsonSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body: Record<string, any> = {};\n if (\n this.props.inputBody.length === 1 &&\n this.props.inputBody[0] === '$body'\n ) {\n return JSON.stringify(this.input.$body);\n }\n\n for (const prop of this.props.inputBody) {\n body[prop] = this.input[prop];\n }\n return JSON.stringify(body);\n }\n getHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n }\n}\n\nclass UrlencodedSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body = new URLSearchParams();\n for (const prop of this.props.inputBody) {\n body.set(prop, this.input[prop]);\n }\n return body;\n }\n getHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n }\n}\n\nclass NoBodySerializer extends Serializer {\n getBody(): BodyInit | null {\n return null;\n }\n getHeaders(): Record<string, string> {\n return {};\n }\n}\n\nclass FormDataSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body = new FormData();\n for (const prop of this.props.inputBody) {\n body.append(prop, this.input[prop]);\n }\n return body;\n }\n getHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n };\n }\n}\n\nexport function json(input: Input, props: Props) {\n return new JsonSerializer(input, props).serialize();\n}\nexport function urlencoded(input: Input, props: Props) {\n return new UrlencodedSerializer(input, props).serialize();\n}\nexport function nobody(input: Input, props: Props) {\n return new NoBodySerializer(input, props).serialize();\n}\nexport function formdata(input: Input, props: Props) {\n return new FormDataSerializer(input, props).serialize();\n}\n\nexport function toRequest<T extends Endpoint>(\n endpoint: T,\n input: Serialized,\n): RequestConfig {\n const [method, path] = endpoint.split(' ');\n const pathVariable = template(path, input.params);\n\n return {\n url: createUrl(pathVariable, input.query),\n init: {\n method: method,\n headers: new Headers(input.headers),\n body: method === 'GET' ? undefined : input.body,\n },\n }\n}\n";
1184
+ var request_default = "type Init = Omit<RequestInit, 'headers'> & { headers: Headers; };\nexport type RequestConfig = { init: Init; url: URL };\nexport type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\nexport type ContentType = 'xml' | 'json' | 'urlencoded' | 'multipart' | 'formdata';\nexport type HeadersInit = [string, string][] | Record<string, string>;\nexport type Endpoint =\n | `${ContentType} ${Method} ${string}`\n | `${Method} ${string}`;\n\nexport type BodyInit =\n | ArrayBuffer\n | Blob\n | FormData\n | URLSearchParams\n | null\n | string;\n\nexport function createUrl(path: string, query: URLSearchParams) {\n const url = new URL(path, `local://`);\n url.search = query.toString();\n return url;\n}\n\nfunction template(\n templateString: string,\n templateVariables: Record<string, any>,\n): string {\n const nargs = /{([0-9a-zA-Z_]+)}/g;\n return templateString.replace(nargs, (match, key: string, index: number) => {\n // Handle escaped double braces\n if (\n templateString[index - 1] === '{' &&\n templateString[index + match.length] === '}'\n ) {\n return key;\n }\n\n const result = key in templateVariables ? templateVariables[key] : null;\n return result === null || result === undefined ? '' : String(result);\n });\n}\n\ntype Input = Record<string, any>;\ntype Props = {\n inputHeaders: string[];\n inputQuery: string[];\n inputBody: string[];\n inputParams: string[];\n};\n\nabstract class Serializer {\n protected input: Input;\n protected props: Props;\n\n constructor(\n input: Input,\n props: Props,\n ) {\n this.input = input;\n this.props = props;\n }\n\n abstract getBody(): BodyInit | null;\n abstract getHeaders(): Record<string, string>;\n serialize(): Serialized {\n const headers = new Headers({});\n for (const header of this.props.inputHeaders) {\n headers.set(header, this.input[header]);\n }\n\n const query = new URLSearchParams();\n for (const key of this.props.inputQuery) {\n const value = this.input[key];\n if (value !== undefined) {\n query.set(key, String(value));\n }\n }\n\n const params = this.props.inputParams.reduce<Record<string, any>>(\n (acc, key) => {\n acc[key] = this.input[key];\n return acc;\n },\n {},\n );\n\n return {\n body: this.getBody(),\n query,\n params,\n headers: this.getHeaders(),\n };\n }\n}\n\ninterface Serialized {\n body: BodyInit | null;\n query: URLSearchParams;\n params: Record<string, any>;\n headers: Record<string, string>;\n}\n\nclass JsonSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body: Record<string, any> = {};\n if (\n this.props.inputBody.length === 1 &&\n this.props.inputBody[0] === '$body'\n ) {\n return JSON.stringify(this.input.$body);\n }\n\n for (const prop of this.props.inputBody) {\n body[prop] = this.input[prop];\n }\n return JSON.stringify(body);\n }\n getHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n }\n}\n\nclass UrlencodedSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body = new URLSearchParams();\n for (const prop of this.props.inputBody) {\n body.set(prop, this.input[prop]);\n }\n return body;\n }\n getHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n }\n}\n\nclass EmptySerializer extends Serializer {\n getBody(): BodyInit | null {\n return null;\n }\n getHeaders(): Record<string, string> {\n return {};\n }\n}\n\nclass FormDataSerializer extends Serializer {\n getBody(): BodyInit | null {\n const body = new FormData();\n for (const prop of this.props.inputBody) {\n body.append(prop, this.input[prop]);\n }\n return body;\n }\n getHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n };\n }\n}\n\nexport function json(input: Input, props: Props) {\n return new JsonSerializer(input, props).serialize();\n}\nexport function urlencoded(input: Input, props: Props) {\n return new UrlencodedSerializer(input, props).serialize();\n}\nexport function empty(input: Input, props: Props) {\n return new EmptySerializer(input, props).serialize();\n}\nexport function formdata(input: Input, props: Props) {\n return new FormDataSerializer(input, props).serialize();\n}\n\nexport function toRequest<T extends Endpoint>(\n endpoint: T,\n input: Serialized,\n): RequestConfig {\n const [method, path] = endpoint.split(' ');\n const pathVariable = template(path, input.params);\n\n return {\n url: createUrl(pathVariable, input.query),\n init: {\n method: method,\n headers: new Headers(input.headers),\n body: method === 'GET' ? undefined : input.body,\n },\n }\n}\n";
1472
1185
 
1473
1186
  // packages/typescript/src/lib/http/response.txt
1474
1187
  var response_default = `export const KIND = Symbol('APIDATA');
@@ -1702,6 +1415,28 @@ export class Gone<T = { message: string }> extends APIError<T, 410> {
1702
1415
  return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1703
1416
  }
1704
1417
  }
1418
+ export class PreconditionFailed<T = { message: string }> extends APIError<T, 412> {
1419
+ static override readonly kind = Symbol.for('PreconditionFailed');
1420
+ static override status = 412 as const;
1421
+ constructor(data: T) {
1422
+ super(PreconditionFailed.status, data);
1423
+ }
1424
+ static override create<T>(status: number, data: T) {
1425
+ Object.defineProperty(data, KIND, { value: this.kind });
1426
+ return new this(data);
1427
+ }
1428
+
1429
+ static is<T extends { [KIND]: (typeof PreconditionFailed)['kind'] }>(
1430
+ value: unknown,
1431
+ ): value is T {
1432
+ return (
1433
+ typeof value === 'object' &&
1434
+ value !== null &&
1435
+ KIND in value &&
1436
+ value[KIND] === this.kind
1437
+ );
1438
+ }
1439
+ }
1705
1440
  export class UnprocessableEntity<
1706
1441
  T = { message: string; errors?: Record<string, string[]> },
1707
1442
  > extends APIError<T, 422> {
@@ -1853,7 +1588,7 @@ export class GatewayTimeout<T = { message: string }> extends APIError<T, 504> {
1853
1588
  }
1854
1589
 
1855
1590
  export type ClientError =
1856
- | BadRequest<{ message: string }>
1591
+ | BadRequest<unknown>
1857
1592
  | Unauthorized<unknown>
1858
1593
  | PaymentRequired<unknown>
1859
1594
  | Forbidden<unknown>
@@ -1862,6 +1597,9 @@ export type ClientError =
1862
1597
  | NotAcceptable<unknown>
1863
1598
  | Conflict<unknown>
1864
1599
  | Gone<unknown>
1600
+ | PreconditionFailed<unknown>
1601
+ | PayloadTooLarge<unknown>
1602
+ | UnsupportedMediaType<unknown>
1865
1603
  | UnprocessableEntity<unknown>
1866
1604
  | TooManyRequests<unknown>;
1867
1605
 
@@ -1878,315 +1616,396 @@ export type SuccessfulResponse =
1878
1616
  | Ok<unknown>
1879
1617
  | Created<unknown>
1880
1618
  | Accepted<unknown>
1881
- | NoContent;
1882
- `;
1619
+ | NoContent;`;
1883
1620
 
1884
- // packages/typescript/src/lib/http/send-request.txt
1885
- var send_request_default = "export interface Type<T> {\n new (...args: any[]): T;\n}\nexport type Parser = (\n response: Response,\n) => Promise<unknown> | ReadableStream<any>;\nexport type OutputType =\n | Type<APIResponse>\n | { parser: Parser; type: Type<APIResponse> };\n\nexport interface RequestSchema {\n schema: z.ZodType;\n toRequest: (input: any) => RequestConfig;\n output: OutputType[];\n}\n\nexport const fetchType = z\n .function()\n .args(z.instanceof(Request))\n .returns(z.promise(z.instanceof(Response)))\n .optional();\n\nexport async function dispatch(\n input: unknown,\n route: RequestSchema,\n options: {\n fetch?: z.infer<typeof fetchType>;\n interceptors?: Interceptor[];\n signal?: AbortSignal;\n },\n) {\n const { interceptors = [] } = options;\n const [parsedInput, parseError] = parseInput(route.schema, input);\n if (parseError) {\n <% if(throwError) { %>\n throw parseError;\n <% } else { %>\n return [null as never, parseError as never] as const;\n <% } %>\n }\n\n let config = route.toRequest(parsedInput as never);\n for (const interceptor of interceptors) {\n if (interceptor.before) {\n config = await interceptor.before(config);\n }\n }\n\n let response = await (options.fetch ?? fetch)(\n new Request(config.url, config.init),\n {\n ...config.init,\n signal: options.signal,\n },\n );\n\n for (let i = interceptors.length - 1; i >= 0; i--) {\n const interceptor = interceptors[i];\n if (interceptor.after) {\n response = await interceptor.after(response.clone());\n }\n }\n return await parse(route, response);\n}\n\nexport async function parse(route: RequestSchema, response: Response) {\n let output: typeof APIResponse | null = null;\n let parser: Parser = buffered;\n for (const outputType of route.output) {\n if ('parser' in outputType) {\n parser = outputType.parser;\n if (isTypeOf(outputType.type, APIResponse)) {\n if (response.status === outputType.type.status) {\n output = outputType.type;\n break;\n }\n }\n } else if (isTypeOf(outputType, APIResponse)) {\n if (response.status === outputType.status) {\n output = outputType;\n break;\n }\n }\n }\n\n if (response.ok) {\n const apiresponse = (output || APIResponse).create(\n response.status,\n await parser(response),\n );\n <% if(throwError) { %>\n return <% if (outputType === 'default') { %>apiresponse.data<% } else { %>apiresponse<% } %>;\n <% } else { %>\n return [<% if (outputType === 'default') { %>apiresponse.data<% } else { %>apiresponse<% } %> , null] as const;\n <% } %>\n }\n<% if(throwError) { %>\n throw (output || APIError).create(\n response.status,\n await parser(response),\n );\n<% } else { %>\n const data = (output || APIError).create(\n response.status,\n await parser(response),\n );\n return [null as never, data as never] as const;\n<% } %>\n}\n\nexport function isTypeOf<T extends Type<APIResponse>>(\n instance: any,\n baseType: T,\n): instance is T {\n if (instance === baseType) {\n return true;\n }\n const prototype = Object.getPrototypeOf(instance);\n if (prototype === null) {\n return false;\n }\n return isTypeOf(prototype, baseType);\n}\n";
1621
+ // packages/typescript/src/lib/paginations/cursor-pagination.txt
1622
+ var cursor_pagination_default = "type CursorPaginationParams = {\n cursor?: string;\n};\n\ninterface CursorMetadata extends Metadata {\n nextCursor?: string;\n}\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends CursorMetadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<T, M extends CursorMetadata> = (\n input: CursorPaginationParams,\n) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class CursorPagination<T, M extends CursorMetadata> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: CursorPaginationParams;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M>;\n\n constructor(\n initialParams: PartialNullable<CursorPaginationParams>,\n fetchFn: FetchFn<T, M>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = {\n cursor: initialParams.cursor ?? undefined,\n };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n cursor: result.meta.nextCursor,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n\ntype PartialNullable<T> = {\n [K in keyof T]?: T[K] | null;\n};\n";
1886
1623
 
1887
- // packages/typescript/src/lib/readme.ts
1888
- import { followRef as followRef6, isRef as isRef7 } from "@sdk-it/core";
1889
- var PropEmitter = class {
1890
- #spec;
1624
+ // packages/typescript/src/lib/paginations/offset-pagination.txt
1625
+ var offset_pagination_default = "type OffsetPaginationParams = {\n offset: number;\n limit: number;\n};\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends Metadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<T, M extends Metadata> = (\n input: OffsetPaginationParams,\n) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class OffsetPagination<T, M extends Metadata> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: OffsetPaginationParams;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M>;\n\n constructor(\n initialParams: Partial<OffsetPaginationParams>,\n fetchFn: FetchFn<T, M>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = {\n limit: initialParams.limit ?? 0,\n offset: initialParams.offset ?? 0,\n };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n offset: this.#params.offset + this.#params.limit,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n\n reset(params?: Partial<OffsetPaginationParams>) {\n this.#meta = null;\n this.#currentPage = null;\n if (params) {\n this.#params = { ...this.#params, ...params };\n } else {\n this.#params.offset = 0;\n }\n return this;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n";
1626
+
1627
+ // packages/typescript/src/lib/paginations/page-pagination.txt
1628
+ var page_pagination_default = "type InferPage<T> = T extends Page<infer U> ? U : never;\ntype PaginationParams<P extends number | bigint, S extends number | bigint> = {\n page?: P;\n pageSize?: S;\n};\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends Metadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> = (input: Partial<PaginationParams<P, S>>) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class Pagination<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: PaginationParams<P, S>;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M, P, S>;\n\n constructor(\n initialParams: Partial<PaginationParams<P, S>>,\n fetchFn: FetchFn<T, M, P, S>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = { ...initialParams, page: initialParams.page };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n page: ((this.#params.page as number) || 0 + 1) as never,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n";
1629
+
1630
+ // packages/typescript/src/lib/typescript-snippet.ts
1631
+ import { camelcase as camelcase3, spinalcase as spinalcase2 } from "stringcase";
1632
+ import { isEmpty as isEmpty3, pascalcase as pascalcase4, resolveRef as resolveRef2 } from "@sdk-it/core";
1633
+ import {
1634
+ patchParameters,
1635
+ securityToOptions as securityToOptions2
1636
+ } from "@sdk-it/spec";
1637
+
1638
+ // packages/typescript/src/lib/emitters/snippet.ts
1639
+ import { followRef as followRef5, isRef as isRef5 } from "@sdk-it/core";
1640
+ var SnippetEmitter = class {
1641
+ spec;
1642
+ generatedRefs = /* @__PURE__ */ new Set();
1643
+ cache = /* @__PURE__ */ new Map();
1891
1644
  constructor(spec) {
1892
- this.#spec = spec;
1645
+ this.spec = spec;
1893
1646
  }
1894
- /**
1895
- * Handle objects (properties)
1896
- */
1897
- #object(schema) {
1898
- const lines = [];
1899
- const properties = schema.properties || {};
1900
- if (Object.keys(properties).length > 0) {
1901
- lines.push(`**Properties:**`);
1902
- for (const [propName, propSchema] of Object.entries(properties)) {
1903
- const isRequired = (schema.required ?? []).includes(propName);
1904
- lines.push(...this.#property(propName, propSchema, isRequired));
1647
+ object(schema) {
1648
+ const schemaObj = isRef5(schema) ? followRef5(this.spec, schema.$ref) : schema;
1649
+ const result = {};
1650
+ const properties = schemaObj.properties || {};
1651
+ for (const [propName, propSchema] of Object.entries(properties)) {
1652
+ const isRequired = (schemaObj.required ?? []).includes(propName);
1653
+ const resolvedProp = isRef5(propSchema) ? followRef5(this.spec, propSchema.$ref) : propSchema;
1654
+ if (isRequired || resolvedProp.example !== void 0 || resolvedProp.default !== void 0 || Math.random() > 0.5) {
1655
+ result[propName] = this.handle(propSchema);
1905
1656
  }
1906
1657
  }
1907
- if (schema.additionalProperties) {
1908
- lines.push(`**Additional Properties:**`);
1909
- if (typeof schema.additionalProperties === "boolean") {
1910
- lines.push(`- Allowed: ${schema.additionalProperties}`);
1911
- } else {
1912
- lines.push(
1913
- ...this.handle(schema.additionalProperties).map((l) => ` ${l}`)
1914
- );
1915
- }
1658
+ if (schemaObj.additionalProperties && typeof schemaObj.additionalProperties === "object") {
1659
+ result["additionalPropExample"] = this.handle(
1660
+ schemaObj.additionalProperties
1661
+ );
1916
1662
  }
1917
- return lines;
1918
- }
1919
- /**
1920
- * Format a property with its type and description
1921
- */
1922
- #property(name, schema, required) {
1923
- const requiredMark = required ? " (required)" : "";
1924
- const propNameLine = `- \`${name}\`${requiredMark}:`;
1925
- const lines = [propNameLine];
1926
- const schemaDocs = this.handle(schema);
1927
- lines.push(...schemaDocs.map((line) => ` ${line}`));
1928
- return lines;
1663
+ return result;
1929
1664
  }
1930
- /**
1931
- * Handle array schemas
1932
- */
1933
- #array(schema) {
1934
- const lines = [];
1935
- lines.push(`**Array items:**`);
1936
- if (schema.items) {
1937
- const itemDocs = this.handle(schema.items);
1938
- lines.push(...itemDocs.map((line) => ` ${line}`));
1939
- } else {
1940
- lines.push(` **Type:** \`unknown\``);
1941
- }
1942
- if (schema.minItems !== void 0)
1943
- lines.push(`- Minimum items: ${schema.minItems}`);
1944
- if (schema.maxItems !== void 0)
1945
- lines.push(`- Maximum items: ${schema.maxItems}`);
1946
- if (schema.uniqueItems)
1947
- lines.push(`- Items must be unique.`);
1948
- return lines;
1949
- }
1950
- #ref($ref) {
1951
- const schemaName = $ref.split("/").pop() || "object";
1952
- const resolved = followRef6(this.#spec, $ref);
1953
- const lines = [
1954
- `**Type:** [\`${schemaName}\`](#${schemaName.toLowerCase()})`
1955
- ];
1956
- if (resolved.description) {
1957
- lines.push(resolved.description);
1665
+ array(schema) {
1666
+ const schemaObj = isRef5(schema) ? followRef5(this.spec, schema.$ref) : schema;
1667
+ const itemsSchema = schemaObj.items;
1668
+ if (!itemsSchema) {
1669
+ return [];
1958
1670
  }
1959
- return lines;
1960
- }
1961
- #allOf(schemas) {
1962
- const lines = ["**All of (Intersection):**"];
1963
- schemas.forEach((subSchema, index) => {
1964
- lines.push(`- **Constraint ${index + 1}:**`);
1965
- const subLines = this.handle(subSchema);
1966
- lines.push(...subLines.map((l) => ` ${l}`));
1967
- });
1968
- return lines;
1969
- }
1970
- #anyOf(schemas) {
1971
- const lines = ["**Any of (Union):**"];
1972
- schemas.forEach((subSchema, index) => {
1973
- lines.push(`- **Option ${index + 1}:**`);
1974
- const subLines = this.handle(subSchema);
1975
- lines.push(...subLines.map((l) => ` ${l}`));
1976
- });
1977
- return lines;
1978
- }
1979
- #oneOf(schemas) {
1980
- const lines = ["**One of (Exclusive Union):**"];
1981
- schemas.forEach((subSchema, index) => {
1982
- lines.push(`- **Option ${index + 1}:**`);
1983
- const subLines = this.handle(subSchema);
1984
- lines.push(...subLines.map((l) => ` ${l}`));
1985
- });
1986
- return lines;
1987
- }
1988
- #enum(schema) {
1989
- const lines = [`**Type:** \`${schema.type || "unknown"}\` (enum)`];
1990
- if (schema.description)
1991
- lines.push(schema.description);
1992
- lines.push("**Allowed values:**");
1993
- lines.push(
1994
- ...(schema.enum || []).map((val) => `- \`${JSON.stringify(val)}\``)
1995
- );
1996
- if (schema.default !== void 0) {
1997
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
1671
+ const count = Math.min(schemaObj.minItems ?? 1, 2);
1672
+ const result = [];
1673
+ for (let i = 0; i < count; i++) {
1674
+ result.push(this.handle(itemsSchema));
1998
1675
  }
1999
- return lines;
1676
+ return result;
2000
1677
  }
2001
- #normal(type, schema, nullable) {
2002
- const lines = [];
2003
- const nullableSuffix = nullable ? " (nullable)" : "";
2004
- const description = schema.description ? [schema.description] : [];
2005
- switch (type) {
2006
- case "string":
2007
- lines.push(
2008
- `**Type:** \`string\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
2009
- );
2010
- lines.push(...description);
2011
- if (schema.minLength !== void 0)
2012
- lines.push(`- Minimum length: ${schema.minLength}`);
2013
- if (schema.maxLength !== void 0)
2014
- lines.push(`- Maximum length: ${schema.maxLength}`);
2015
- if (schema.pattern !== void 0)
2016
- lines.push(`- Pattern: \`${schema.pattern}\``);
2017
- break;
2018
- case "number":
2019
- case "integer":
2020
- lines.push(
2021
- `**Type:** \`${type}\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
2022
- );
2023
- lines.push(...description);
2024
- if (schema.minimum !== void 0) {
2025
- const exclusiveMin = typeof schema.exclusiveMinimum === "number";
2026
- lines.push(
2027
- `- Minimum: ${schema.minimum}${exclusiveMin ? " (exclusive)" : ""}`
2028
- );
2029
- if (exclusiveMin) {
2030
- lines.push(
2031
- `- Must be strictly greater than: ${schema.exclusiveMinimum}`
2032
- );
2033
- }
2034
- } else if (typeof schema.exclusiveMinimum === "number") {
2035
- lines.push(
2036
- `- Must be strictly greater than: ${schema.exclusiveMinimum}`
2037
- );
2038
- }
2039
- if (schema.maximum !== void 0) {
2040
- const exclusiveMax = typeof schema.exclusiveMaximum === "number";
2041
- lines.push(
2042
- `- Maximum: ${schema.maximum}${exclusiveMax ? " (exclusive)" : ""}`
2043
- );
2044
- if (exclusiveMax) {
2045
- lines.push(
2046
- `- Must be strictly less than: ${schema.exclusiveMaximum}`
2047
- );
2048
- }
2049
- } else if (typeof schema.exclusiveMaximum === "number") {
2050
- lines.push(
2051
- `- Must be strictly less than: ${schema.exclusiveMaximum}`
2052
- );
2053
- }
2054
- if (schema.multipleOf !== void 0)
2055
- lines.push(`- Must be a multiple of: ${schema.multipleOf}`);
2056
- break;
2057
- case "boolean":
2058
- lines.push(`**Type:** \`boolean\`${nullableSuffix}`);
2059
- lines.push(...description);
2060
- break;
2061
- case "object":
2062
- lines.push(`**Type:** \`object\`${nullableSuffix}`);
2063
- lines.push(...description);
2064
- lines.push(...this.#object(schema));
2065
- break;
2066
- case "array":
2067
- lines.push(`**Type:** \`array\`${nullableSuffix}`);
2068
- lines.push(...description);
2069
- lines.push(...this.#array(schema));
2070
- break;
2071
- case "null":
2072
- lines.push(`**Type:** \`null\``);
2073
- lines.push(...description);
2074
- break;
1678
+ string(schema) {
1679
+ if (schema.example !== void 0)
1680
+ return String(schema.example);
1681
+ if (schema.default !== void 0)
1682
+ return String(schema.default);
1683
+ switch (schema.format) {
1684
+ case "date-time":
1685
+ case "datetime":
1686
+ return (/* @__PURE__ */ new Date()).toISOString();
1687
+ case "date":
1688
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1689
+ case "time":
1690
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[1];
1691
+ case "email":
1692
+ return "user@example.com";
1693
+ case "uuid":
1694
+ return "123e4567-e89b-12d3-a456-426614174000";
1695
+ case "uri":
1696
+ case "url":
1697
+ return "https://example.com";
1698
+ case "ipv4":
1699
+ return "192.168.1.1";
1700
+ case "ipv6":
1701
+ return "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1702
+ case "hostname":
1703
+ return "example.com";
1704
+ case "binary":
1705
+ case "byte":
1706
+ return `new Blob(['example'], { type: 'text/plain' })`;
2075
1707
  default:
2076
- lines.push(`**Type:** \`${type}\`${nullableSuffix}`);
2077
- lines.push(...description);
1708
+ if (schema.enum && schema.enum.length > 0) {
1709
+ return String(schema.enum[0]);
1710
+ }
1711
+ return schema.pattern ? `string matching ${schema.pattern}` : "example";
2078
1712
  }
2079
- if (schema.default !== void 0) {
2080
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
1713
+ }
1714
+ number(schema) {
1715
+ if (schema.example !== void 0)
1716
+ return Number(schema.example);
1717
+ if (schema.default !== void 0)
1718
+ return Number(schema.default);
1719
+ let value;
1720
+ if (typeof schema.exclusiveMinimum === "number") {
1721
+ value = schema.exclusiveMinimum + 1;
1722
+ } else if (typeof schema.minimum === "number") {
1723
+ value = schema.minimum;
1724
+ } else {
1725
+ value = schema.type === "integer" ? 42 : 42.42;
1726
+ }
1727
+ if (typeof schema.exclusiveMaximum === "number" && value >= schema.exclusiveMaximum) {
1728
+ value = schema.exclusiveMaximum - 1;
1729
+ } else if (typeof schema.maximum === "number" && value > schema.maximum) {
1730
+ value = schema.maximum;
2081
1731
  }
2082
- return lines.filter((l) => l);
1732
+ if (typeof schema.multipleOf === "number" && value % schema.multipleOf !== 0) {
1733
+ value = Math.floor(value / schema.multipleOf) * schema.multipleOf;
1734
+ }
1735
+ return schema.type === "integer" ? Math.floor(value) : value;
1736
+ }
1737
+ boolean(schema) {
1738
+ if (schema.example !== void 0)
1739
+ return Boolean(schema.example);
1740
+ if (schema.default !== void 0)
1741
+ return Boolean(schema.default);
1742
+ return true;
1743
+ }
1744
+ null() {
1745
+ return null;
1746
+ }
1747
+ ref($ref) {
1748
+ const parts = $ref.split("/");
1749
+ const refKey = parts[parts.length - 1] || "";
1750
+ if (this.cache.has($ref)) {
1751
+ return this.cache.get($ref);
1752
+ }
1753
+ this.cache.set($ref, { _ref: refKey });
1754
+ const resolved = followRef5(this.spec, $ref);
1755
+ const result = this.handle(resolved);
1756
+ this.cache.set($ref, result);
1757
+ return result;
1758
+ }
1759
+ allOf(schemas) {
1760
+ const initial = {};
1761
+ return schemas.reduce((result, schema) => {
1762
+ const example = this.handle(schema);
1763
+ if (typeof example === "object" && example !== null) {
1764
+ return { ...result, ...example };
1765
+ }
1766
+ return result;
1767
+ }, initial);
1768
+ }
1769
+ anyOf(schemas) {
1770
+ if (schemas.length === 0)
1771
+ return {};
1772
+ return this.handle(schemas[0]);
1773
+ }
1774
+ oneOf(schemas) {
1775
+ if (schemas.length === 0)
1776
+ return {};
1777
+ return this.handle(schemas[0]);
1778
+ }
1779
+ enum(schema) {
1780
+ return Array.isArray(schema.enum) && schema.enum.length > 0 ? schema.enum[0] : void 0;
2083
1781
  }
2084
- /**
2085
- * Handle schemas by resolving references and delegating to appropriate handler
2086
- */
2087
1782
  handle(schemaOrRef) {
2088
- if (isRef7(schemaOrRef)) {
2089
- return this.#ref(schemaOrRef.$ref);
1783
+ if (isRef5(schemaOrRef)) {
1784
+ return this.ref(schemaOrRef.$ref);
1785
+ }
1786
+ const schema = isRef5(schemaOrRef) ? followRef5(this.spec, schemaOrRef.$ref) : schemaOrRef;
1787
+ if (schema.example !== void 0) {
1788
+ return schema.example;
1789
+ }
1790
+ if (schema.default !== void 0) {
1791
+ return schema.default;
2090
1792
  }
2091
- const schema = schemaOrRef;
2092
1793
  if (schema.allOf && Array.isArray(schema.allOf)) {
2093
- return this.#allOf(schema.allOf);
1794
+ return this.allOf(schema.allOf);
2094
1795
  }
2095
1796
  if (schema.anyOf && Array.isArray(schema.anyOf)) {
2096
- return this.#anyOf(schema.anyOf);
1797
+ return this.anyOf(schema.anyOf);
2097
1798
  }
2098
1799
  if (schema.oneOf && Array.isArray(schema.oneOf)) {
2099
- return this.#oneOf(schema.oneOf);
2100
- }
2101
- if (schema.enum && Array.isArray(schema.enum)) {
2102
- return this.#enum(schema);
1800
+ return this.oneOf(schema.oneOf);
2103
1801
  }
2104
- let types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
2105
- let nullable = false;
2106
- if (types.includes("null")) {
2107
- nullable = true;
2108
- types = types.filter((t) => t !== "null");
1802
+ if (schema.enum && Array.isArray(schema.enum) && schema.enum.length > 0) {
1803
+ return this.enum(schema);
2109
1804
  }
1805
+ const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
2110
1806
  if (types.length === 0) {
2111
1807
  if (schema.properties || schema.additionalProperties) {
2112
- types = ["object"];
1808
+ return this.object(schema);
2113
1809
  } else if (schema.items) {
2114
- types = ["array"];
1810
+ return this.array(schema);
2115
1811
  }
1812
+ return "example";
1813
+ }
1814
+ const primaryType = types.find((t) => t !== "null") || types[0];
1815
+ switch (primaryType) {
1816
+ case "string":
1817
+ return this.string(schema);
1818
+ case "number":
1819
+ case "integer":
1820
+ return this.number(schema);
1821
+ case "boolean":
1822
+ return this.boolean(schema);
1823
+ case "object":
1824
+ return this.object(schema);
1825
+ case "array":
1826
+ return this.array(schema);
1827
+ case "null":
1828
+ return this.null();
1829
+ default:
1830
+ return "unknown";
2116
1831
  }
2117
- if (types.length === 0) {
2118
- const lines2 = ["**Type:** `unknown`"];
2119
- if (schema.description)
2120
- lines2.push(schema.description);
2121
- if (schema.default !== void 0)
2122
- lines2.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
2123
- return lines2;
2124
- }
2125
- if (types.length === 1) {
2126
- return this.#normal(types[0], schema, nullable);
2127
- }
2128
- const typeString = types.join(" | ");
2129
- const nullableSuffix = nullable ? " (nullable)" : "";
2130
- const lines = [`**Type:** \`${typeString}\`${nullableSuffix}`];
2131
- if (schema.description)
2132
- lines.push(schema.description);
2133
- if (schema.default !== void 0)
2134
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
2135
- return lines;
2136
1832
  }
2137
- /**
2138
- * Process a request body and return markdown documentation
2139
- */
2140
- requestBody(requestBody) {
2141
- if (!requestBody)
2142
- return [];
2143
- const resolvedBody = isRef7(requestBody) ? followRef6(this.#spec, requestBody.$ref) : requestBody;
2144
- const lines = [];
2145
- lines.push(`##### Request Body`);
2146
- if (resolvedBody.description) {
2147
- lines.push(resolvedBody.description);
2148
- }
2149
- if (resolvedBody.required) {
2150
- lines.push(`*This request body is required.*`);
2151
- }
2152
- if (resolvedBody.content) {
2153
- for (const [contentType, mediaType] of Object.entries(
2154
- resolvedBody.content
2155
- )) {
2156
- lines.push(`**Content Type:** \`${contentType}\``);
2157
- if (mediaType.schema) {
2158
- const schemaDocs = this.handle(mediaType.schema);
2159
- lines.push(...schemaDocs);
1833
+ };
1834
+
1835
+ // packages/typescript/src/lib/typescript-snippet.ts
1836
+ var TypeScriptGenerator = class {
1837
+ #spec;
1838
+ #settings;
1839
+ #snippetEmitter;
1840
+ #clientName;
1841
+ #packageName;
1842
+ constructor(spec, settings) {
1843
+ this.#spec = spec;
1844
+ this.#settings = settings;
1845
+ this.#snippetEmitter = new SnippetEmitter(spec);
1846
+ this.#clientName = settings.name?.trim() ? pascalcase4(settings.name) : "Client";
1847
+ this.#packageName = settings.name ? `@${spinalcase2(this.#clientName.toLowerCase())}/sdk` : "sdk";
1848
+ }
1849
+ succinct(entry, operation, values) {
1850
+ let payload = "{}";
1851
+ if (!isEmpty3(operation.requestBody)) {
1852
+ const contentTypes = Object.keys(operation.requestBody.content || {});
1853
+ const schema = resolveRef2(
1854
+ this.#spec,
1855
+ operation.requestBody.content[contentTypes[0]].schema
1856
+ );
1857
+ const examplePayload = this.#snippetEmitter.handle({
1858
+ ...schema,
1859
+ properties: Object.assign({}, schema.properties, schema.properties)
1860
+ });
1861
+ Object.assign(
1862
+ examplePayload,
1863
+ values.requestBody ?? {},
1864
+ values.pathParameters ?? {},
1865
+ values.queryParameters ?? {},
1866
+ values.headers ?? {},
1867
+ values.cookies ?? {}
1868
+ );
1869
+ payload = examplePayload;
1870
+ } else {
1871
+ const requestBody = { type: "object", properties: {} };
1872
+ patchParameters(
1873
+ this.#spec,
1874
+ requestBody,
1875
+ operation.parameters,
1876
+ operation.security ?? []
1877
+ );
1878
+ const examplePayload = this.#snippetEmitter.handle(requestBody);
1879
+ Object.assign(
1880
+ examplePayload,
1881
+ values.pathParameters ?? {},
1882
+ values.queryParameters ?? {},
1883
+ values.headers ?? {},
1884
+ values.cookies ?? {}
1885
+ );
1886
+ payload = examplePayload;
1887
+ }
1888
+ payload = JSON.stringify(
1889
+ payload,
1890
+ (key, value) => {
1891
+ if (value?.startsWith && value.startsWith("new")) {
1892
+ return `__REPLACE_${Math.random().toString(36).substring(2, 11)}__${value}__REPLACE_END__`;
2160
1893
  }
1894
+ return value;
1895
+ },
1896
+ 2
1897
+ ).replace(/"__REPLACE_[^"]*__([^"]*?)__REPLACE_END__"/g, "$1");
1898
+ let successResponse;
1899
+ for (const status in operation.responses) {
1900
+ if (status.startsWith("2")) {
1901
+ successResponse = operation.responses[status];
1902
+ break;
1903
+ }
1904
+ }
1905
+ if (successResponse) {
1906
+ if (successResponse.headers?.["Transfer-Encoding"]) {
1907
+ return this.#httpStreaming(entry, payload);
1908
+ }
1909
+ if (successResponse.content && successResponse.content["application/octet-stream"]) {
1910
+ return this.#streamDownload(entry, payload);
2161
1911
  }
2162
1912
  }
2163
- return lines;
1913
+ if (!isEmpty3(operation["x-pagination"])) {
1914
+ return this.#pagination(operation, entry, payload);
1915
+ }
1916
+ return this.#normal(entry, payload);
2164
1917
  }
2165
- };
2166
- function toReadme(spec) {
2167
- const markdown = [];
2168
- const propEmitter = new PropEmitter(spec);
2169
- forEachOperation({ spec }, ({ method, path, name }, operation) => {
2170
- spec.components ??= {};
2171
- spec.components.schemas ??= {};
2172
- const statuses = [];
2173
- markdown.push(
2174
- `#### ${name || operation.operationId} | ${`_${method.toUpperCase()} ${path}_`}`
2175
- );
2176
- markdown.push(operation.summary || "");
2177
- const requestBodyContent = propEmitter.requestBody(operation.requestBody);
2178
- if (requestBodyContent.length > 1) {
2179
- markdown.push(requestBodyContent.join("\n\n"));
1918
+ #pagination(opeartion, entry, payload) {
1919
+ const pagination = opeartion["x-pagination"];
1920
+ switch (pagination.type) {
1921
+ case "page":
1922
+ return {
1923
+ content: `const result = ${this.#ddd(entry, payload)}`,
1924
+ footer: `for await (const page of result) {
1925
+ console.log(page);
1926
+ }`
1927
+ };
1928
+ case "offset":
1929
+ return {
1930
+ content: `const result = ${this.#ddd(entry, payload)}`,
1931
+ footer: `for await (const page of result) {
1932
+ console.log(page);
1933
+ }`
1934
+ };
1935
+ case "cursor":
1936
+ return {
1937
+ content: `const result = ${this.#ddd(entry, payload)}`,
1938
+ footer: `for await (const page of result) {
1939
+ console.log(page);
1940
+ }`
1941
+ };
2180
1942
  }
2181
- markdown.push(`##### Responses`);
2182
- for (const status in operation.responses) {
2183
- const response = operation.responses[status];
2184
- const resolvedResponse = isRef7(response) ? followRef6(spec, response.$ref) : response;
2185
- statuses.push(`**${status}** _${resolvedResponse.description}_`);
1943
+ return this.#normal(entry, payload);
1944
+ }
1945
+ #normal(entry, payload) {
1946
+ return {
1947
+ content: `const result = ${this.#ddd(entry, payload)};`,
1948
+ footer: "console.log(result.data)"
1949
+ };
1950
+ }
1951
+ #streamDownload(entry, payload) {
1952
+ return {
1953
+ content: `const stream = ${this.#ddd(entry, payload)}`,
1954
+ footer: `await writeFile('./report.pdf', stream);`
1955
+ };
1956
+ }
1957
+ #httpStreaming(entry, payload) {
1958
+ return {
1959
+ content: `const stream = ${this.#ddd(entry, payload)}`,
1960
+ footer: `for await (const chunk of stream) {
1961
+ console.log(chunk);
1962
+ }`
1963
+ };
1964
+ }
1965
+ #ddd(entry, payload) {
1966
+ return `await ${camelcase3(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
1967
+ }
1968
+ snippet(entry, operation, config = {}) {
1969
+ const payload = this.succinct(entry, operation, config);
1970
+ const content = [
1971
+ this.client(),
1972
+ "",
1973
+ payload.content,
1974
+ "",
1975
+ payload.footer
1976
+ ];
1977
+ if (config.frame !== false) {
1978
+ content.unshift("```typescript");
1979
+ content.push("```");
2186
1980
  }
2187
- markdown.push(`<small>${statuses.join("\n\n")}</small>`);
2188
- });
2189
- return markdown.join("\n\n");
1981
+ return content.join("\n");
1982
+ }
1983
+ #authentication() {
1984
+ return securityToOptions2(
1985
+ this.#spec,
1986
+ this.#spec.security ?? [],
1987
+ this.#spec.components?.securitySchemes ?? {}
1988
+ );
1989
+ }
1990
+ client() {
1991
+ const inputs = [
1992
+ `baseUrl: '${this.#spec.servers?.[0]?.url ?? "http://localhost:3000"}'`
1993
+ ];
1994
+ const authOptions = this.#authentication();
1995
+ if (!isEmpty3(authOptions)) {
1996
+ const [firstAuth] = authOptions;
1997
+ inputs.push(`${firstAuth.name}: ${firstAuth.example}`);
1998
+ }
1999
+ return `import { ${this.#clientName} } from '${this.#packageName}';
2000
+
2001
+ const ${camelcase3(this.#clientName)} = new ${this.#clientName}({
2002
+ ${inputs.join(",\n ")}
2003
+ });`;
2004
+ }
2005
+ };
2006
+ function generateSnippet(spec, settings, entry, operation, config = {}) {
2007
+ const generator = new TypeScriptGenerator(spec, settings);
2008
+ return generator.snippet(entry, operation, config);
2190
2009
  }
2191
2010
 
2192
2011
  // packages/typescript/src/lib/generate.ts
@@ -2195,7 +2014,7 @@ function security(spec) {
2195
2014
  const components = spec.components || {};
2196
2015
  const securitySchemes = components.securitySchemes || {};
2197
2016
  const paths = Object.values(spec.paths ?? {});
2198
- const options = securityToOptions(security2, securitySchemes);
2017
+ const options = securityToOptions(spec, security2, securitySchemes);
2199
2018
  for (const it of paths) {
2200
2019
  for (const method of methods) {
2201
2020
  const operation = it[method];
@@ -2204,64 +2023,82 @@ function security(spec) {
2204
2023
  }
2205
2024
  Object.assign(
2206
2025
  options,
2207
- securityToOptions(operation.security || [], securitySchemes, "input")
2026
+ securityToOptions(
2027
+ spec,
2028
+ operation.security || [],
2029
+ securitySchemes,
2030
+ "input"
2031
+ )
2208
2032
  );
2209
2033
  }
2210
2034
  }
2211
2035
  return options;
2212
2036
  }
2213
- async function generate(spec, settings) {
2037
+ async function generate(openapi, settings) {
2038
+ const spec = augmentSpec(
2039
+ { spec: openapi, responses: { flattenErrorResponses: true } },
2040
+ false
2041
+ );
2042
+ const generator = new TypeScriptGenerator(spec, settings);
2214
2043
  const style = Object.assign(
2215
2044
  {},
2216
2045
  {
2217
- errorAsValue: true,
2046
+ errorAsValue: false,
2218
2047
  name: "github",
2219
2048
  outputType: "default"
2220
2049
  },
2221
2050
  settings.style ?? {}
2222
2051
  );
2052
+ const output = settings.mode === "full" ? join2(settings.output, "src") : settings.output;
2223
2053
  settings.useTsExtension ??= true;
2054
+ const { writer, files: writtenFiles } = createWriterProxy(
2055
+ settings.writer ?? writeFiles,
2056
+ output
2057
+ );
2058
+ settings.writer = writer;
2059
+ settings.readFolder ??= async (folder) => {
2060
+ const files = await readdir(folder, { withFileTypes: true });
2061
+ return files.map((file) => ({
2062
+ fileName: file.name,
2063
+ filePath: join2(file.parentPath, file.name),
2064
+ isFolder: file.isDirectory()
2065
+ }));
2066
+ };
2224
2067
  const makeImport = (moduleSpecifier) => {
2225
2068
  return settings.useTsExtension ? `${moduleSpecifier}.ts` : moduleSpecifier;
2226
2069
  };
2227
- const { commonSchemas, endpoints, groups, outputs, commonZod } = generateCode(
2228
- {
2229
- spec,
2230
- style,
2231
- makeImport
2232
- }
2233
- );
2234
- const output = settings.mode === "full" ? join2(settings.output, "src") : settings.output;
2070
+ const { endpoints, groups, commonZod } = generateCode({
2071
+ spec,
2072
+ style,
2073
+ makeImport
2074
+ });
2235
2075
  const options = security(spec);
2236
- const clientName = settings.name?.trim() ? pascalcase3(settings.name) : "Client";
2237
- const readme = settings.readme ? toReadme(spec) : "";
2238
- const inputFiles = generateInputs(groups, commonZod, makeImport);
2239
- console.log("Writing to", output);
2240
- await writeFiles(output, {
2076
+ const clientName = pascalcase5((settings.name || "client").trim());
2077
+ const packageName = settings.name ? `@${spinalcase3(settings.name.trim().toLowerCase())}/sdk` : "sdk";
2078
+ const inputs = toInputs(groups, commonZod, makeImport);
2079
+ const models = serializeModels(spec);
2080
+ await settings.writer(output, {
2241
2081
  "outputs/.gitkeep": "",
2242
2082
  "inputs/.gitkeep": "",
2243
2083
  "models/.getkeep": ""
2244
2084
  });
2245
- await writeFiles(join2(output, "http"), {
2246
- "interceptors.ts": `
2247
- import type { RequestConfig, HeadersInit } from './${makeImport("request")}';
2248
- ${interceptors_default}`,
2085
+ await settings.writer(join2(output, "http"), {
2249
2086
  "parse-response.ts": parse_response_default,
2250
- "send-request.ts": `import z from 'zod';
2251
- import type { Interceptor } from './${makeImport("interceptors")}';
2252
- import { buffered } from './${makeImport("parse-response")}';
2253
- import { parseInput } from './${makeImport("parser")}';
2254
- import type { RequestConfig } from './${makeImport("request")}';
2255
- import { APIError, APIResponse } from './${makeImport("response")}';
2256
-
2257
- ${template2(send_request_default, {})({ throwError: !style.errorAsValue, outputType: style.outputType })}`,
2258
2087
  "response.ts": response_default,
2259
2088
  "parser.ts": parser_default,
2260
- "request.ts": request_default
2089
+ "request.ts": request_default,
2090
+ "dispatcher.ts": `import z from 'zod';
2091
+ import { type Interceptor } from '${makeImport("../http/interceptors")}';
2092
+ import { type RequestConfig } from '${makeImport("../http/request")}';
2093
+ import { buffered } from '${makeImport("./parse-response")}';
2094
+ import { APIError, APIResponse, type SuccessfulResponse, type ProblematicResponse } from '${makeImport("./response")}';
2095
+
2096
+ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputType: style.outputType })}`,
2097
+ "interceptors.ts": `
2098
+ import type { RequestConfig, HeadersInit } from './${makeImport("request")}';
2099
+ ${interceptors_default}`
2261
2100
  });
2262
- await writeFiles(join2(output, "outputs"), outputs);
2263
- const modelsImports = Object.entries(commonSchemas).map(([name]) => name);
2264
- await writeFiles(output, {
2101
+ await settings.writer(output, {
2265
2102
  "client.ts": client_default(
2266
2103
  {
2267
2104
  name: clientName,
@@ -2271,52 +2108,80 @@ ${template2(send_request_default, {})({ throwError: !style.errorAsValue, outputT
2271
2108
  },
2272
2109
  style
2273
2110
  ),
2274
- ...inputFiles,
2275
- ...endpoints,
2276
- ...Object.fromEntries(
2277
- Object.entries(commonSchemas).map(([name, schema]) => [
2278
- `models/${name}.ts`,
2279
- [
2280
- `import { z } from 'zod';`,
2281
- ...exclude(modelsImports, [name]).map(
2282
- (it) => `import type { ${it} } from './${it}.ts';`
2283
- ),
2284
- `export type ${name} = ${schema};`
2285
- ].join("\n")
2286
- ])
2287
- )
2111
+ ...inputs,
2112
+ ...endpoints
2113
+ });
2114
+ await settings.writer(output, models);
2115
+ await settings.writer(join2(output, "pagination"), {
2116
+ "cursor-pagination.ts": cursor_pagination_default,
2117
+ "offset-pagination.ts": offset_pagination_default,
2118
+ "page-pagination.ts": page_pagination_default
2288
2119
  });
2120
+ const metadata = await readWriteMetadata(output, Array.from(writtenFiles));
2121
+ if (settings.cleanup !== false && writtenFiles.size > 0) {
2122
+ await cleanFiles(metadata.content, output, [
2123
+ "/tsconfig*.json",
2124
+ "/package.json",
2125
+ "/metadata.json",
2126
+ "/**/index.ts"
2127
+ ]);
2128
+ }
2289
2129
  const folders = [
2290
- getFolderExports(join2(output, "outputs"), settings.useTsExtension),
2130
+ getFolderExports(
2131
+ join2(output, "outputs"),
2132
+ settings.readFolder,
2133
+ settings.useTsExtension
2134
+ ),
2291
2135
  getFolderExports(
2292
2136
  join2(output, "inputs"),
2137
+ settings.readFolder,
2293
2138
  settings.useTsExtension,
2294
2139
  ["ts"],
2295
- (dirent) => dirent.isDirectory() && ["schemas"].includes(dirent.name)
2140
+ (dirent) => dirent.isFolder && ["schemas"].includes(dirent.fileName)
2141
+ ),
2142
+ getFolderExports(
2143
+ join2(output, "api"),
2144
+ settings.readFolder,
2145
+ settings.useTsExtension
2296
2146
  ),
2297
- getFolderExports(join2(output, "api"), settings.useTsExtension),
2298
2147
  getFolderExports(
2299
2148
  join2(output, "http"),
2149
+ settings.readFolder,
2300
2150
  settings.useTsExtension,
2301
2151
  ["ts"],
2302
- (dirent) => !["response.ts", "parser.ts"].includes(dirent.name)
2152
+ (dirent) => !["response.ts", "parser.ts"].includes(dirent.fileName)
2153
+ ),
2154
+ getFolderExports(
2155
+ join2(output, "models"),
2156
+ settings.readFolder,
2157
+ settings.useTsExtension
2303
2158
  )
2304
2159
  ];
2305
- if (modelsImports.length) {
2306
- folders.push(
2307
- getFolderExports(join2(output, "models"), settings.useTsExtension)
2308
- );
2309
- }
2310
2160
  const [outputIndex, inputsIndex, apiIndex, httpIndex, modelsIndex] = await Promise.all(folders);
2311
- await writeFiles(output, {
2161
+ await settings.writer(join2(output, "pagination"), {
2162
+ "index.ts": await getFolderExports(
2163
+ join2(output, "pagination"),
2164
+ settings.readFolder,
2165
+ settings.useTsExtension,
2166
+ ["ts"]
2167
+ )
2168
+ });
2169
+ await settings.writer(output, {
2312
2170
  "api/index.ts": apiIndex,
2313
2171
  "outputs/index.ts": outputIndex,
2314
2172
  "inputs/index.ts": inputsIndex || null,
2315
2173
  "http/index.ts": httpIndex,
2316
- ...modelsImports.length ? { "models/index.ts": modelsIndex } : {}
2174
+ "models/index.ts": modelsIndex
2175
+ // ...(modelsImports.length ? { 'models/index.ts': modelsIndex } : {}),
2317
2176
  });
2318
- await writeFiles(output, {
2319
- "index.ts": await getFolderExports(output, settings.useTsExtension, ["ts"])
2177
+ await settings.writer(output, {
2178
+ "index.ts": await getFolderExports(
2179
+ output,
2180
+ settings.readFolder,
2181
+ settings.useTsExtension,
2182
+ ["ts"],
2183
+ (config) => config.fileName.endsWith("pagination")
2184
+ )
2320
2185
  });
2321
2186
  if (settings.mode === "full") {
2322
2187
  const configFiles = {
@@ -2324,9 +2189,23 @@ ${template2(send_request_default, {})({ throwError: !style.errorAsValue, outputT
2324
2189
  ignoreIfExists: true,
2325
2190
  content: JSON.stringify(
2326
2191
  {
2327
- name: settings.name ? `@${spinalcase3(clientName.toLowerCase())}/sdk` : "sdk",
2192
+ name: packageName,
2193
+ version: "0.0.1",
2328
2194
  type: "module",
2329
2195
  main: "./src/index.ts",
2196
+ module: "./src/index.ts",
2197
+ types: "./src/index.ts",
2198
+ publishConfig: {
2199
+ access: "public"
2200
+ },
2201
+ exports: {
2202
+ "./package.json": "./package.json",
2203
+ ".": {
2204
+ types: "./src/index.ts",
2205
+ import: "./src/index.ts",
2206
+ default: "./src/index.ts"
2207
+ }
2208
+ },
2330
2209
  dependencies: {
2331
2210
  "fast-content-type-parse": "^3.0.0",
2332
2211
  zod: "^3.24.2"
@@ -2359,33 +2238,104 @@ ${template2(send_request_default, {})({ throwError: !style.errorAsValue, outputT
2359
2238
  )
2360
2239
  }
2361
2240
  };
2362
- if (readme) {
2241
+ if (settings.readme) {
2363
2242
  configFiles["README.md"] = {
2364
- ignoreIfExists: true,
2365
- content: readme
2243
+ ignoreIfExists: false,
2244
+ content: toReadme(spec, {
2245
+ generateSnippet: (...args) => generator.snippet(...args)
2246
+ })
2366
2247
  };
2367
2248
  }
2368
- await writeFiles(settings.output, configFiles);
2249
+ await settings.writer(settings.output, configFiles);
2369
2250
  }
2370
2251
  await settings.formatCode?.({
2371
2252
  output,
2372
2253
  env: npmRunPathEnv()
2373
2254
  });
2374
2255
  }
2375
-
2376
- // packages/typescript/src/lib/watcher.ts
2377
- import { watch as nodeWatch } from "node:fs/promises";
2378
- import { debounceTime, from } from "rxjs";
2379
- function watch(path) {
2380
- return from(
2381
- nodeWatch(path, {
2382
- persistent: true,
2383
- recursive: true
2384
- })
2385
- ).pipe(debounceTime(400));
2256
+ function serializeModels(spec) {
2257
+ const filesMap = {};
2258
+ const files = {};
2259
+ for (const [name, schema] of Object.entries(spec.components.schemas)) {
2260
+ const isResponseBody = schema["x-responsebody"];
2261
+ const isRequestBody = schema["x-requestbody"];
2262
+ const responseGroup = schema["x-response-group"];
2263
+ const stream = schema["x-stream"];
2264
+ const folder = isResponseBody ? "outputs" : "models";
2265
+ let typeContent = "ReadableStream";
2266
+ if (!stream) {
2267
+ const serializer = new TypeScriptEmitter(spec);
2268
+ typeContent = serializer.handle(schema, true);
2269
+ }
2270
+ const fileContent = [
2271
+ `
2272
+ ${schema.description ? `
2273
+ /**
2274
+ * ${schema.description}
2275
+ */
2276
+ ` : ""}`,
2277
+ `export type ${pascalcase5(sanitizeTag4(name))} = ${typeContent};`
2278
+ ];
2279
+ const fileName = responseGroup ? join2(folder, `${spinalcase3(responseGroup)}.ts`) : join2(folder, `${spinalcase3(name)}.ts`);
2280
+ filesMap[fileName] ??= [];
2281
+ filesMap[fileName].push(fileContent.join("\n"));
2282
+ }
2283
+ for (const [group, contents] of Object.entries(filesMap)) {
2284
+ let fileContent = contents.join("\n");
2285
+ if (fileContent.includes("models.")) {
2286
+ fileContent = `import type * as models from '../index.ts';
2287
+ ${fileContent}`;
2288
+ }
2289
+ files[group] = fileContent;
2290
+ }
2291
+ return files;
2292
+ }
2293
+ function toInputs(operationsSet, commonZod, makeImport) {
2294
+ const commonImports = commonZod.keys().toArray();
2295
+ const inputs = {};
2296
+ for (const [name, operations] of Object.entries(operationsSet)) {
2297
+ const output = [];
2298
+ const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
2299
+ for (const operation of operations) {
2300
+ const schemaName = camelcase4(`${operation.name} schema`);
2301
+ const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
2302
+ for (const it of commonImports) {
2303
+ if (schema.includes(it)) {
2304
+ imports.add(
2305
+ `import { ${it} } from './schemas/${makeImport(spinalcase3(it))}';`
2306
+ );
2307
+ }
2308
+ }
2309
+ output.push(schema);
2310
+ }
2311
+ inputs[`inputs/${spinalcase3(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
2312
+ }
2313
+ const schemas = commonZod.entries().reduce((acc, [name, schema]) => {
2314
+ const output = [`import { z } from 'zod';`];
2315
+ const content = `export const ${name} = ${schema};`;
2316
+ for (const schema2 of commonImports) {
2317
+ const preciseMatch = new RegExp(`\\b${schema2}\\b`);
2318
+ if (preciseMatch.test(content) && schema2 !== name) {
2319
+ output.push(
2320
+ `import { ${schema2} } from './${makeImport(spinalcase3(schema2))}';`
2321
+ );
2322
+ }
2323
+ }
2324
+ output.push(content);
2325
+ return [
2326
+ [`inputs/schemas/${spinalcase3(name)}.ts`, output.join("\n")],
2327
+ ...acc
2328
+ ];
2329
+ }, []);
2330
+ return {
2331
+ ...Object.fromEntries(schemas),
2332
+ ...inputs
2333
+ };
2386
2334
  }
2387
2335
  export {
2336
+ TypeScriptGenerator,
2388
2337
  generate,
2389
- watch
2338
+ generateSnippet,
2339
+ toInputs
2390
2340
  };
2391
2341
  //# sourceMappingURL=index.js.map