@sdk-it/typescript 0.18.0 → 0.19.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,138 @@
1
1
  // packages/typescript/src/lib/generate.ts
2
- import { template } from "lodash-es";
3
- import { join as join2 } from "node:path";
2
+ import { template as template2 } from "lodash-es";
3
+ import { join as join3 } from "node:path";
4
4
  import { npmRunPathEnv } from "npm-run-path";
5
5
  import { spinalcase as spinalcase3 } from "stringcase";
6
- import { getFolderExports, methods, writeFiles } from "@sdk-it/core";
6
+
7
+ // packages/core/dist/index.js
8
+ import {
9
+ pascalcase as _pascalcase,
10
+ snakecase as _snakecase,
11
+ spinalcase as _spinalcase
12
+ } from "stringcase";
13
+ import ts, { TypeFlags, symbolName } from "typescript";
14
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
15
+ import { dirname, extname, isAbsolute, join } from "node:path";
16
+ import debug from "debug";
17
+ import ts2 from "typescript";
18
+ import { get } from "lodash-es";
19
+ var deriveSymbol = Symbol.for("serialize");
20
+ var $types = Symbol.for("types");
21
+ async function exist(file) {
22
+ return stat(file).then(() => true).catch(() => false);
23
+ }
24
+ async function writeFiles(dir, contents) {
25
+ await Promise.all(
26
+ Object.entries(contents).map(async ([file, content]) => {
27
+ if (content === null) {
28
+ return;
29
+ }
30
+ const filePath = isAbsolute(file) ? file : join(dir, file);
31
+ await mkdir(dirname(filePath), { recursive: true });
32
+ if (typeof content === "string") {
33
+ await writeFile(filePath, content, "utf-8");
34
+ } else {
35
+ if (content.ignoreIfExists) {
36
+ if (!await exist(filePath)) {
37
+ await writeFile(filePath, content.content, "utf-8");
38
+ }
39
+ } else {
40
+ await writeFile(filePath, content.content, "utf-8");
41
+ }
42
+ }
43
+ })
44
+ );
45
+ }
46
+ async function getFolderExports(folder, includeExtension = true, extensions = ["ts"], ignore = () => false) {
47
+ const files = await readdir(folder, { withFileTypes: true });
48
+ const exports = [];
49
+ for (const file of files) {
50
+ if (ignore(file)) {
51
+ continue;
52
+ }
53
+ if (file.isDirectory()) {
54
+ if (await exist(`${file.parentPath}/${file.name}/index.ts`)) {
55
+ exports.push(
56
+ `export * from './${file.name}/index${includeExtension ? ".ts" : ""}';`
57
+ );
58
+ }
59
+ } else if (file.name !== "index.ts" && extensions.includes(getExt(file.name))) {
60
+ exports.push(
61
+ `export * from './${includeExtension ? file.name : file.name.replace(extname(file.name), "")}';`
62
+ );
63
+ }
64
+ }
65
+ return exports.join("\n");
66
+ }
67
+ var getExt = (fileName) => {
68
+ if (!fileName) {
69
+ return "";
70
+ }
71
+ const lastDot = fileName.lastIndexOf(".");
72
+ if (lastDot === -1) {
73
+ return "";
74
+ }
75
+ const ext = fileName.slice(lastDot + 1).split("/").filter(Boolean).join("");
76
+ if (ext === fileName) {
77
+ return "";
78
+ }
79
+ return ext || "txt";
80
+ };
81
+ var methods = [
82
+ "get",
83
+ "post",
84
+ "put",
85
+ "patch",
86
+ "delete",
87
+ "trace",
88
+ "head"
89
+ ];
90
+ var logger = debug("january:client");
91
+ function isRef(obj) {
92
+ return obj && "$ref" in obj;
93
+ }
94
+ function cleanRef(ref) {
95
+ return ref.replace(/^#\//, "");
96
+ }
97
+ function parseRef(ref) {
98
+ const parts = ref.split("/");
99
+ const [model] = parts.splice(-1);
100
+ const [namespace] = parts.splice(-1);
101
+ return {
102
+ model,
103
+ namespace,
104
+ path: cleanRef(parts.join("/"))
105
+ };
106
+ }
107
+ function followRef(spec, ref) {
108
+ const pathParts = cleanRef(ref).split("/");
109
+ const entry = get(spec, pathParts);
110
+ if (entry && "$ref" in entry) {
111
+ return followRef(spec, entry.$ref);
112
+ }
113
+ return entry;
114
+ }
115
+ function removeDuplicates(data, accessor = (item) => item) {
116
+ return [...new Map(data.map((x) => [accessor(x), x])).values()];
117
+ }
118
+ function toLitObject(obj, accessor = (value) => value) {
119
+ return `{${Object.keys(obj).map((key) => `${key}: ${accessor(obj[key])}`).join(", ")}}`;
120
+ }
121
+ function isEmpty(value) {
122
+ if (value === null || value === void 0 || value === "") {
123
+ return true;
124
+ }
125
+ if (Array.isArray(value) && value.length === 0) {
126
+ return true;
127
+ }
128
+ if (typeof value === "object" && Object.keys(value).length === 0) {
129
+ return true;
130
+ }
131
+ return false;
132
+ }
7
133
 
8
134
  // packages/typescript/src/lib/client.ts
9
- import { toLitObject } from "@sdk-it/core";
10
- var client_default = (spec, throwError) => {
135
+ var client_default = (spec, style) => {
11
136
  const optionsEntries = Object.entries(spec.options).map(
12
137
  ([key, value]) => [`'${key}'`, value]
13
138
  );
@@ -29,8 +154,8 @@ var client_default = (spec, throwError) => {
29
154
  }
30
155
  };
31
156
  return `
32
- import type { RequestConfig } from './http/${spec.makeImport("request")}';
33
- import { fetchType, sendRequest, parse } from './http/${spec.makeImport("send-request")}';
157
+ import type { HeadersInit, RequestConfig } from './http/${spec.makeImport("request")}';
158
+ import { fetchType, dispatch, parse } from './http/${spec.makeImport("send-request")}';
34
159
  import z from 'zod';
35
160
  import type { Endpoints } from './api/${spec.makeImport("endpoints")}';
36
161
  import schemas from './api/${spec.makeImport("schemas")}';
@@ -57,11 +182,9 @@ export class ${spec.name} {
57
182
  endpoint: E,
58
183
  input: Endpoints[E]['input'],
59
184
  options?: { signal?: AbortSignal, headers?: HeadersInit },
60
- )
61
- ${throwError ? `: Endpoints[E]['output']` : `: Promise<readonly [Endpoints[E]['output'], Endpoints[E]['error'] | null]>`}
62
- {
185
+ ) ${style.errorAsValue ? `: Promise<readonly [Endpoints[E]['output'], Endpoints[E]['error'] | null]>` : `: Promise<Endpoints[E]['output']>`} {
63
186
  const route = schemas[endpoint];
64
- return sendRequest(Object.assign(this.#defaultInputs, input), route, {
187
+ const result = await dispatch(Object.assign(this.#defaultInputs, input), route, {
65
188
  fetch: this.options.fetch,
66
189
  interceptors: [
67
190
  createHeadersInterceptor(() => this.defaultHeaders, options?.headers ?? {}),
@@ -69,20 +192,23 @@ export class ${spec.name} {
69
192
  ],
70
193
  signal: options?.signal,
71
194
  });
195
+ return ${style.errorAsValue ? `result as [Endpoints[E]['output'], Endpoints[E]['error'] | null]` : `result as Endpoints[E]['output']`};
72
196
  }
73
197
 
74
198
  async prepare<E extends keyof Endpoints>(
75
199
  endpoint: E,
76
200
  input: Endpoints[E]['input'],
77
201
  options?: { headers?: HeadersInit },
78
- ): Promise<
202
+ ): ${style.errorAsValue ? `Promise<
79
203
  readonly [
80
204
  RequestConfig & {
81
205
  parse: (response: Response) => ReturnType<typeof parse>;
82
206
  },
83
207
  ParseError<(typeof schemas)[E]['schema']> | null,
84
208
  ]
85
- > {
209
+ >` : `Promise<RequestConfig & {
210
+ parse: (response: Response) => ReturnType<typeof parse>;
211
+ }>`} {
86
212
  const route = schemas[endpoint];
87
213
 
88
214
  const interceptors = [
@@ -94,7 +220,7 @@ export class ${spec.name} {
94
220
  ];
95
221
  const [parsedInput, parseError] = parseInput(route.schema, input);
96
222
  if (parseError) {
97
- return [null as never, parseError as never] as const;
223
+ ${style.errorAsValue ? "return [null as never, parseError as never] as const;" : "throw parseError;"}
98
224
  }
99
225
 
100
226
  let config = route.toRequest(parsedInput as never);
@@ -103,10 +229,8 @@ export class ${spec.name} {
103
229
  config = await interceptor.before(config);
104
230
  }
105
231
  }
106
- return [
107
- { ...config, parse: (response: Response) => parse(route, response) },
108
- null as never,
109
- ] as const;
232
+ const prepared = { ...config, parse: (response: Response) => parse(route, response) };
233
+ return ${style.errorAsValue ? "[prepared, null as never] as const;" : "prepared"}
110
234
  }
111
235
 
112
236
  get defaultHeaders() {
@@ -130,10 +254,9 @@ export class ${spec.name} {
130
254
  };
131
255
 
132
256
  // packages/typescript/src/lib/generator.ts
133
- import { merge } from "lodash-es";
134
- import { join } from "node:path";
257
+ import { merge, template } from "lodash-es";
258
+ import { join as join2 } from "node:path";
135
259
  import { camelcase as camelcase3, pascalcase as pascalcase2, spinalcase as spinalcase2 } from "stringcase";
136
- import { followRef as followRef4, isEmpty, isRef as isRef5 } from "@sdk-it/core";
137
260
 
138
261
  // packages/spec/dist/lib/operation.js
139
262
  import { camelcase } from "stringcase";
@@ -398,7 +521,6 @@ function determineGenericTag(pathString, operation) {
398
521
  }
399
522
 
400
523
  // packages/typescript/src/lib/emitters/zod.ts
401
- import { cleanRef, followRef, isRef, parseRef } from "@sdk-it/core";
402
524
  var ZodDeserialzer = class {
403
525
  circularRefTracker = /* @__PURE__ */ new Set();
404
526
  #spec;
@@ -660,12 +782,10 @@ function appendDefault(defaultValue) {
660
782
  }
661
783
 
662
784
  // packages/typescript/src/lib/sdk.ts
663
- import { get } from "lodash-es";
785
+ import { get as get2 } from "lodash-es";
664
786
  import { camelcase as camelcase2, pascalcase, spinalcase } from "stringcase";
665
- import { followRef as followRef3, isRef as isRef4, toLitObject as toLitObject2 } from "@sdk-it/core";
666
787
 
667
788
  // packages/typescript/src/lib/emitters/interface.ts
668
- import { cleanRef as cleanRef2, followRef as followRef2, isRef as isRef2, parseRef as parseRef2 } from "@sdk-it/core";
669
789
  var TypeScriptDeserialzer = class {
670
790
  circularRefTracker = /* @__PURE__ */ new Set();
671
791
  #spec;
@@ -674,70 +794,12 @@ var TypeScriptDeserialzer = class {
674
794
  this.#spec = spec;
675
795
  this.#onRef = onRef;
676
796
  }
677
- #stringifyKey = (key) => {
678
- const reservedWords = [
679
- "constructor",
680
- "prototype",
681
- "break",
682
- "case",
683
- "catch",
684
- "class",
685
- "const",
686
- "continue",
687
- "debugger",
688
- "default",
689
- "delete",
690
- "do",
691
- "else",
692
- "export",
693
- "extends",
694
- "false",
695
- "finally",
696
- "for",
697
- "function",
698
- "if",
699
- "import",
700
- "in",
701
- "instanceof",
702
- "new",
703
- "null",
704
- "return",
705
- "super",
706
- "switch",
707
- "this",
708
- "throw",
709
- "true",
710
- "try",
711
- "typeof",
712
- "var",
713
- "void",
714
- "while",
715
- "with",
716
- "yield"
717
- ];
718
- if (reservedWords.includes(key)) {
719
- return `'${key}'`;
720
- }
721
- if (key.trim() === "") {
722
- return `'${key}'`;
723
- }
724
- const firstChar = key.charAt(0);
725
- const validFirstChar = firstChar >= "a" && firstChar <= "z" || firstChar >= "A" && firstChar <= "Z" || firstChar === "_" || firstChar === "$";
726
- if (!validFirstChar) {
727
- return `'${key.replace(/'/g, "\\'")}'`;
728
- }
729
- for (let i = 1; i < key.length; i++) {
730
- const char = key.charAt(i);
731
- const validChar = char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "0" && char <= "9" || char === "_" || char === "$";
732
- if (!validChar) {
733
- return `'${key.replace(/'/g, "\\'")}'`;
734
- }
735
- }
736
- return key;
737
- };
738
- #stringifyKeyV2 = (value) => {
797
+ #stringifyKey = (value) => {
739
798
  return `'${value}'`;
740
799
  };
800
+ #isInternal = (schema) => {
801
+ return isRef(schema) ? false : !!schema["x-internal"];
802
+ };
741
803
  /**
742
804
  * Handle objects (properties)
743
805
  */
@@ -746,7 +808,7 @@ var TypeScriptDeserialzer = class {
746
808
  const propEntries = Object.entries(properties).map(([key, propSchema]) => {
747
809
  const isRequired = (schema.required ?? []).includes(key);
748
810
  const tsType = this.handle(propSchema, isRequired);
749
- return `${this.#stringifyKeyV2(key)}: ${tsType}`;
811
+ return `${this.#isInternal(propSchema) ? key : this.#stringifyKey(key)}: ${tsType}`;
750
812
  });
751
813
  if (schema.additionalProperties) {
752
814
  if (typeof schema.additionalProperties === "object") {
@@ -797,14 +859,14 @@ var TypeScriptDeserialzer = class {
797
859
  }
798
860
  }
799
861
  ref($ref, required) {
800
- const schemaName = cleanRef2($ref).split("/").pop();
862
+ const schemaName = cleanRef($ref).split("/").pop();
801
863
  if (this.circularRefTracker.has(schemaName)) {
802
864
  return schemaName;
803
865
  }
804
866
  this.circularRefTracker.add(schemaName);
805
867
  this.#onRef?.(
806
868
  schemaName,
807
- this.handle(followRef2(this.#spec, $ref), required)
869
+ this.handle(followRef(this.#spec, $ref), required)
808
870
  );
809
871
  this.circularRefTracker.delete(schemaName);
810
872
  return appendOptional2(schemaName, required);
@@ -822,8 +884,8 @@ var TypeScriptDeserialzer = class {
822
884
  }
823
885
  oneOf(schemas, required) {
824
886
  const oneOfTypes = schemas.map((sub) => {
825
- if (isRef2(sub)) {
826
- const { model } = parseRef2(sub.$ref);
887
+ if (isRef(sub)) {
888
+ const { model } = parseRef(sub.$ref);
827
889
  if (this.circularRefTracker.has(model)) {
828
890
  return model;
829
891
  }
@@ -870,7 +932,7 @@ var TypeScriptDeserialzer = class {
870
932
  return appendOptional2(type, required);
871
933
  }
872
934
  handle(schema, required) {
873
- if (isRef2(schema)) {
935
+ if (isRef(schema)) {
874
936
  return this.ref(schema.$ref, required);
875
937
  }
876
938
  if (schema.allOf && Array.isArray(schema.allOf)) {
@@ -885,6 +947,12 @@ var TypeScriptDeserialzer = class {
885
947
  if (schema.enum && Array.isArray(schema.enum)) {
886
948
  return this.enum(schema.enum, required);
887
949
  }
950
+ if (schema.const) {
951
+ if (schema["x-internal"]) {
952
+ return `${schema.const}`;
953
+ }
954
+ return this.enum([schema.const], required);
955
+ }
888
956
  const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
889
957
  if (!types.length) {
890
958
  if ("properties" in schema) {
@@ -903,20 +971,12 @@ var TypeScriptDeserialzer = class {
903
971
  }
904
972
  return this.normal(types[0], schema, required);
905
973
  }
906
- /**
907
- * Generate an interface declaration
908
- */
909
- generateInterface(name, schema) {
910
- const content = this.handle(schema, true);
911
- return `interface ${name} ${content}`;
912
- }
913
974
  };
914
975
  function appendOptional2(type, isRequired) {
915
976
  return isRequired ? type : `${type} | undefined`;
916
977
  }
917
978
 
918
979
  // packages/typescript/src/lib/utils.ts
919
- import { isRef as isRef3, removeDuplicates } from "@sdk-it/core";
920
980
  function securityToOptions(security2, securitySchemes, staticIn) {
921
981
  securitySchemes ??= {};
922
982
  const options = {};
@@ -926,7 +986,7 @@ function securityToOptions(security2, securitySchemes, staticIn) {
926
986
  continue;
927
987
  }
928
988
  const schema = securitySchemes[name];
929
- if (isRef3(schema)) {
989
+ if (isRef(schema)) {
930
990
  throw new Error(`Ref security schemas are not supported`);
931
991
  }
932
992
  if (schema.type === "http") {
@@ -1015,7 +1075,7 @@ function generateInputs(operationsSet, commonZod, makeImport) {
1015
1075
  const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
1016
1076
  for (const operation of operations) {
1017
1077
  const schemaName = camelcase2(`${operation.name} schema`);
1018
- const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
1078
+ const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject(operation.schemas)};`;
1019
1079
  const inputContent = schema;
1020
1080
  for (const schema2 of commonImports) {
1021
1081
  if (inputContent.includes(schema2)) {
@@ -1085,7 +1145,7 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
1085
1145
  return statusCode >= 200 && statusCode < 300;
1086
1146
  }).length > 1;
1087
1147
  for (const status in specOperation.responses) {
1088
- const response = isRef4(specOperation.responses[status]) ? followRef3(spec, specOperation.responses[status].$ref) : specOperation.responses[status];
1148
+ const response = isRef(specOperation.responses[status]) ? followRef(spec, specOperation.responses[status].$ref) : specOperation.responses[status];
1089
1149
  const handled = handleResponse(
1090
1150
  spec,
1091
1151
  operation.name,
@@ -1175,7 +1235,7 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
1175
1235
  );
1176
1236
  const statusCode = +status;
1177
1237
  const parser = (response.headers ?? {})["Transfer-Encoding"] ? "chunked" : "buffered";
1178
- const statusName = statusCodeToResponseMap[status] || "APIResponse";
1238
+ const statusName = `http.${statusCodeToResponseMap[status] || "APIResponse"}`;
1179
1239
  const interfaceName = pascalcase(
1180
1240
  operationName + ` output${numbered ? status : ""}`
1181
1241
  );
@@ -1183,22 +1243,34 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
1183
1243
  outputs.push(statusName);
1184
1244
  } else {
1185
1245
  if (status.endsWith("XX")) {
1186
- outputs.push(`APIError<${interfaceName}>`);
1246
+ outputs.push(`http.APIError<${interfaceName}>`);
1187
1247
  } else {
1188
1248
  outputs.push(
1189
1249
  parser !== "buffered" ? `{type: ${statusName}<${interfaceName}>, parser: ${parser}}` : `${statusName}<${interfaceName}>`
1190
1250
  );
1191
1251
  }
1192
1252
  }
1193
- const responseContent = get(response, ["content"]);
1253
+ const responseContent = get2(response, ["content"]);
1194
1254
  const isJson = responseContent && responseContent["application/json"];
1195
- const responseSchema = isJson ? typeScriptDeserialzer.handle(
1196
- responseContent["application/json"].schema,
1197
- true
1198
- ) : "void";
1255
+ let responseSchema = parser === "chunked" ? "ReadableStream" : "void";
1256
+ if (isJson) {
1257
+ const schema = responseContent["application/json"].schema;
1258
+ const isObject = !isRef(schema) && schema.type === "object";
1259
+ if (isObject && schema.properties) {
1260
+ schema.properties["[http.KIND]"] = {
1261
+ "x-internal": true,
1262
+ const: `typeof ${statusName}.kind`,
1263
+ type: "string"
1264
+ };
1265
+ schema.required ??= [];
1266
+ schema.required.push("[KIND]");
1267
+ }
1268
+ responseSchema = typeScriptDeserialzer.handle(schema, true);
1269
+ }
1199
1270
  responses.push({
1200
1271
  name: interfaceName,
1201
- schema: responseSchema
1272
+ schema: responseSchema,
1273
+ description: response.description
1202
1274
  });
1203
1275
  const statusGroup = +status.slice(0, 1);
1204
1276
  if (statusCode >= 400 || statusGroup >= 4) {
@@ -1212,15 +1284,6 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
1212
1284
  namedImports: [{ isTypeOnly: true, name: interfaceName }]
1213
1285
  };
1214
1286
  } else if (statusCode >= 200 && statusCode < 300 || statusCode >= 2 || statusGroup <= 3) {
1215
- endpointImports[statusName] = {
1216
- moduleSpecifier: utils.makeImport("../http/response"),
1217
- namedImports: [
1218
- {
1219
- isTypeOnly: false,
1220
- name: statusName
1221
- }
1222
- ]
1223
- };
1224
1287
  endpointImports[interfaceName] = {
1225
1288
  defaultImport: void 0,
1226
1289
  isTypeOnly: true,
@@ -1233,7 +1296,7 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
1233
1296
  }
1234
1297
 
1235
1298
  // packages/typescript/src/lib/styles/github/endpoints.txt
1236
- var endpoints_default = "\ntype 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: EndpointOutput<K>;\n error: EndpointError<K> | ParseError<(typeof schemas)[K]['schema']>;\n };\n};";
1299
+ 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};";
1237
1300
 
1238
1301
  // packages/typescript/src/lib/generator.ts
1239
1302
  function generateCode(config) {
@@ -1259,7 +1322,7 @@ function generateCode(config) {
1259
1322
  const inputs = {};
1260
1323
  const additionalProperties = [];
1261
1324
  for (const param of operation.parameters ?? []) {
1262
- if (isRef5(param)) {
1325
+ if (isRef(param)) {
1263
1326
  throw new Error(`Found reference in parameter ${param.$ref}`);
1264
1327
  }
1265
1328
  if (!param.schema) {
@@ -1301,9 +1364,9 @@ function generateCode(config) {
1301
1364
  };
1302
1365
  let outgoingContentType;
1303
1366
  if (!isEmpty(operation.requestBody)) {
1304
- const requestBody = isRef5(operation.requestBody) ? followRef4(config.spec, operation.requestBody.$ref) : operation.requestBody;
1367
+ const requestBody = isRef(operation.requestBody) ? followRef(config.spec, operation.requestBody.$ref) : operation.requestBody;
1305
1368
  for (const type in requestBody.content) {
1306
- const ctSchema = isRef5(requestBody.content[type].schema) ? followRef4(config.spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
1369
+ const ctSchema = isRef(requestBody.content[type].schema) ? followRef(config.spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
1307
1370
  if (!ctSchema) {
1308
1371
  console.warn(
1309
1372
  `Schema not found for ${type} in ${entry.method} ${entry.path}`
@@ -1373,14 +1436,23 @@ function generateCode(config) {
1373
1436
  },
1374
1437
  { makeImport: config.makeImport }
1375
1438
  );
1376
- const output = [`import z from 'zod';`];
1439
+ const output = [
1440
+ `import z from 'zod';`,
1441
+ `import type * as http from '../http';`
1442
+ ];
1377
1443
  const responses = endpoint.responses.flatMap((it) => it.responses);
1378
1444
  const responsesImports = endpoint.responses.flatMap(
1379
1445
  (it) => Object.values(it.imports)
1380
1446
  );
1381
1447
  if (responses.length) {
1382
1448
  output.push(
1383
- ...responses.map((it) => `export type ${it.name} = ${it.schema};`)
1449
+ ...responses.map(
1450
+ (it) => `${it.description ? `
1451
+ /**
1452
+ * ${it.description}
1453
+ */
1454
+ ` : ""} export type ${it.name} = ${it.schema};`
1455
+ )
1384
1456
  );
1385
1457
  } else {
1386
1458
  output.push(
@@ -1431,7 +1503,7 @@ function generateCode(config) {
1431
1503
  commonZod,
1432
1504
  outputs,
1433
1505
  endpoints: {
1434
- [join("api", "endpoints.ts")]: `
1506
+ [join2("api", "endpoints.ts")]: `
1435
1507
 
1436
1508
 
1437
1509
  import type z from 'zod';
@@ -1445,9 +1517,9 @@ import type { OutputType, Parser, Type } from '${config.makeImport(
1445
1517
 
1446
1518
  import schemas from '${config.makeImport("./schemas")}';
1447
1519
 
1448
- ${endpoints_default}`,
1449
- [`${join("api", "schemas.ts")}`]: `${allSchemas.map((it) => it.import).join("\n")}
1450
-
1520
+ ${template(endpoints_default)({ outputType: config.style?.outputType })}`,
1521
+ [`${join2("api", "schemas.ts")}`]: `${allSchemas.map((it) => it.import).join("\n")}
1522
+ import { KIND } from "${config.makeImport("../http/index")}";
1451
1523
  export default {
1452
1524
  ${allSchemas.map((it) => it.use).join(",\n")}
1453
1525
  };
@@ -1466,11 +1538,12 @@ ${allSchemas.map((it) => it.use).join(",\n")}
1466
1538
  );
1467
1539
  return [
1468
1540
  [
1469
- join("api", `${spinalcase2(name)}.ts`),
1541
+ join2("api", `${spinalcase2(name)}.ts`),
1470
1542
  `${[
1471
1543
  ...imps,
1472
1544
  // ...imports,
1473
1545
  `import z from 'zod';`,
1546
+ `import * as http from '${config.makeImport("../http/response")}';`,
1474
1547
  `import { toRequest, json, urlencoded, nobody, formdata, createUrl } from '${config.makeImport("../http/request")}';`,
1475
1548
  `import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
1476
1549
  `import * as ${camelcase3(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`
@@ -1488,8 +1561,8 @@ ${endpoint.flatMap((it) => it.schemas).join(",\n")}
1488
1561
  };
1489
1562
  }
1490
1563
  function toProps(spec, schemaOrRef, aggregator = []) {
1491
- if (isRef5(schemaOrRef)) {
1492
- const schema = followRef4(spec, schemaOrRef.$ref);
1564
+ if (isRef(schemaOrRef)) {
1565
+ const schema = followRef(spec, schemaOrRef.$ref);
1493
1566
  return toProps(spec, schema, aggregator);
1494
1567
  } else if (schemaOrRef.type === "object") {
1495
1568
  for (const [name] of Object.entries(schemaOrRef.properties ?? {})) {
@@ -1534,7 +1607,7 @@ function bodyInputs(config, ctSchema) {
1534
1607
  }
1535
1608
 
1536
1609
  // packages/typescript/src/lib/http/interceptors.txt
1537
- 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.dir('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";
1610
+ 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";
1538
1611
 
1539
1612
  // packages/typescript/src/lib/http/parse-response.txt
1540
1613
  var parse_response_default = 'import { parse } from "fast-content-type-parse";\n\nasync function handleChunkedResponse(response: Response, contentType: string) {\n const { type } = parse(contentType);\n\n switch (type) {\n case "application/json": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return JSON.parse(buffer);\n }\n case "text/html":\n case "text/plain": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return buffer;\n }\n default:\n return response.body;\n }\n}\n\nexport function chunked(response: Response) {\n return response.body!;\n}\n\nexport async function buffered(response: Response) {\n const contentType = response.headers.get("Content-Type");\n if (!contentType) {\n throw new Error("Content-Type header is missing");\n }\n\n if (response.status === 204) {\n return null;\n }\n\n const { type } = parse(contentType);\n switch (type) {\n case "application/json":\n return response.json();\n case "text/plain":\n return response.text();\n case "text/html":\n return response.text();\n case "text/xml":\n case "application/xml":\n return response.text();\n case "application/x-www-form-urlencoded": {\n const text = await response.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n case "multipart/form-data":\n return response.formData();\n default:\n throw new Error(`Unsupported content type: ${contentType}`);\n }\n}\n';
@@ -1543,13 +1616,421 @@ var parse_response_default = 'import { parse } from "fast-content-type-parse";\n
1543
1616
  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";
1544
1617
 
1545
1618
  // packages/typescript/src/lib/http/request.txt
1546
- 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 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";
1619
+ 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";
1547
1620
 
1548
1621
  // packages/typescript/src/lib/http/response.txt
1549
- var response_default = "export class APIResponse<Body = unknown, Status extends number = number> {\n static status: number;\n status: Status;\n data: Body;\n\n constructor(status: Status, data: Body) {\n this.status = status;\n this.data = data;\n }\n\n static create<Body = unknown>(status: number, data: Body) {\n return new this(status, data);\n }\n}\n\nexport class APIError<Body, Status extends number = number> extends APIResponse<\n Body,\n Status\n> {\n static override create<T>(status: number, data: T) {\n return new this(status, data);\n }\n}\n\n// 2xx Success\nexport class Ok<T> extends APIResponse<T, 200> {\n static override status = 200 as const;\n constructor(data: T) {\n super(Ok.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Created<T> extends APIResponse<T, 201> {\n static override status = 201 as const;\n constructor(data: T) {\n super(Created.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Accepted<T> extends APIResponse<T, 202> {\n static override status = 202 as const;\n constructor(data: T) {\n super(Accepted.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class NoContent extends APIResponse<never, 204> {\n static override status = 204 as const;\n constructor() {\n super(NoContent.status, null as never);\n }\n static override create(status: number, data: never): NoContent {\n return new this();\n }\n}\n\n// 4xx Client Errors\nexport class BadRequest<T> extends APIError<T, 400> {\n static override status = 400 as const;\n constructor(data: T) {\n super(BadRequest.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Unauthorized<T = { message: string }> extends APIError<T, 401> {\n static override status = 401 as const;\n constructor(data: T) {\n super(Unauthorized.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class PaymentRequired<T = { message: string }> extends APIError<T, 402> {\n static override status = 402 as const;\n constructor(data: T) {\n super(PaymentRequired.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Forbidden<T = { message: string }> extends APIError<T, 403> {\n static override status = 403 as const;\n constructor(data: T) {\n super(Forbidden.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class NotFound<T = { message: string }> extends APIError<T, 404> {\n static override status = 404 as const;\n constructor(data: T) {\n super(NotFound.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class MethodNotAllowed<T = { message: string }> extends APIError<\n T,\n 405\n> {\n static override status = 405 as const;\n constructor(data: T) {\n super(MethodNotAllowed.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class NotAcceptable<T = { message: string }> extends APIError<T, 406> {\n static override status = 406 as const;\n constructor(data: T) {\n super(NotAcceptable.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Conflict<T = { message: string }> extends APIError<T, 409> {\n static override status = 409 as const;\n constructor(data: T) {\n super(Conflict.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class Gone<T = { message: string }> extends APIError<T, 410> {\n static override status = 410 as const;\n constructor(data: T) {\n super(Gone.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class UnprocessableEntity<\n T = { message: string; errors?: Record<string, string[]> },\n> extends APIError<T, 422> {\n static override status = 422 as const;\n constructor(data: T) {\n super(UnprocessableEntity.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class TooManyRequests<\n T = { message: string; retryAfter?: string },\n> extends APIError<T, 429> {\n static override status = 429 as const;\n constructor(data: T) {\n super(TooManyRequests.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class PayloadTooLarge<T = { message: string }> extends APIError<T, 413> {\n static override status = 413 as const;\n constructor(data: T) {\n super(PayloadTooLarge.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class UnsupportedMediaType<T = { message: string }> extends APIError<\n T,\n 415\n> {\n static override status = 415 as const;\n constructor(data: T) {\n super(UnsupportedMediaType.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\n\n// 5xx Server Errors\nexport class InternalServerError<T = { message: string }> extends APIError<\n T,\n 500\n> {\n static override status = 500 as const;\n constructor(data: T) {\n super(InternalServerError.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class NotImplemented<T = { message: string }> extends APIError<T, 501> {\n static override status = 501 as const;\n constructor(data: T) {\n super(NotImplemented.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class BadGateway<T = { message: string }> extends APIError<T, 502> {\n static override status = 502 as const;\n constructor(data: T) {\n super(BadGateway.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class ServiceUnavailable<\n T = { message: string; retryAfter?: string },\n> extends APIError<T, 503> {\n static override status = 503 as const;\n constructor(data: T) {\n super(ServiceUnavailable.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\nexport class GatewayTimeout<T = { message: string }> extends APIError<T, 504> {\n static override status = 504 as const;\n constructor(data: T) {\n super(GatewayTimeout.status, data);\n }\n static override create<T>(status: number, data: T) {\n return new this(data);\n }\n}\n\nexport type ClientError =\n | BadRequest<{ message: string }>\n | Unauthorized<unknown>\n | PaymentRequired<unknown>\n | Forbidden<unknown>\n | NotFound<unknown>\n | MethodNotAllowed<unknown>\n | NotAcceptable<unknown>\n | Conflict<unknown>\n | Gone<unknown>\n | UnprocessableEntity<unknown>\n | TooManyRequests<unknown>;\n\nexport type ServerError =\n | InternalServerError<unknown>\n | NotImplemented<unknown>\n | BadGateway<unknown>\n | ServiceUnavailable<unknown>\n | GatewayTimeout<unknown>;\n\nexport type ProblematicResponse = ClientError | ServerError;\n\nexport type SuccessfulResponse = Ok<unknown> | Created<unknown> | Accepted<unknown> | NoContent;";
1622
+ var response_default = `export const KIND = Symbol('APIDATA');
1623
+
1624
+ export class APIResponse<Body = unknown, Status extends number = number> {
1625
+ static readonly status: number;
1626
+ static readonly kind: symbol = Symbol.for("APIResponse");
1627
+ status: Status;
1628
+ data: Body;
1629
+
1630
+ constructor(status: Status, data: Body) {
1631
+ this.status = status;
1632
+ this.data = data;
1633
+ }
1634
+
1635
+ static create<Body = unknown>(status: number, data: Body) {
1636
+ return new this(status, data);
1637
+ }
1638
+
1639
+ }
1640
+
1641
+ export class APIError<Body, Status extends number = number> extends APIResponse<
1642
+ Body,
1643
+ Status
1644
+ > {
1645
+ static override create<T>(status: number, data: T) {
1646
+ return new this(status, data);
1647
+ }
1648
+ }
1649
+
1650
+
1651
+ // 2xx Success
1652
+ export class Ok<T> extends APIResponse<T, 200> {
1653
+ static override readonly kind = Symbol.for("Ok");
1654
+ static override readonly status = 200 as const;
1655
+ constructor(data: T) {
1656
+ super(Ok.status, data);
1657
+ }
1658
+ static override create<T>(status: number, data: T) {
1659
+ Object.defineProperty(data, KIND, { value: this.kind });
1660
+ return new this(data);
1661
+ }
1662
+
1663
+ static is<T extends {[KIND]:typeof Ok['kind']}>(value: unknown): value is T {
1664
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1665
+ }
1666
+ }
1667
+
1668
+
1669
+ export class Created<T> extends APIResponse<T, 201> {
1670
+ static override readonly kind = Symbol.for("Created");
1671
+ static override status = 201 as const;
1672
+ constructor(data: T) {
1673
+ super(Created.status, data);
1674
+ }
1675
+ static override create<T>(status: number, data: T) {
1676
+ Object.defineProperty(data, KIND, { value: this.kind });
1677
+ return new this(data);
1678
+ }
1679
+
1680
+ static is<T extends {[KIND]: typeof Created['kind']}>(value: unknown): value is T {
1681
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1682
+ }
1683
+ }
1684
+ export class Accepted<T> extends APIResponse<T, 202> {
1685
+ static override readonly kind = Symbol.for("Accepted");
1686
+ static override status = 202 as const;
1687
+ constructor(data: T) {
1688
+ super(Accepted.status, data);
1689
+ }
1690
+ static override create<T>(status: number, data: T) {
1691
+ Object.defineProperty(data, KIND, { value: this.kind });
1692
+ return new this(data);
1693
+ }
1694
+
1695
+ static is<T extends {[KIND]: typeof Accepted['kind']}>(value: unknown): value is T {
1696
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1697
+ }
1698
+ }
1699
+ export class NoContent extends APIResponse<never, 204> {
1700
+ static override readonly kind = Symbol.for("NoContent");
1701
+ static override status = 204 as const;
1702
+ constructor() {
1703
+ super(NoContent.status, null as never);
1704
+ }
1705
+ static override create(status: number, data: never): NoContent {
1706
+ return new this();
1707
+ }
1708
+
1709
+ static is<T extends {[KIND]: typeof NoContent['kind']}>(value: unknown): value is T {
1710
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1711
+ }
1712
+ }
1713
+
1714
+ // 4xx Client Errors
1715
+ export class BadRequest<T> extends APIError<T, 400> {
1716
+ static override readonly kind = Symbol.for("BadRequest");
1717
+ static override status = 400 as const;
1718
+ constructor(data: T) {
1719
+ super(BadRequest.status, data);
1720
+ }
1721
+ static override create<T>(status: number, data: T) {
1722
+ Object.defineProperty(data, KIND, { value: this.kind });
1723
+ return new this(data);
1724
+ }
1725
+
1726
+ static is<T extends {[KIND]: typeof BadRequest['kind']}>(value: unknown): value is T {
1727
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1728
+ }
1729
+ }
1730
+ export class Unauthorized<T = { message: string }> extends APIError<T, 401> {
1731
+ static override readonly kind = Symbol.for("Unauthorized");
1732
+ static override status = 401 as const;
1733
+ constructor(data: T) {
1734
+ super(Unauthorized.status, data);
1735
+ }
1736
+ static override create<T>(status: number, data: T) {
1737
+ Object.defineProperty(data, KIND, { value: this.kind });
1738
+ return new this(data);
1739
+ }
1740
+
1741
+ static is<T extends {[KIND]: typeof Unauthorized['kind']}>(value: unknown): value is T {
1742
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1743
+ }
1744
+ }
1745
+ export class PaymentRequired<T = { message: string }> extends APIError<T, 402> {
1746
+ static override readonly kind = Symbol.for("PaymentRequired");
1747
+ static override status = 402 as const;
1748
+ constructor(data: T) {
1749
+ super(PaymentRequired.status, data);
1750
+ }
1751
+ static override create<T>(status: number, data: T) {
1752
+ Object.defineProperty(data, KIND, { value: this.kind });
1753
+ return new this(data);
1754
+ }
1755
+
1756
+ static is<T extends {[KIND]: typeof PaymentRequired['kind']}>(value: unknown): value is T {
1757
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1758
+ }
1759
+ }
1760
+ export class Forbidden<T = { message: string }> extends APIError<T, 403> {
1761
+ static override readonly kind = Symbol.for("Forbidden");
1762
+ static override status = 403 as const;
1763
+ constructor(data: T) {
1764
+ super(Forbidden.status, data);
1765
+ }
1766
+ static override create<T>(status: number, data: T) {
1767
+ Object.defineProperty(data, KIND, { value: this.kind });
1768
+ return new this(data);
1769
+ }
1770
+
1771
+ static is<T extends {[KIND]: typeof Forbidden['kind']}>(value: unknown): value is T {
1772
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1773
+ }
1774
+ }
1775
+ export class NotFound<T = { message: string }> extends APIError<T, 404> {
1776
+ static override readonly kind = Symbol.for("NotFound");
1777
+ static override status = 404 as const;
1778
+ constructor(data: T) {
1779
+ super(NotFound.status, data);
1780
+ }
1781
+ static override create<T>(status: number, data: T) {
1782
+ Object.defineProperty(data, KIND, { value: this.kind });
1783
+ return new this(data);
1784
+ }
1785
+
1786
+ static is<T extends {[KIND]: typeof NotFound['kind']}>(value: unknown): value is T {
1787
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1788
+ }
1789
+ }
1790
+ export class MethodNotAllowed<T = { message: string }> extends APIError<
1791
+ T,
1792
+ 405
1793
+ > {
1794
+ static override readonly kind = Symbol.for("MethodNotAllowed");
1795
+ static override status = 405 as const;
1796
+ constructor(data: T) {
1797
+ super(MethodNotAllowed.status, data);
1798
+ }
1799
+ static override create<T>(status: number, data: T) {
1800
+ Object.defineProperty(data, KIND, { value: this.kind });
1801
+ return new this(data);
1802
+ }
1803
+
1804
+ static is<T extends {[KIND]: typeof MethodNotAllowed['kind']}>(value: unknown): value is T {
1805
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1806
+ }
1807
+ }
1808
+ export class NotAcceptable<T = { message: string }> extends APIError<T, 406> {
1809
+ static override readonly kind = Symbol.for("NotAcceptable");
1810
+ static override status = 406 as const;
1811
+ constructor(data: T) {
1812
+ super(NotAcceptable.status, data);
1813
+ }
1814
+ static override create<T>(status: number, data: T) {
1815
+ Object.defineProperty(data, KIND, { value: this.kind });
1816
+ return new this(data);
1817
+ }
1818
+
1819
+ static is<T extends {[KIND]: typeof NotAcceptable['kind']}>(value: unknown): value is T {
1820
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1821
+ }
1822
+ }
1823
+ export class Conflict<T = { message: string }> extends APIError<T, 409> {
1824
+ static override readonly kind = Symbol.for("Conflict");
1825
+ static override status = 409 as const;
1826
+ constructor(data: T) {
1827
+ super(Conflict.status, data);
1828
+ }
1829
+ static override create<T>(status: number, data: T) {
1830
+ Object.defineProperty(data, KIND, { value: this.kind });
1831
+ return new this(data);
1832
+ }
1833
+
1834
+ static is<T extends {[KIND]: typeof Conflict['kind']}>(value: unknown): value is T {
1835
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1836
+ }
1837
+ }
1838
+ export class Gone<T = { message: string }> extends APIError<T, 410> {
1839
+ static override readonly kind = Symbol.for("Gone");
1840
+ static override status = 410 as const;
1841
+ constructor(data: T) {
1842
+ super(Gone.status, data);
1843
+ }
1844
+ static override create<T>(status: number, data: T) {
1845
+ Object.defineProperty(data, KIND, { value: this.kind });
1846
+ return new this(data);
1847
+ }
1848
+
1849
+ static is<T extends {[KIND]: typeof Gone['kind']}>(value: unknown): value is T {
1850
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1851
+ }
1852
+ }
1853
+ export class UnprocessableEntity<
1854
+ T = { message: string; errors?: Record<string, string[]> },
1855
+ > extends APIError<T, 422> {
1856
+ static override readonly kind = Symbol.for("UnprocessableEntity");
1857
+ static override status = 422 as const;
1858
+ constructor(data: T) {
1859
+ super(UnprocessableEntity.status, data);
1860
+ }
1861
+ static override create<T>(status: number, data: T) {
1862
+ Object.defineProperty(data, KIND, { value: this.kind });
1863
+ return new this(data);
1864
+ }
1865
+
1866
+ static is<T extends {[KIND]: typeof UnprocessableEntity['kind']}>(value: unknown): value is T {
1867
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1868
+ }
1869
+ }
1870
+ export class TooManyRequests<
1871
+ T = { message: string; retryAfter?: string },
1872
+ > extends APIError<T, 429> {
1873
+ static override readonly kind = Symbol.for("TooManyRequests");
1874
+ static override status = 429 as const;
1875
+ constructor(data: T) {
1876
+ super(TooManyRequests.status, data);
1877
+ }
1878
+ static override create<T>(status: number, data: T) {
1879
+ Object.defineProperty(data, KIND, { value: this.kind });
1880
+ return new this(data);
1881
+ }
1882
+
1883
+ static is<T extends {[KIND]: typeof TooManyRequests['kind']}>(value: unknown): value is T {
1884
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1885
+ }
1886
+ }
1887
+ export class PayloadTooLarge<T = { message: string }> extends APIError<T, 413> {
1888
+ static override readonly kind = Symbol.for("PayloadTooLarge");
1889
+ static override status = 413 as const;
1890
+ constructor(data: T) {
1891
+ super(PayloadTooLarge.status, data);
1892
+ }
1893
+ static override create<T>(status: number, data: T) {
1894
+ Object.defineProperty(data, KIND, { value: this.kind });
1895
+ return new this(data);
1896
+ }
1897
+
1898
+ static is<T extends {[KIND]: typeof PayloadTooLarge['kind']}>(value: unknown): value is T {
1899
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1900
+ }
1901
+ }
1902
+ export class UnsupportedMediaType<T = { message: string }> extends APIError<
1903
+ T,
1904
+ 415
1905
+ > {
1906
+ static override readonly kind = Symbol.for("UnsupportedMediaType");
1907
+ static override status = 415 as const;
1908
+ constructor(data: T) {
1909
+ super(UnsupportedMediaType.status, data);
1910
+ }
1911
+ static override create<T>(status: number, data: T) {
1912
+ Object.defineProperty(data, KIND, { value: this.kind });
1913
+ return new this(data);
1914
+ }
1915
+
1916
+ static is<T extends {[KIND]: typeof UnsupportedMediaType['kind']}>(value: unknown): value is T {
1917
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1918
+ }
1919
+ }
1920
+
1921
+ // 5xx Server Errors
1922
+ export class InternalServerError<T = { message: string }> extends APIError<
1923
+ T,
1924
+ 500
1925
+ > {
1926
+ static override readonly kind = Symbol.for("InternalServerError");
1927
+ static override status = 500 as const;
1928
+ constructor(data: T) {
1929
+ super(InternalServerError.status, data);
1930
+ }
1931
+ static override create<T>(status: number, data: T) {
1932
+ Object.defineProperty(data, KIND, { value: this.kind });
1933
+ return new this(data);
1934
+ }
1935
+
1936
+ static is<T extends {[KIND]: typeof InternalServerError['kind']}>(value: unknown): value is T {
1937
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1938
+ }
1939
+ }
1940
+ export class NotImplemented<T = { message: string }> extends APIError<T, 501> {
1941
+ static override readonly kind = Symbol.for("NotImplemented");
1942
+ static override status = 501 as const;
1943
+ constructor(data: T) {
1944
+ super(NotImplemented.status, data);
1945
+ }
1946
+ static override create<T>(status: number, data: T) {
1947
+ Object.defineProperty(data, KIND, { value: this.kind });
1948
+ return new this(data);
1949
+ }
1950
+
1951
+ static is<T extends {[KIND]: typeof NotImplemented['kind']}>(value: unknown): value is T {
1952
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1953
+ }
1954
+ }
1955
+ export class BadGateway<T = { message: string }> extends APIError<T, 502> {
1956
+ static override readonly kind = Symbol.for("BadGateway");
1957
+ static override status = 502 as const;
1958
+ constructor(data: T) {
1959
+ super(BadGateway.status, data);
1960
+ }
1961
+ static override create<T>(status: number, data: T) {
1962
+ Object.defineProperty(data, KIND, { value: this.kind });
1963
+ return new this(data);
1964
+ }
1965
+
1966
+ static is<T extends {[KIND]: typeof BadGateway['kind']}>(value: unknown): value is T {
1967
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1968
+ }
1969
+ }
1970
+ export class ServiceUnavailable<
1971
+ T = { message: string; retryAfter?: string },
1972
+ > extends APIError<T, 503> {
1973
+ static override readonly kind = Symbol.for("ServiceUnavailable");
1974
+ static override status = 503 as const;
1975
+ constructor(data: T) {
1976
+ super(ServiceUnavailable.status, data);
1977
+ }
1978
+ static override create<T>(status: number, data: T) {
1979
+ Object.defineProperty(data, KIND, { value: this.kind });
1980
+ return new this(data);
1981
+ }
1982
+
1983
+ static is<T extends {[KIND]: typeof ServiceUnavailable['kind']}>(value: unknown): value is T {
1984
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
1985
+ }
1986
+ }
1987
+ export class GatewayTimeout<T = { message: string }> extends APIError<T, 504> {
1988
+ static override readonly kind = Symbol.for("GatewayTimeout");
1989
+ static override status = 504 as const;
1990
+ constructor(data: T) {
1991
+ super(GatewayTimeout.status, data);
1992
+ }
1993
+ static override create<T>(status: number, data: T) {
1994
+ Object.defineProperty(data, KIND, { value: this.kind });
1995
+ return new this(data);
1996
+ }
1997
+
1998
+ static is<T extends {[KIND]: typeof GatewayTimeout['kind']}>(value: unknown): value is T {
1999
+ return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
2000
+ }
2001
+ }
2002
+
2003
+ export type ClientError =
2004
+ | BadRequest<{ message: string }>
2005
+ | Unauthorized<unknown>
2006
+ | PaymentRequired<unknown>
2007
+ | Forbidden<unknown>
2008
+ | NotFound<unknown>
2009
+ | MethodNotAllowed<unknown>
2010
+ | NotAcceptable<unknown>
2011
+ | Conflict<unknown>
2012
+ | Gone<unknown>
2013
+ | UnprocessableEntity<unknown>
2014
+ | TooManyRequests<unknown>;
2015
+
2016
+ export type ServerError =
2017
+ | InternalServerError<unknown>
2018
+ | NotImplemented<unknown>
2019
+ | BadGateway<unknown>
2020
+ | ServiceUnavailable<unknown>
2021
+ | GatewayTimeout<unknown>;
2022
+
2023
+ export type ProblematicResponse = ClientError | ServerError;
2024
+
2025
+ export type SuccessfulResponse =
2026
+ | Ok<unknown>
2027
+ | Created<unknown>
2028
+ | Accepted<unknown>
2029
+ | NoContent;
2030
+ `;
1550
2031
 
1551
2032
  // packages/typescript/src/lib/http/send-request.txt
1552
- 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 sendRequest(\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 data = (output || APIResponse).create(\n response.status,\n await parser(response),\n );\n <% if(throwError) { %>\n return data;\n <% } else { %>\n return [data as never, 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";
2033
+ 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";
1553
2034
 
1554
2035
  // packages/typescript/src/lib/generate.ts
1555
2036
  function security(spec) {
@@ -1573,6 +2054,15 @@ function security(spec) {
1573
2054
  return options;
1574
2055
  }
1575
2056
  async function generate(spec, settings) {
2057
+ const style = Object.assign(
2058
+ {},
2059
+ {
2060
+ errorAsValue: true,
2061
+ name: "github",
2062
+ outputType: "default"
2063
+ },
2064
+ settings.style ?? {}
2065
+ );
1576
2066
  settings.useTsExtension ??= true;
1577
2067
  const makeImport = (moduleSpecifier) => {
1578
2068
  return settings.useTsExtension ? `${moduleSpecifier}.ts` : moduleSpecifier;
@@ -1580,11 +2070,11 @@ async function generate(spec, settings) {
1580
2070
  const { commonSchemas, endpoints, groups, outputs, commonZod } = generateCode(
1581
2071
  {
1582
2072
  spec,
1583
- style: "github",
2073
+ style,
1584
2074
  makeImport
1585
2075
  }
1586
2076
  );
1587
- const output = settings.mode === "full" ? join2(settings.output, "src") : settings.output;
2077
+ const output = settings.mode === "full" ? join3(settings.output, "src") : settings.output;
1588
2078
  const options = security(spec);
1589
2079
  const clientName = settings.name || "Client";
1590
2080
  const inputFiles = generateInputs(groups, commonZod, makeImport);
@@ -1594,9 +2084,9 @@ async function generate(spec, settings) {
1594
2084
  "models/.getkeep": ""
1595
2085
  // 'README.md': readme,
1596
2086
  });
1597
- await writeFiles(join2(output, "http"), {
2087
+ await writeFiles(join3(output, "http"), {
1598
2088
  "interceptors.ts": `
1599
- import { type RequestConfig } from './${makeImport("request")}';
2089
+ import type { RequestConfig, HeadersInit } from './${makeImport("request")}';
1600
2090
  ${interceptors_default}`,
1601
2091
  "parse-response.ts": parse_response_default,
1602
2092
  "send-request.ts": `import z from 'zod';
@@ -1606,12 +2096,12 @@ import { parseInput } from './${makeImport("parser")}';
1606
2096
  import type { RequestConfig } from './${makeImport("request")}';
1607
2097
  import { APIError, APIResponse } from './${makeImport("response")}';
1608
2098
 
1609
- ${template(send_request_default, {})({ throwError: settings.throwError })}`,
2099
+ ${template2(send_request_default, {})({ throwError: !style.errorAsValue, outputType: style.outputType })}`,
1610
2100
  "response.ts": response_default,
1611
2101
  "parser.ts": parser_default,
1612
2102
  "request.ts": request_default
1613
2103
  });
1614
- await writeFiles(join2(output, "outputs"), outputs);
2104
+ await writeFiles(join3(output, "outputs"), outputs);
1615
2105
  const modelsImports = Object.entries(commonSchemas).map(([name]) => name);
1616
2106
  await writeFiles(output, {
1617
2107
  "client.ts": client_default(
@@ -1621,7 +2111,7 @@ ${template(send_request_default, {})({ throwError: settings.throwError })}`,
1621
2111
  options,
1622
2112
  makeImport
1623
2113
  },
1624
- settings.throwError ?? false
2114
+ style
1625
2115
  ),
1626
2116
  ...inputFiles,
1627
2117
  ...endpoints,
@@ -1639,24 +2129,24 @@ ${template(send_request_default, {})({ throwError: settings.throwError })}`,
1639
2129
  )
1640
2130
  });
1641
2131
  const folders = [
1642
- getFolderExports(join2(output, "outputs"), settings.useTsExtension),
2132
+ getFolderExports(join3(output, "outputs"), settings.useTsExtension),
1643
2133
  getFolderExports(
1644
- join2(output, "inputs"),
2134
+ join3(output, "inputs"),
1645
2135
  settings.useTsExtension,
1646
2136
  ["ts"],
1647
2137
  (dirent) => dirent.isDirectory() && ["schemas"].includes(dirent.name)
1648
2138
  ),
1649
- getFolderExports(join2(output, "api"), settings.useTsExtension),
2139
+ getFolderExports(join3(output, "api"), settings.useTsExtension),
1650
2140
  getFolderExports(
1651
- join2(output, "http"),
2141
+ join3(output, "http"),
1652
2142
  settings.useTsExtension,
1653
2143
  ["ts"],
1654
- (dirent) => dirent.name !== "response.ts"
2144
+ (dirent) => !["response.ts", "parser.ts"].includes(dirent.name)
1655
2145
  )
1656
2146
  ];
1657
2147
  if (modelsImports.length) {
1658
2148
  folders.push(
1659
- getFolderExports(join2(output, "models"), settings.useTsExtension)
2149
+ getFolderExports(join3(output, "models"), settings.useTsExtension)
1660
2150
  );
1661
2151
  }
1662
2152
  const [outputIndex, inputsIndex, apiIndex, httpIndex, modelsIndex] = await Promise.all(folders);