@sdkgen/node-runtime 0.0.0-dev.20231002144112 → 0.0.0-dev.20231002191238

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.
Files changed (66) hide show
  1. package/dist/api-config.js +15 -0
  2. package/dist/context.js +2 -0
  3. package/dist/encode-decode.js +338 -0
  4. package/dist/error.js +27 -0
  5. package/dist/execute.js +53 -0
  6. package/dist/http-client.js +103 -0
  7. package/dist/http-server.js +930 -0
  8. package/dist/index.js +7 -0
  9. package/dist/swagger.js +448 -0
  10. package/dist/test-wrapper.js +53 -0
  11. package/dist/utils.js +4 -0
  12. package/package.json +19 -12
  13. package/.eslintignore +0 -1
  14. package/.eslintrc.json +0 -3
  15. package/.prettierrc +0 -12
  16. package/.vscode/settings.json +0 -14
  17. package/dist/spec/error.spec.d.ts +0 -1
  18. package/dist/spec/error.spec.js +0 -15
  19. package/dist/spec/rest/rest.spec.d.ts +0 -1
  20. package/dist/spec/rest/rest.spec.js +0 -353
  21. package/dist/spec/runtime/errors.spec.d.ts +0 -1
  22. package/dist/spec/runtime/errors.spec.js +0 -43
  23. package/dist/spec/runtime/middleware.spec.d.ts +0 -1
  24. package/dist/spec/runtime/middleware.spec.js +0 -100
  25. package/dist/spec/simple/legacyNodeClient.d.ts +0 -17
  26. package/dist/spec/simple/legacyNodeClient.js +0 -128
  27. package/dist/spec/simple/simple.spec.d.ts +0 -1
  28. package/dist/spec/simple/simple.spec.js +0 -113
  29. package/dist/spec/types.d.ts +0 -1
  30. package/dist/spec/types.js +0 -60
  31. package/dist/spec/types.spec.d.ts +0 -1
  32. package/dist/spec/types.spec.js +0 -128
  33. package/dist/src/api-config.js +0 -19
  34. package/dist/src/context.js +0 -2
  35. package/dist/src/encode-decode.js +0 -376
  36. package/dist/src/error.js +0 -32
  37. package/dist/src/execute.js +0 -56
  38. package/dist/src/http-client.js +0 -105
  39. package/dist/src/http-server.js +0 -941
  40. package/dist/src/index.js +0 -18
  41. package/dist/src/swagger.js +0 -439
  42. package/dist/src/test-wrapper.js +0 -52
  43. package/dist/src/utils.js +0 -7
  44. package/dist/tsconfig.tsbuildinfo +0 -1
  45. package/src/api-config.ts +0 -26
  46. package/src/context.ts +0 -41
  47. package/src/encode-decode.ts +0 -471
  48. package/src/error.ts +0 -30
  49. package/src/execute.ts +0 -67
  50. package/src/http-client.ts +0 -131
  51. package/src/http-server.ts +0 -1137
  52. package/src/index.ts +0 -7
  53. package/src/swagger.ts +0 -498
  54. package/src/test-wrapper.ts +0 -66
  55. package/src/utils.ts +0 -17
  56. /package/dist/{src/api-config.d.ts → api-config.d.ts} +0 -0
  57. /package/dist/{src/context.d.ts → context.d.ts} +0 -0
  58. /package/dist/{src/encode-decode.d.ts → encode-decode.d.ts} +0 -0
  59. /package/dist/{src/error.d.ts → error.d.ts} +0 -0
  60. /package/dist/{src/execute.d.ts → execute.d.ts} +0 -0
  61. /package/dist/{src/http-client.d.ts → http-client.d.ts} +0 -0
  62. /package/dist/{src/http-server.d.ts → http-server.d.ts} +0 -0
  63. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
  64. /package/dist/{src/swagger.d.ts → swagger.d.ts} +0 -0
  65. /package/dist/{src/test-wrapper.d.ts → test-wrapper.d.ts} +0 -0
  66. /package/dist/{src/utils.d.ts → utils.d.ts} +0 -0
@@ -1,471 +0,0 @@
1
- import * as CNPJ from "@fnando/cnpj";
2
- import * as CPF from "@fnando/cpf";
3
- import type { AstJson, TypeDescription } from "@sdkgen/parser";
4
- import { Decimal } from "decimal.js";
5
-
6
- import type { DeepReadonly } from "./utils";
7
-
8
- type TypeTable = AstJson["typeTable"];
9
-
10
- const simpleStringTypes = ["string", "email", "html", "xml"];
11
- const simpleTypes = ["json", "bool", "url", "int", "uint", "float", "money", "hex", "uuid", "base64", "void", ...simpleStringTypes];
12
-
13
- type ExpandRecursively<T> = T extends object ? (T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never) : T;
14
-
15
- type JsonType = number | string | boolean | null | JsonType[] | { [Key in string]: JsonType };
16
-
17
- type AnyDecodedType = number | string | boolean | null | bigint | Decimal | Buffer | Date | AnyDecodedType[] | { [Key in string]: AnyDecodedType };
18
-
19
- export type DecodedType<Type, Table extends object = {}> = TypeDescription extends Type
20
- ? AnyDecodedType
21
- : Type extends "string" | "email" | "html" | "xml" | "url" | "hex" | "uuid" | "base64" | "cpf" | "cnpj"
22
- ? string
23
- : Type extends "json"
24
- ? JsonType
25
- : Type extends "bool"
26
- ? boolean
27
- : Type extends "void"
28
- ? null
29
- : Type extends "int" | "uint" | "float" | "money"
30
- ? number
31
- : Type extends "bigint"
32
- ? bigint
33
- : Type extends "bytes"
34
- ? Buffer
35
- : Type extends "decimal"
36
- ? Decimal
37
- : Type extends "date" | "datetime"
38
- ? Date
39
- : Type extends `${infer X}?`
40
- ? DecodedType<X, Table> | null
41
- : Type extends `${infer X}[]`
42
- ? Array<DecodedType<X, Table>>
43
- : Type extends Array<string | [string, string]>
44
- ? DecodedEnumType<Type, Table>
45
- : Type extends ReadonlyArray<string | readonly [string, string]>
46
- ? DecodedEnumType<Type, Table>
47
- : Type extends object
48
- ? { -readonly [Key in keyof Type]: DecodedType<Type[Key], Table> }
49
- : object extends Table
50
- ? never
51
- : Type extends keyof Table
52
- ? DecodedType<Table[Type], Table>
53
- : never;
54
-
55
- type DecodedEnumType<
56
- Type extends Array<string | [string, string]> | ReadonlyArray<string | readonly [string, string]>,
57
- Table extends object,
58
- > = Type[number] extends string ? Type[number] : DecodeTaggedEnumValueType<Type[number], Table>;
59
-
60
- type DecodeTaggedEnumValueType<
61
- ValueType extends string | [string, string] | readonly [string, string],
62
- Table extends object,
63
- > = ValueType extends string
64
- ? { tag: ValueType }
65
- : ValueType extends [infer Tag, infer Struct]
66
- ? ExpandRecursively<{ tag: Tag } & DecodedType<Struct, Table>>
67
- : ValueType extends readonly [infer Tag, infer Struct]
68
- ? ExpandRecursively<{ tag: Tag } & DecodedType<Struct, Table>>
69
- : never;
70
-
71
- export type EncodedType<Type, Table extends object = {}> = TypeDescription extends Type
72
- ? JsonType
73
- : Type extends "string" | "email" | "html" | "xml" | "url" | "hex" | "uuid" | "base64" | "cpf" | "cnpj"
74
- ? string
75
- : Type extends "json"
76
- ? JsonType
77
- : Type extends "bool"
78
- ? boolean
79
- : Type extends "void"
80
- ? null
81
- : Type extends "int" | "uint" | "float" | "money"
82
- ? number
83
- : Type extends "bigint" | "bytes" | "date" | "datetime" | "decimal"
84
- ? string
85
- : Type extends `${infer X}?`
86
- ? EncodedType<X, Table> | null
87
- : Type extends `${infer X}[]`
88
- ? Array<EncodedType<X, Table>>
89
- : Type extends Array<string | [string, string]>
90
- ? EnumEncodedValueType<Type[number], Table>
91
- : Type extends ReadonlyArray<string | readonly [string, string]>
92
- ? EnumEncodedValueType<Type[number], Table>
93
- : Type extends object
94
- ? { -readonly [Key in keyof Type]: EncodedType<Type[Key], Table> }
95
- : object extends Table
96
- ? never
97
- : Type extends keyof Table
98
- ? EncodedType<Table[Type], Table>
99
- : never;
100
-
101
- type EnumEncodedValueType<ValueType extends string | [string, string] | readonly [string, string], Table extends object> = ValueType extends string
102
- ? ValueType
103
- : ValueType extends [infer Tag, infer Struct]
104
- ? [Tag, EncodedType<Struct, Table>]
105
- : ValueType extends readonly [infer Tag, infer Struct]
106
- ? [Tag, EncodedType<Struct, Table>]
107
- : never;
108
-
109
- class ParseError extends Error {
110
- constructor(path: string, type: DeepReadonly<TypeDescription>, value: unknown) {
111
- let str: string;
112
-
113
- try {
114
- str = JSON.stringify(value);
115
- } catch (err) {
116
- str = String(value);
117
- }
118
-
119
- super(`Invalid type at '${path}', expected ${String(type)}, got ${str}`);
120
- }
121
- }
122
-
123
- function simpleEncodeDecode(path: string, type: string, value: unknown) {
124
- if (type === "json") {
125
- if (value === null || value === undefined) {
126
- return null;
127
- }
128
-
129
- return JSON.parse(JSON.stringify(value)) as unknown;
130
- } else if (type === "bool") {
131
- if (typeof value !== "boolean") {
132
- throw new ParseError(path, type, value);
133
- }
134
-
135
- return value;
136
- } else if (simpleStringTypes.includes(type)) {
137
- if (typeof value !== "string") {
138
- throw new ParseError(path, type, value);
139
- }
140
-
141
- return value;
142
- } else if (type === "hex") {
143
- if (typeof value !== "string" || !/^(?:[A-Fa-f0-9]{2})*$/u.test(value)) {
144
- throw new ParseError(path, type, value);
145
- }
146
-
147
- return value.toLowerCase();
148
- } else if (type === "uuid") {
149
- if (typeof value !== "string" || !/^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$/u.test(value)) {
150
- throw new ParseError(path, type, value);
151
- }
152
-
153
- return value.toLowerCase();
154
- } else if (type === "base64") {
155
- if (typeof value !== "string" || Buffer.from(value, "base64").toString("base64") !== value) {
156
- throw new ParseError(path, type, value);
157
- }
158
-
159
- return value;
160
- } else if (type === "int") {
161
- if (typeof value !== "number" || (value | 0) !== value) {
162
- throw new ParseError(path, type, value);
163
- }
164
-
165
- return value;
166
- } else if (type === "uint") {
167
- if (typeof value !== "number" || (value | 0) !== value || value < 0) {
168
- throw new ParseError(path, type, value);
169
- }
170
-
171
- return value;
172
- } else if (type === "float") {
173
- if (typeof value !== "number") {
174
- throw new ParseError(path, type, value);
175
- }
176
-
177
- return value;
178
- } else if (type === "money") {
179
- if (typeof value !== "number" || !Number.isInteger(value)) {
180
- throw new ParseError(path, type, value);
181
- }
182
-
183
- return value;
184
- } else if (type === "url") {
185
- let url: URL | undefined;
186
-
187
- if (typeof value === "string") {
188
- try {
189
- url = new URL(value);
190
- } catch (e) {
191
- // ignore
192
- }
193
- }
194
-
195
- if (!url) {
196
- throw new ParseError(path, type, value);
197
- }
198
-
199
- return url.toString();
200
- } else if (type === "void") {
201
- return null;
202
- }
203
-
204
- throw new Error(`Unknown type '${type}' at '${path}'`);
205
- }
206
-
207
- export function encode<Table extends DeepReadonly<TypeTable>, Type extends DeepReadonly<TypeDescription>>(
208
- typeTable: Table,
209
- path: string,
210
- type: Type,
211
- value: unknown,
212
- ): EncodedType<Type, Table> {
213
- if (typeof type === "string" && !type.endsWith("?") && type !== "void" && (value === null || value === undefined)) {
214
- throw new Error(`Invalid type at '${path}', cannot be null`);
215
- } else if (Array.isArray(type)) {
216
- if (type.every(tag => typeof tag === "string")) {
217
- for (const tag of type) {
218
- if (tag === value) {
219
- return tag as EncodedType<Type, Table>;
220
- }
221
- }
222
- } else if (typeof value === "object" && value && "tag" in value) {
223
- const { tag: tagValue, ...restValue } = value as object & { tag: unknown };
224
-
225
- for (const entry of type) {
226
- if (typeof entry === "string") {
227
- if (entry === tagValue) {
228
- return entry as EncodedType<Type, Table>;
229
- }
230
- } else {
231
- const [tag, valueType] = entry as [string, string];
232
-
233
- if (tag === tagValue) {
234
- const encodedValues = encode(typeTable, `${path}.${tag}`, valueType, restValue) as object;
235
-
236
- // eslint-disable-next-line max-depth
237
- if (Object.values(encodedValues).every(v => v === null)) {
238
- return tag as EncodedType<Type, Table>;
239
- }
240
-
241
- return [tag, encodedValues] as EncodedType<Type, Table>;
242
- }
243
- }
244
- }
245
- }
246
-
247
- throw new ParseError(path, type, value);
248
- } else if (typeof type === "object") {
249
- if (typeof value !== "object") {
250
- throw new ParseError(path, type, value);
251
- }
252
-
253
- const obj: Record<string, unknown> = {};
254
-
255
- for (const key of Object.keys(type)) {
256
- obj[key] = encode(typeTable, `${path}.${key}`, (type as Record<string, TypeDescription>)[key], (value as Record<string, unknown>)[key]);
257
- }
258
-
259
- return obj as EncodedType<Type, Table>;
260
- } else if (typeof type === "string" && type.endsWith("?")) {
261
- if (value === null || value === undefined) {
262
- return null as EncodedType<Type, Table>;
263
- }
264
-
265
- return encode(typeTable, path, type.slice(0, type.length - 1), value) as EncodedType<Type, Table>;
266
- } else if (typeof type === "string" && type.endsWith("[]")) {
267
- if (!Array.isArray(value)) {
268
- throw new ParseError(path, type, value);
269
- }
270
-
271
- return value.map((entry, index) => encode(typeTable, `${path}[${index}]`, type.slice(0, type.length - 2), entry)) as EncodedType<Type, Table>;
272
- } else if (typeof type === "string" && simpleTypes.includes(type)) {
273
- return simpleEncodeDecode(path, type, value) as EncodedType<Type, Table>;
274
- } else if (type === "bytes") {
275
- if (!(value instanceof Buffer)) {
276
- throw new ParseError(path, type, value);
277
- }
278
-
279
- return value.toString("base64") as EncodedType<Type, Table>;
280
- } else if (type === "bigint") {
281
- if (!(typeof value === "bigint")) {
282
- throw new ParseError(path, type, value);
283
- }
284
-
285
- return value.toString() as EncodedType<Type, Table>;
286
- } else if (type === "cpf") {
287
- if (typeof value !== "string" || !CPF.isValid(value)) {
288
- throw new ParseError(path, type, value);
289
- }
290
-
291
- return CPF.strip(value) as EncodedType<Type, Table>;
292
- } else if (type === "cnpj") {
293
- if (typeof value !== "string" || !CNPJ.isValid(value)) {
294
- throw new ParseError(path, type, value);
295
- }
296
-
297
- return CNPJ.strip(value) as EncodedType<Type, Table>;
298
- } else if (type === "date") {
299
- if (!(value instanceof Date && !isNaN(value.getTime())) && !(typeof value === "string" && /^[0-9]{4}-[01][0-9]-[0123][0-9]$/u.test(value))) {
300
- throw new ParseError(path, type, value);
301
- }
302
-
303
- const dateValue = value instanceof Date ? value : new Date(value);
304
-
305
- return `${dateValue.getFullYear().toString().padStart(4, "0")}-${(dateValue.getMonth() + 1).toString().padStart(2, "0")}-${dateValue
306
- .getDate()
307
- .toString()
308
- .padStart(2, "0")}` as EncodedType<Type, Table>;
309
- } else if (type === "datetime") {
310
- if (
311
- !(value instanceof Date && !isNaN(value.getTime())) &&
312
- !(
313
- typeof value === "string" &&
314
- /^[0-9]{4}-[01][0-9]-[0123][0-9]T[012][0-9]:[0123456][0-9]:[0123456][0-9](?:\.[0-9]{1,6})?(?:Z|[+-][012][0-9]:[0123456][0-9])?$/u.test(value)
315
- )
316
- ) {
317
- throw new ParseError(path, type, value);
318
- }
319
-
320
- return (typeof value === "string" ? new Date(value) : value).toISOString().replace("Z", "") as EncodedType<Type, Table>;
321
- } else if (type === "decimal") {
322
- if (typeof value !== "number" && (typeof value !== "string" || !/^-?[0-9]+(?:\.[0-9]+)?$/u.test(value)) && !Decimal.isDecimal(value)) {
323
- throw new ParseError(path, type, value);
324
- }
325
-
326
- return new Decimal(value).toString() as EncodedType<Type, Table>;
327
- } else {
328
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
329
- const resolved = (typeTable as Record<string, TypeDescription>)[type as string];
330
-
331
- if (resolved) {
332
- return encode(typeTable, path, resolved, value) as EncodedType<Type, Table>;
333
- }
334
-
335
- throw new Error(`Unknown type '${String(type)}' at '${path}'`);
336
- }
337
- }
338
-
339
- export function decode<Table extends DeepReadonly<TypeTable>, Type extends DeepReadonly<TypeDescription>>(
340
- typeTable: Table,
341
- path: string,
342
- type: Type,
343
- value: unknown,
344
- ): DecodedType<Type, Table> {
345
- if (typeof type === "string" && !type.endsWith("?") && type !== "void" && (value === null || value === undefined)) {
346
- throw new Error(`Invalid type at '${path}', cannot be null`);
347
- } else if (Array.isArray(type)) {
348
- if (type.every(tag => typeof tag === "string")) {
349
- for (const tag of type) {
350
- if (tag === value) {
351
- return tag as DecodedType<Type, Table>;
352
- }
353
- }
354
- } else {
355
- for (const entry of type) {
356
- if (typeof entry === "string") {
357
- if (entry === value) {
358
- return { tag: entry } as DecodedType<Type, Table>;
359
- }
360
- } else {
361
- const [tag, valueType] = entry as [string, string];
362
-
363
- if (tag === value) {
364
- const decodedValues = decode(typeTable, `${path}.${tag}`, valueType, {}) as object;
365
-
366
- return { ...decodedValues, tag } as DecodedType<Type, Table>;
367
- } else if (Array.isArray(value) && value.length === 2 && tag === value[0]) {
368
- const decodedValues = decode(typeTable, `${path}.${tag}`, valueType, value[1]) as object;
369
-
370
- return { ...decodedValues, tag } as DecodedType<Type, Table>;
371
- }
372
- }
373
- }
374
- }
375
-
376
- throw new ParseError(path, type, value);
377
- } else if (typeof type === "object") {
378
- if (typeof value !== "object") {
379
- throw new ParseError(path, type, value);
380
- }
381
-
382
- const obj: Record<string, unknown> = {};
383
-
384
- for (const key of Object.keys(type)) {
385
- obj[key] = decode(typeTable, `${path}.${key}`, (type as Record<string, TypeDescription>)[key], (value as Record<string, unknown>)[key]);
386
- }
387
-
388
- return obj as DecodedType<Type, Table>;
389
- } else if (typeof type === "string" && type.endsWith("?")) {
390
- if (value === null || value === undefined) {
391
- return null as DecodedType<Type, Table>;
392
- }
393
-
394
- return decode(typeTable, path, type.slice(0, type.length - 1), value) as unknown as DecodedType<Type, Table>;
395
- } else if (typeof type === "string" && type.endsWith("[]")) {
396
- if (!Array.isArray(value)) {
397
- throw new ParseError(path, type, value);
398
- }
399
-
400
- return value.map((entry, index) => decode(typeTable, `${path}[${index}]`, type.slice(0, type.length - 2), entry)) as DecodedType<Type, Table>;
401
- } else if (typeof type === "string" && simpleTypes.includes(type)) {
402
- return simpleEncodeDecode(path, type, value) as DecodedType<Type, Table>;
403
- } else if (type === "bytes") {
404
- if (typeof value !== "string") {
405
- throw new ParseError(path, `${String(type)} (base 64)`, value);
406
- }
407
-
408
- const buffer = Buffer.from(value, "base64");
409
-
410
- if (buffer.toString("base64") !== value) {
411
- throw new ParseError(path, `${String(type)} (base 64)`, value);
412
- }
413
-
414
- return buffer as DecodedType<Type, Table>;
415
- } else if (type === "bigint") {
416
- if (typeof value !== "number" && (typeof value !== "string" || !/^-?[0-9]+$/u.test(value))) {
417
- throw new ParseError(path, type, value);
418
- }
419
-
420
- return BigInt(value) as DecodedType<Type, Table>;
421
- } else if (type === "cpf") {
422
- if (typeof value !== "string" || !CPF.isValid(value)) {
423
- throw new ParseError(path, type, value);
424
- }
425
-
426
- return CPF.format(value) as DecodedType<Type, Table>;
427
- } else if (type === "cnpj") {
428
- if (typeof value !== "string" || !CNPJ.isValid(value)) {
429
- throw new ParseError(path, type, value);
430
- }
431
-
432
- return CNPJ.format(value) as DecodedType<Type, Table>;
433
- } else if (type === "date") {
434
- if (typeof value !== "string" || !/^[0-9]{4}-[01][0-9]-[0123][0-9]$/u.test(value)) {
435
- throw new ParseError(path, type, value);
436
- }
437
-
438
- const day = parseInt(value.split("-")[2], 10);
439
- const month = parseInt(value.split("-")[1], 10) - 1;
440
- const year = parseInt(value.split("-")[0], 10);
441
- const date = new Date(year, month, day);
442
-
443
- if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
444
- throw new ParseError(path, type, value);
445
- }
446
-
447
- return date as DecodedType<Type, Table>;
448
- } else if (type === "datetime") {
449
- if (typeof value !== "string" || !/^[0-9]{4}-[01][0-9]-[0123][0-9]T[012][0-9]:[0123456][0-9]:[0123456][0-9](?:\.[0-9]{1,6})?Z?$/u.test(value)) {
450
- throw new ParseError(path, type, value);
451
- }
452
-
453
- return new Date(`${value.endsWith("Z") ? value : value.concat("Z")}`) as DecodedType<Type, Table>;
454
- } else if (type === "decimal") {
455
- if (typeof value !== "number" && (typeof value !== "string" || !/^-?[0-9]+(?:\.[0-9]+)?$/u.test(value))) {
456
- throw new ParseError(path, type, value);
457
- }
458
-
459
- return new Decimal(value) as DecodedType<Type, Table>;
460
- } else {
461
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
462
- const resolved = (typeTable as Record<string, TypeDescription>)[type as string];
463
-
464
- if (resolved) {
465
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
466
- return decode(typeTable, path, resolved, value) as unknown as DecodedType<Type, Table>;
467
- }
468
-
469
- throw new Error(`Unknown type '${String(type)}' at '${path}'`);
470
- }
471
- }
package/src/error.ts DELETED
@@ -1,30 +0,0 @@
1
- export abstract class SdkgenError extends Error {
2
- get type(): string {
3
- return this.constructor.name;
4
- }
5
-
6
- public toJSON(): { message: string; type: string } {
7
- return {
8
- message: this.message,
9
- type: this.type,
10
- };
11
- }
12
- }
13
- export abstract class SdkgenErrorWithData<DataType> extends SdkgenError {
14
- constructor(
15
- message: string,
16
- public data: DataType,
17
- ) {
18
- super(message);
19
- }
20
-
21
- public toJSON(): { data: DataType; message: string; type: string } {
22
- return {
23
- data: this.data,
24
- message: this.message,
25
- type: this.type,
26
- };
27
- }
28
- }
29
-
30
- export class Fatal extends SdkgenError {}
package/src/execute.ts DELETED
@@ -1,67 +0,0 @@
1
- import { ThrowsAnnotation } from "@sdkgen/parser";
2
-
3
- import type { BaseApiConfig } from "./api-config";
4
- import type { Context, ContextReply } from "./context";
5
- import { decode, encode } from "./encode-decode";
6
- import { Fatal } from "./error";
7
- import { has } from "./utils";
8
-
9
- export async function executeRequest<ExtraContextT>(ctx: Context & ExtraContextT, apiConfig: BaseApiConfig<ExtraContextT>) {
10
- // eslint-disable-next-line func-style
11
- let next = async () => {
12
- try {
13
- const functionDescription = apiConfig.astJson.functionTable[ctx.request.name];
14
- const functionImplementation = apiConfig.fn[ctx.request.name];
15
-
16
- if (!functionDescription || !functionImplementation) {
17
- throw new Fatal(`Function does not exist: ${ctx.request.name}`);
18
- }
19
-
20
- const args = decode(apiConfig.astJson.typeTable, `${ctx.request.name}.args`, functionDescription.args, ctx.request.args);
21
-
22
- const ret = (await functionImplementation(ctx, args)) as unknown;
23
- const encodedRet = encode(apiConfig.astJson.typeTable, `${ctx.request.name}.ret`, functionDescription.ret, ret);
24
-
25
- return { result: encodedRet } as ContextReply;
26
- } catch (error) {
27
- return { error } as ContextReply;
28
- }
29
- };
30
-
31
- for (let i = apiConfig.middlewares.length - 1; i >= 0; --i) {
32
- const middleware = apiConfig.middlewares[i];
33
- const previousNext = next;
34
-
35
- next = async () => {
36
- try {
37
- return await middleware(ctx, previousNext);
38
- } catch (error) {
39
- return { error } as ContextReply;
40
- }
41
- };
42
- }
43
-
44
- const reply = await next();
45
-
46
- // If errors, check if the error type is one of the @throws annotation. If it isn't, change to Fatal
47
- if (reply.error) {
48
- const functionAst = apiConfig.ast.operations.find(op => op.name === ctx.request.name);
49
-
50
- if (functionAst) {
51
- const allowedErrors = functionAst.annotations.filter(ann => ann instanceof ThrowsAnnotation).map(ann => (ann as ThrowsAnnotation).error);
52
-
53
- if (
54
- typeof reply.error !== "object" ||
55
- reply.error === null ||
56
- !has(reply.error, "type") ||
57
- typeof reply.error.type !== "string" ||
58
- (allowedErrors.length > 0 && !allowedErrors.includes(reply.error.type)) ||
59
- !apiConfig.astJson.errors.map(error => (typeof error === "string" ? error : error[0])).includes(reply.error.type)
60
- ) {
61
- Object.defineProperty(reply.error, "type", { value: "Fatal" });
62
- }
63
- }
64
- }
65
-
66
- return reply;
67
- }
@@ -1,131 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- /* eslint-disable prefer-promise-reject-errors */
3
- import { randomBytes } from "crypto";
4
- import { request as httpRequest } from "http";
5
- import { request as httpsRequest } from "https";
6
- import type { RequestOptions } from "https";
7
- import { hostname } from "os";
8
- import { URL } from "url";
9
-
10
- import type { AstJson } from "@sdkgen/parser";
11
- import type { PartialDeep } from "type-fest";
12
-
13
- import type { Context } from "./context";
14
- import { decode, encode } from "./encode-decode";
15
- import type { SdkgenError, SdkgenErrorWithData } from "./error";
16
- import type { DeepReadonly } from "./utils";
17
- import { has } from "./utils";
18
-
19
- type ErrClasses = Record<string, (new (message: string, data: any) => SdkgenErrorWithData<any>) | (new (message: string) => SdkgenError) | undefined>;
20
-
21
- export class SdkgenHttpClient {
22
- private baseUrl: URL;
23
-
24
- extra = new Map<string, unknown>();
25
-
26
- constructor(
27
- baseUrl: string,
28
- private astJson: DeepReadonly<AstJson>,
29
- private errClasses: ErrClasses,
30
- ) {
31
- this.baseUrl = new URL(baseUrl);
32
- }
33
-
34
- async makeRequest(ctx: PartialDeep<Context> | null, functionName: string, args: unknown): Promise<any> {
35
- const func = this.astJson.functionTable[functionName];
36
-
37
- if (!func) {
38
- throw new Error(`Unknown function ${functionName}`);
39
- }
40
-
41
- const extra: Record<string, unknown> = {};
42
-
43
- for (const [key, value] of this.extra) {
44
- extra[key] = value;
45
- }
46
-
47
- const requestBody = JSON.stringify({
48
- args: encode(this.astJson.typeTable, `${functionName}.args`, func.args, args),
49
- deviceInfo: ctx?.request?.deviceInfo ?? { id: hostname(), type: "node" },
50
- extra: {
51
- ...extra,
52
- ...ctx?.request?.extra,
53
- },
54
- name: functionName,
55
- requestId: ctx?.request?.id ? ctx.request.id + randomBytes(6).toString("hex") : randomBytes(16).toString("hex"),
56
- version: 3,
57
- });
58
-
59
- const options: RequestOptions = {
60
- hostname: this.baseUrl.hostname,
61
- method: "POST",
62
- path: this.baseUrl.pathname,
63
- port: this.baseUrl.port,
64
- headers: {
65
- "content-type": "application/sdkgen",
66
- },
67
- };
68
-
69
- const encodedRet = await new Promise<unknown>((resolve, reject) => {
70
- const req = (this.baseUrl.protocol === "http:" ? httpRequest : httpsRequest)(options, res => {
71
- let data = "";
72
-
73
- res.on("data", chunk => {
74
- data += chunk;
75
- });
76
- res.on("end", () => {
77
- try {
78
- const response = JSON.parse(data) as object;
79
-
80
- if (has(response, "error") && response.error) {
81
- reject(response.error);
82
- } else {
83
- resolve(has(response, "result") ? response.result : null);
84
- }
85
- } catch (error) {
86
- reject({ message: `${error}`, type: "Fatal" });
87
- }
88
- });
89
- res.on("error", error => {
90
- reject({ message: `${error}`, type: "Fatal" });
91
- });
92
- res.on("aborted", () => {
93
- reject({ message: "Request aborted", type: "Fatal" });
94
- });
95
- });
96
-
97
- req.on("error", error => {
98
- reject({ message: `${error}`, type: "Fatal" });
99
- });
100
-
101
- req.write(requestBody);
102
- req.end();
103
- }).catch((error: object) => {
104
- if (has(error, "type") && has(error, "message") && typeof error.type === "string" && typeof error.message === "string") {
105
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
106
- const errClass = this.errClasses[error.type] ?? this.errClasses.Fatal!;
107
- const errType = errClass.name;
108
-
109
- const errorJson = this.astJson.errors.find(err => (Array.isArray(err) ? err[0] === errType : err === errType));
110
-
111
- let newError;
112
-
113
- if (errorJson && Array.isArray(errorJson) && has(error, "data")) {
114
- newError = new errClass(error.message, decode(this.astJson.typeTable, `${errClass.name}.data`, errorJson[1], error.data));
115
- } else {
116
- newError = new errClass(error.message, undefined);
117
- }
118
-
119
- if (!newError.type) {
120
- (newError as unknown as { type: string }).type = errType;
121
- }
122
-
123
- throw newError;
124
- } else {
125
- throw error;
126
- }
127
- });
128
-
129
- return decode(this.astJson.typeTable, `${functionName}.ret`, func.ret, encodedRet);
130
- }
131
- }