@sdkgen/node-runtime 2.3.2 → 2.5.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/api-config.js +19 -0
- package/dist/{src/context.d.ts → context.d.ts} +1 -0
- package/dist/context.js +3 -0
- package/dist/encode-decode.js +344 -0
- package/dist/error.js +33 -0
- package/dist/execute.js +57 -0
- package/dist/http-client.js +107 -0
- package/dist/{src/http-server.d.ts → http-server.d.ts} +1 -0
- package/dist/http-server.js +941 -0
- package/dist/{src/index.js → index.js} +1 -0
- package/dist/swagger.js +454 -0
- package/dist/test-wrapper.js +58 -0
- package/dist/utils.js +8 -0
- package/package.json +50 -34
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -3
- package/.prettierrc +0 -12
- package/.vscode/settings.json +0 -14
- package/dist/spec/error.spec.d.ts +0 -1
- package/dist/spec/error.spec.js +0 -15
- package/dist/spec/rest/rest.spec.d.ts +0 -1
- package/dist/spec/rest/rest.spec.js +0 -353
- package/dist/spec/runtime/errors.spec.d.ts +0 -1
- package/dist/spec/runtime/errors.spec.js +0 -43
- package/dist/spec/runtime/middleware.spec.d.ts +0 -1
- package/dist/spec/runtime/middleware.spec.js +0 -100
- package/dist/spec/simple/legacyNodeClient.d.ts +0 -17
- package/dist/spec/simple/legacyNodeClient.js +0 -128
- package/dist/spec/simple/simple.spec.d.ts +0 -1
- package/dist/spec/simple/simple.spec.js +0 -113
- package/dist/spec/types.d.ts +0 -1
- package/dist/spec/types.js +0 -60
- package/dist/spec/types.spec.d.ts +0 -1
- package/dist/spec/types.spec.js +0 -128
- package/dist/src/api-config.js +0 -19
- package/dist/src/context.js +0 -2
- package/dist/src/encode-decode.js +0 -376
- package/dist/src/error.js +0 -32
- package/dist/src/execute.js +0 -56
- package/dist/src/http-client.js +0 -105
- package/dist/src/http-server.js +0 -941
- package/dist/src/swagger.js +0 -439
- package/dist/src/test-wrapper.js +0 -52
- package/dist/src/utils.js +0 -7
- package/dist/tsconfig.tsbuildinfo +0 -1
- /package/dist/{src/api-config.d.ts → api-config.d.ts} +0 -0
- /package/dist/{src/encode-decode.d.ts → encode-decode.d.ts} +0 -0
- /package/dist/{src/error.d.ts → error.d.ts} +0 -0
- /package/dist/{src/execute.d.ts → execute.d.ts} +0 -0
- /package/dist/{src/http-client.d.ts → http-client.d.ts} +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/swagger.d.ts → swagger.d.ts} +0 -0
- /package/dist/{src/test-wrapper.d.ts → test-wrapper.d.ts} +0 -0
- /package/dist/{src/utils.d.ts → utils.d.ts} +0 -0
package/dist/src/http-server.js
DELETED
|
@@ -1,941 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SdkgenHttpServer = void 0;
|
|
7
|
-
const crypto_1 = require("crypto");
|
|
8
|
-
const fs_1 = require("fs");
|
|
9
|
-
const http_1 = require("http");
|
|
10
|
-
const os_1 = require("os");
|
|
11
|
-
const querystring_1 = require("querystring");
|
|
12
|
-
const url_1 = require("url");
|
|
13
|
-
const util_1 = require("util");
|
|
14
|
-
const csharp_generator_1 = require("@sdkgen/csharp-generator");
|
|
15
|
-
const dart_generator_1 = require("@sdkgen/dart-generator");
|
|
16
|
-
const fsharp_generator_1 = require("@sdkgen/fsharp-generator");
|
|
17
|
-
const kotlin_generator_1 = require("@sdkgen/kotlin-generator");
|
|
18
|
-
const parser_1 = require("@sdkgen/parser");
|
|
19
|
-
const playground_1 = require("@sdkgen/playground");
|
|
20
|
-
const swift_generator_1 = require("@sdkgen/swift-generator");
|
|
21
|
-
const typescript_generator_1 = require("@sdkgen/typescript-generator");
|
|
22
|
-
const busboy_1 = __importDefault(require("busboy"));
|
|
23
|
-
const file_type_1 = __importDefault(require("file-type"));
|
|
24
|
-
const request_ip_1 = require("request-ip");
|
|
25
|
-
const serve_handler_1 = __importDefault(require("serve-handler"));
|
|
26
|
-
const encode_decode_1 = require("./encode-decode");
|
|
27
|
-
const error_1 = require("./error");
|
|
28
|
-
const execute_1 = require("./execute");
|
|
29
|
-
const swagger_1 = require("./swagger");
|
|
30
|
-
const utils_1 = require("./utils");
|
|
31
|
-
class SdkgenHttpServer {
|
|
32
|
-
constructor(apiConfig, ...maybeExtraContext) {
|
|
33
|
-
var _a;
|
|
34
|
-
this.apiConfig = apiConfig;
|
|
35
|
-
this.headers = new Map();
|
|
36
|
-
this.healthChecks = [];
|
|
37
|
-
this.handlers = [];
|
|
38
|
-
this.dynamicCorsOrigin = true;
|
|
39
|
-
this.introspection = true;
|
|
40
|
-
this.log = (message) => {
|
|
41
|
-
console.log(`${new Date().toISOString()} ${message}`);
|
|
42
|
-
};
|
|
43
|
-
this.hasSwagger = false;
|
|
44
|
-
this.ignoredUrlPrefix = "";
|
|
45
|
-
this.handleRequest = (req, res) => {
|
|
46
|
-
const hrStart = process.hrtime();
|
|
47
|
-
req.on("error", err => {
|
|
48
|
-
console.error(err);
|
|
49
|
-
res.end();
|
|
50
|
-
});
|
|
51
|
-
res.on("error", err => {
|
|
52
|
-
console.error(err);
|
|
53
|
-
res.end();
|
|
54
|
-
});
|
|
55
|
-
if (this.dynamicCorsOrigin && req.headers.origin) {
|
|
56
|
-
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
|
|
57
|
-
res.setHeader("Vary", "Origin");
|
|
58
|
-
}
|
|
59
|
-
for (const [header, value] of this.headers) {
|
|
60
|
-
if (req.method === "OPTIONS" && !header.startsWith("access-control-")) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
res.setHeader(header, value);
|
|
64
|
-
}
|
|
65
|
-
if (req.method === "OPTIONS") {
|
|
66
|
-
res.writeHead(200);
|
|
67
|
-
res.end();
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const handleBody = (body) => {
|
|
71
|
-
this.handleRequestWithBody(req, res, body, hrStart).catch((e) => this.writeReply(res, null, { error: e }, hrStart));
|
|
72
|
-
};
|
|
73
|
-
// Google Cloud Functions add a rawBody property to the request object
|
|
74
|
-
if ((0, utils_1.has)(req, "rawBody") && req.rawBody instanceof Buffer) {
|
|
75
|
-
handleBody(req.rawBody);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
const body = [];
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
80
|
-
req.on("data", chunk => body.push(chunk));
|
|
81
|
-
req.on("end", () => {
|
|
82
|
-
handleBody(Buffer.concat(body));
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
this.extraContext = ((_a = maybeExtraContext[0]) !== null && _a !== void 0 ? _a : {});
|
|
87
|
-
this.httpServer = (0, http_1.createServer)(this.handleRequest.bind(this));
|
|
88
|
-
this.enableCors();
|
|
89
|
-
this.attachRestHandlers();
|
|
90
|
-
const targetTable = [
|
|
91
|
-
["/targets/android/client.kt", (ast) => (0, kotlin_generator_1.generateAndroidClientSource)(ast, true)],
|
|
92
|
-
["/targets/android/client_without_callbacks.kt", (ast) => (0, kotlin_generator_1.generateAndroidClientSource)(ast, false)],
|
|
93
|
-
["/targets/dotnet/api.cs", csharp_generator_1.generateCSharpServerSource],
|
|
94
|
-
["/targets/dotnet/api.fs", fsharp_generator_1.generateFSharpServerSource],
|
|
95
|
-
["/targets/flutter/client.dart", dart_generator_1.generateDartClientSource],
|
|
96
|
-
["/targets/ios/client.swift", (ast) => (0, swift_generator_1.generateSwiftClientSource)(ast, false)],
|
|
97
|
-
["/targets/ios/client-rx.swift", (ast) => (0, swift_generator_1.generateSwiftClientSource)(ast, true)],
|
|
98
|
-
["/targets/node/api.ts", typescript_generator_1.generateNodeServerSource],
|
|
99
|
-
["/targets/node/client.ts", typescript_generator_1.generateNodeClientSource],
|
|
100
|
-
["/targets/web/client.ts", typescript_generator_1.generateBrowserClientSource],
|
|
101
|
-
];
|
|
102
|
-
for (const [path, generateFn] of targetTable) {
|
|
103
|
-
this.addHttpHandler("GET", path, (_req, res) => {
|
|
104
|
-
if (!this.introspection) {
|
|
105
|
-
res.statusCode = 404;
|
|
106
|
-
res.end();
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
try {
|
|
110
|
-
res.setHeader("Content-Type", "application/octet-stream");
|
|
111
|
-
res.write(generateFn(this.apiConfig.ast));
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
console.error(e);
|
|
115
|
-
res.statusCode = 500;
|
|
116
|
-
res.write(`${e}`);
|
|
117
|
-
}
|
|
118
|
-
res.end();
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
this.addHttpHandler("GET", "/ast.json", (_req, res) => {
|
|
122
|
-
if (!this.introspection) {
|
|
123
|
-
res.statusCode = 404;
|
|
124
|
-
res.end();
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
res.setHeader("Content-Type", "application/json");
|
|
128
|
-
res.write(JSON.stringify(apiConfig.astJson));
|
|
129
|
-
res.end();
|
|
130
|
-
});
|
|
131
|
-
this.addHttpHandler("GET", /^\/playground.*/u, (req, res) => {
|
|
132
|
-
if (!this.introspection) {
|
|
133
|
-
res.statusCode = 404;
|
|
134
|
-
res.end();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
if (req.url) {
|
|
138
|
-
req.url = req.url.endsWith("/playground") ? req.url.replace(/\/playground/u, "/index.html") : req.url.replace(/\/playground/u, "");
|
|
139
|
-
}
|
|
140
|
-
(0, serve_handler_1.default)(req, res, {
|
|
141
|
-
cleanUrls: false,
|
|
142
|
-
directoryListing: false,
|
|
143
|
-
etag: true,
|
|
144
|
-
public: playground_1.PLAYGROUND_PUBLIC_PATH,
|
|
145
|
-
}).catch(e => {
|
|
146
|
-
console.error(e);
|
|
147
|
-
res.statusCode = 500;
|
|
148
|
-
res.write(`${e}`);
|
|
149
|
-
res.end();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
registerHealthCheck(healthCheck) {
|
|
154
|
-
this.healthChecks.push(healthCheck);
|
|
155
|
-
}
|
|
156
|
-
ignoreUrlPrefix(urlPrefix) {
|
|
157
|
-
this.ignoredUrlPrefix = urlPrefix;
|
|
158
|
-
}
|
|
159
|
-
async listen(port = 8000) {
|
|
160
|
-
return new Promise(resolve => {
|
|
161
|
-
this.httpServer.listen(port, () => {
|
|
162
|
-
const addr = this.httpServer.address();
|
|
163
|
-
let urlHost;
|
|
164
|
-
if (addr.address === "::") {
|
|
165
|
-
urlHost = `localhost:${addr.port}`;
|
|
166
|
-
}
|
|
167
|
-
else if (addr.family === "ipv6") {
|
|
168
|
-
urlHost = `[${addr.address}]:${addr.port}`;
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
urlHost = `${addr.address}:${addr.port}`;
|
|
172
|
-
}
|
|
173
|
-
if (addr.address === "::" || addr.address === "0.0.0.0") {
|
|
174
|
-
console.log(`\nListening on port ${addr.port}`);
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
console.log(`\nListening on port ${addr.port} (${addr.address})`);
|
|
178
|
-
}
|
|
179
|
-
if (this.introspection) {
|
|
180
|
-
console.log(`Playground: http://${urlHost}/playground`);
|
|
181
|
-
}
|
|
182
|
-
if (this.hasSwagger) {
|
|
183
|
-
console.log(`Swagger UI: http://${urlHost}/swagger`);
|
|
184
|
-
}
|
|
185
|
-
console.log("");
|
|
186
|
-
resolve();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
async close() {
|
|
191
|
-
return (0, util_1.promisify)(this.httpServer.close.bind(this.httpServer))();
|
|
192
|
-
}
|
|
193
|
-
enableCors() {
|
|
194
|
-
this.addHeader("Access-Control-Allow-Methods", "DELETE, HEAD, PUT, POST, PATCH, GET, OPTIONS");
|
|
195
|
-
this.addHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
196
|
-
this.addHeader("Access-Control-Max-Age", "86400");
|
|
197
|
-
}
|
|
198
|
-
addHeader(header, value) {
|
|
199
|
-
const cleanHeader = header.toLowerCase().trim();
|
|
200
|
-
const existing = this.headers.get(cleanHeader);
|
|
201
|
-
if (existing) {
|
|
202
|
-
if (!existing.includes(value)) {
|
|
203
|
-
this.headers.set(cleanHeader, `${existing}, ${value}`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
this.headers.set(cleanHeader, value);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
addHttpHandler(method, matcher, handler) {
|
|
211
|
-
this.handlers.push({ handler, matcher, method });
|
|
212
|
-
}
|
|
213
|
-
findBestHandler(path, req) {
|
|
214
|
-
const matchingHandlers = this.handlers
|
|
215
|
-
.filter(({ method }) => method === req.method)
|
|
216
|
-
.filter(({ matcher }) => {
|
|
217
|
-
var _a;
|
|
218
|
-
if (typeof matcher === "string") {
|
|
219
|
-
return matcher === path;
|
|
220
|
-
}
|
|
221
|
-
return ((_a = matcher.exec(path)) === null || _a === void 0 ? void 0 : _a[0]) === path;
|
|
222
|
-
})
|
|
223
|
-
.sort(({ matcher: first }, { matcher: second }) => {
|
|
224
|
-
// Prefer string matches instead of Regexp matches
|
|
225
|
-
if (typeof first === "string" && typeof second === "string") {
|
|
226
|
-
return 0;
|
|
227
|
-
}
|
|
228
|
-
else if (typeof first === "string") {
|
|
229
|
-
return -1;
|
|
230
|
-
}
|
|
231
|
-
else if (typeof second === "string") {
|
|
232
|
-
return 1;
|
|
233
|
-
}
|
|
234
|
-
const firstMatch = first.exec(path);
|
|
235
|
-
const secondMatch = second.exec(path);
|
|
236
|
-
if (!firstMatch) {
|
|
237
|
-
return -1;
|
|
238
|
-
}
|
|
239
|
-
if (!secondMatch) {
|
|
240
|
-
return 1;
|
|
241
|
-
}
|
|
242
|
-
// Compute how many characters were NOT part of a capture group
|
|
243
|
-
const firstLength = firstMatch[0].length - firstMatch.slice(1).reduce((acc, cur) => acc + cur.length, 0);
|
|
244
|
-
const secondLength = secondMatch[0].length - secondMatch.slice(1).reduce((acc, cur) => acc + cur.length, 0);
|
|
245
|
-
// Prefer the maximum number of non-captured characters
|
|
246
|
-
return secondLength - firstLength;
|
|
247
|
-
});
|
|
248
|
-
return matchingHandlers.length ? matchingHandlers[0] : null;
|
|
249
|
-
}
|
|
250
|
-
attachRestHandlers() {
|
|
251
|
-
function escapeRegExp(str) {
|
|
252
|
-
return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
253
|
-
}
|
|
254
|
-
for (const op of this.apiConfig.ast.operations) {
|
|
255
|
-
for (const ann of op.annotations) {
|
|
256
|
-
if (!(ann instanceof parser_1.RestAnnotation)) {
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
if (!this.hasSwagger) {
|
|
260
|
-
(0, swagger_1.setupSwagger)(this);
|
|
261
|
-
this.hasSwagger = true;
|
|
262
|
-
}
|
|
263
|
-
const pathFragments = ann.path.split(/\{\w+\}/u);
|
|
264
|
-
let pathRegex = "^";
|
|
265
|
-
for (let i = 0; i < pathFragments.length; ++i) {
|
|
266
|
-
if (i > 0) {
|
|
267
|
-
pathRegex += "([^/]+?)";
|
|
268
|
-
}
|
|
269
|
-
pathRegex += escapeRegExp(pathFragments[i]);
|
|
270
|
-
}
|
|
271
|
-
pathRegex += "/?$";
|
|
272
|
-
for (const header of ann.headers.keys()) {
|
|
273
|
-
this.addHeader("Access-Control-Allow-Headers", header.toLowerCase());
|
|
274
|
-
}
|
|
275
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
276
|
-
this.addHttpHandler(ann.method, new RegExp(pathRegex, "u"), async (req, res, body) => {
|
|
277
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
278
|
-
try {
|
|
279
|
-
const args = {};
|
|
280
|
-
const files = [];
|
|
281
|
-
const { pathname, query } = (0, url_1.parse)((_a = req.url) !== null && _a !== void 0 ? _a : "");
|
|
282
|
-
const match = pathname === null || pathname === void 0 ? void 0 : pathname.match(pathRegex);
|
|
283
|
-
if (!match) {
|
|
284
|
-
res.statusCode = 404;
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
const simpleArgs = new Map();
|
|
288
|
-
for (let i = 0; i < ann.pathVariables.length; ++i) {
|
|
289
|
-
const argName = ann.pathVariables[i];
|
|
290
|
-
const argValue = match[i + 1];
|
|
291
|
-
simpleArgs.set(argName, argValue);
|
|
292
|
-
}
|
|
293
|
-
const parsedQuery = query ? (0, querystring_1.parse)(query) : {};
|
|
294
|
-
for (const argName of ann.queryVariables) {
|
|
295
|
-
const argValue = (_b = parsedQuery[argName]) !== null && _b !== void 0 ? _b : null;
|
|
296
|
-
if (argValue === null) {
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
simpleArgs.set(argName, Array.isArray(argValue) ? argValue.join("") : argValue);
|
|
300
|
-
}
|
|
301
|
-
for (const [headerName, argName] of ann.headers) {
|
|
302
|
-
const argValue = (_c = req.headers[headerName.toLowerCase()]) !== null && _c !== void 0 ? _c : null;
|
|
303
|
-
if (argValue === null) {
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
simpleArgs.set(argName, Array.isArray(argValue) ? argValue.join("") : argValue);
|
|
307
|
-
}
|
|
308
|
-
if (!ann.bodyVariable && ((_d = req.headers["content-type"]) === null || _d === void 0 ? void 0 : _d.match(/^application\/x-www-form-urlencoded/iu))) {
|
|
309
|
-
const parsedBody = (0, querystring_1.parse)(body.toString());
|
|
310
|
-
for (const argName of ann.queryVariables) {
|
|
311
|
-
const argValue = (_e = parsedBody[argName]) !== null && _e !== void 0 ? _e : null;
|
|
312
|
-
if (argValue === null) {
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
simpleArgs.set(argName, Array.isArray(argValue) ? argValue.join("") : argValue);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
else if (!ann.bodyVariable && ((_f = req.headers["content-type"]) === null || _f === void 0 ? void 0 : _f.match(/^multipart\/form-data/iu))) {
|
|
319
|
-
const busboy = (0, busboy_1.default)({ headers: req.headers });
|
|
320
|
-
const filePromises = [];
|
|
321
|
-
busboy.on("field", (field, value) => {
|
|
322
|
-
if (ann.queryVariables.includes(field)) {
|
|
323
|
-
simpleArgs.set(field, `${value}`);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
busboy.on("file", (_field, stream, info) => {
|
|
327
|
-
const tempName = (0, crypto_1.randomBytes)(32).toString("hex");
|
|
328
|
-
const writeStream = (0, fs_1.createWriteStream)(tempName);
|
|
329
|
-
filePromises.push(new Promise((resolve, reject) => {
|
|
330
|
-
writeStream.on("error", reject);
|
|
331
|
-
writeStream.on("close", () => {
|
|
332
|
-
const contents = (0, fs_1.createReadStream)(tempName);
|
|
333
|
-
files.push({ contents, name: info.filename });
|
|
334
|
-
contents.on("open", () => {
|
|
335
|
-
(0, fs_1.unlink)(tempName, err => {
|
|
336
|
-
if (err) {
|
|
337
|
-
reject(err);
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
resolve();
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
writeStream.on("open", () => {
|
|
346
|
-
stream.pipe(writeStream);
|
|
347
|
-
});
|
|
348
|
-
}));
|
|
349
|
-
});
|
|
350
|
-
await new Promise((resolve, reject) => {
|
|
351
|
-
busboy.on("finish", resolve);
|
|
352
|
-
busboy.on("error", reject);
|
|
353
|
-
busboy.write(body);
|
|
354
|
-
});
|
|
355
|
-
await Promise.all(filePromises);
|
|
356
|
-
}
|
|
357
|
-
else if (ann.bodyVariable) {
|
|
358
|
-
const argName = ann.bodyVariable;
|
|
359
|
-
const arg = op.args.find(x => x.name === argName);
|
|
360
|
-
if (/application\/json/iu.test((_g = req.headers["content-type"]) !== null && _g !== void 0 ? _g : "")) {
|
|
361
|
-
args[argName] = JSON.parse(body.toString());
|
|
362
|
-
}
|
|
363
|
-
else if (arg) {
|
|
364
|
-
let { type } = arg;
|
|
365
|
-
let solved = false;
|
|
366
|
-
if (type instanceof parser_1.OptionalType) {
|
|
367
|
-
if (body.length === 0) {
|
|
368
|
-
args[argName] = null;
|
|
369
|
-
solved = true;
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
type = type.base;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
if (!solved) {
|
|
376
|
-
if (type instanceof parser_1.BoolPrimitiveType ||
|
|
377
|
-
type instanceof parser_1.IntPrimitiveType ||
|
|
378
|
-
type instanceof parser_1.UIntPrimitiveType ||
|
|
379
|
-
type instanceof parser_1.FloatPrimitiveType ||
|
|
380
|
-
type instanceof parser_1.StringPrimitiveType ||
|
|
381
|
-
type instanceof parser_1.DatePrimitiveType ||
|
|
382
|
-
type instanceof parser_1.DateTimePrimitiveType ||
|
|
383
|
-
type instanceof parser_1.MoneyPrimitiveType ||
|
|
384
|
-
type instanceof parser_1.DecimalPrimitiveType ||
|
|
385
|
-
type instanceof parser_1.BigIntPrimitiveType ||
|
|
386
|
-
type instanceof parser_1.CpfPrimitiveType ||
|
|
387
|
-
type instanceof parser_1.CnpjPrimitiveType ||
|
|
388
|
-
type instanceof parser_1.UuidPrimitiveType ||
|
|
389
|
-
type instanceof parser_1.HexPrimitiveType ||
|
|
390
|
-
type instanceof parser_1.Base64PrimitiveType) {
|
|
391
|
-
simpleArgs.set(argName, body.toString());
|
|
392
|
-
}
|
|
393
|
-
else if (type instanceof parser_1.BytesPrimitiveType) {
|
|
394
|
-
args[argName] = body.toString("base64");
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
args[argName] = JSON.parse(body.toString());
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
for (const [argName, argValue] of simpleArgs) {
|
|
403
|
-
const arg = op.args.find(x => x.name === argName);
|
|
404
|
-
if (!arg) {
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
let { type } = arg;
|
|
408
|
-
if (type instanceof parser_1.OptionalType) {
|
|
409
|
-
if (argValue === null) {
|
|
410
|
-
args[argName] = null;
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
type = type.base;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
else if (argValue === null) {
|
|
418
|
-
args[argName] = argValue;
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
if (type instanceof parser_1.BoolPrimitiveType) {
|
|
422
|
-
if (argValue === "true") {
|
|
423
|
-
args[argName] = true;
|
|
424
|
-
}
|
|
425
|
-
else if (argValue === "false") {
|
|
426
|
-
args[argName] = false;
|
|
427
|
-
}
|
|
428
|
-
else {
|
|
429
|
-
args[argName] = argValue;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
else if (type instanceof parser_1.UIntPrimitiveType || type instanceof parser_1.IntPrimitiveType || type instanceof parser_1.MoneyPrimitiveType) {
|
|
433
|
-
args[argName] = parseInt(argValue, 10);
|
|
434
|
-
}
|
|
435
|
-
else if (type instanceof parser_1.FloatPrimitiveType) {
|
|
436
|
-
args[argName] = parseFloat(argValue);
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
args[argName] = argValue;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
const ip = (0, request_ip_1.getClientIp)(req);
|
|
443
|
-
if (!ip) {
|
|
444
|
-
throw new Error("Couldn't determine client IP");
|
|
445
|
-
}
|
|
446
|
-
const request = {
|
|
447
|
-
args,
|
|
448
|
-
deviceInfo: {
|
|
449
|
-
fingerprint: null,
|
|
450
|
-
id: (0, crypto_1.randomBytes)(16).toString("hex"),
|
|
451
|
-
language: null,
|
|
452
|
-
platform: null,
|
|
453
|
-
timezone: null,
|
|
454
|
-
type: "rest",
|
|
455
|
-
version: null,
|
|
456
|
-
},
|
|
457
|
-
extra: {},
|
|
458
|
-
files,
|
|
459
|
-
headers: req.headers,
|
|
460
|
-
id: (0, crypto_1.randomBytes)(16).toString("hex"),
|
|
461
|
-
ip,
|
|
462
|
-
name: op.name,
|
|
463
|
-
version: 3,
|
|
464
|
-
};
|
|
465
|
-
await this.executeRequest(request, (ctx, reply) => {
|
|
466
|
-
try {
|
|
467
|
-
if (ctx) {
|
|
468
|
-
for (const [headerKey, headerValue] of ctx.response.headers.entries()) {
|
|
469
|
-
res.setHeader(headerKey, headerValue);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
if (ctx === null || ctx === void 0 ? void 0 : ctx.response.statusCode) {
|
|
473
|
-
res.statusCode = ctx.response.statusCode;
|
|
474
|
-
}
|
|
475
|
-
if (reply.error) {
|
|
476
|
-
const error = this.makeResponseError(reply.error);
|
|
477
|
-
if (!(ctx === null || ctx === void 0 ? void 0 : ctx.response.statusCode)) {
|
|
478
|
-
const errorNode = this.apiConfig.ast.errors.find(node => node.name === error.type);
|
|
479
|
-
const statusAnnotation = errorNode === null || errorNode === void 0 ? void 0 : errorNode.annotations.find(x => x instanceof parser_1.StatusCodeAnnotation);
|
|
480
|
-
res.statusCode = statusAnnotation ? statusAnnotation.statusCode : error.type === "Fatal" ? 500 : 400;
|
|
481
|
-
}
|
|
482
|
-
res.setHeader("content-type", "application/json");
|
|
483
|
-
res.write(JSON.stringify(error));
|
|
484
|
-
res.end();
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
if (req.headers.accept === "application/json") {
|
|
488
|
-
res.setHeader("content-type", "application/json");
|
|
489
|
-
res.write(JSON.stringify(reply.result));
|
|
490
|
-
res.end();
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
let type = op.returnType;
|
|
494
|
-
if (type instanceof parser_1.OptionalType) {
|
|
495
|
-
if (reply.result === null) {
|
|
496
|
-
if (!(ctx === null || ctx === void 0 ? void 0 : ctx.response.statusCode)) {
|
|
497
|
-
res.statusCode = ann.method === "GET" ? 404 : 204;
|
|
498
|
-
}
|
|
499
|
-
res.end();
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
type = type.base;
|
|
503
|
-
}
|
|
504
|
-
if (type instanceof parser_1.BoolPrimitiveType ||
|
|
505
|
-
type instanceof parser_1.IntPrimitiveType ||
|
|
506
|
-
type instanceof parser_1.UIntPrimitiveType ||
|
|
507
|
-
type instanceof parser_1.FloatPrimitiveType ||
|
|
508
|
-
type instanceof parser_1.StringPrimitiveType ||
|
|
509
|
-
type instanceof parser_1.DatePrimitiveType ||
|
|
510
|
-
type instanceof parser_1.DateTimePrimitiveType ||
|
|
511
|
-
type instanceof parser_1.MoneyPrimitiveType ||
|
|
512
|
-
type instanceof parser_1.DecimalPrimitiveType ||
|
|
513
|
-
type instanceof parser_1.BigIntPrimitiveType ||
|
|
514
|
-
type instanceof parser_1.CpfPrimitiveType ||
|
|
515
|
-
type instanceof parser_1.CnpjPrimitiveType ||
|
|
516
|
-
type instanceof parser_1.UuidPrimitiveType ||
|
|
517
|
-
type instanceof parser_1.HexPrimitiveType ||
|
|
518
|
-
type instanceof parser_1.Base64PrimitiveType) {
|
|
519
|
-
res.setHeader("content-type", "text/plain");
|
|
520
|
-
res.write(`${reply.result}`);
|
|
521
|
-
res.end();
|
|
522
|
-
}
|
|
523
|
-
else if (type instanceof parser_1.HtmlPrimitiveType) {
|
|
524
|
-
res.setHeader("content-type", "text/html");
|
|
525
|
-
res.write(`${reply.result}`);
|
|
526
|
-
res.end();
|
|
527
|
-
}
|
|
528
|
-
else if (type instanceof parser_1.XmlPrimitiveType) {
|
|
529
|
-
res.setHeader("content-type", "text/xml");
|
|
530
|
-
res.write(`${reply.result}`);
|
|
531
|
-
res.end();
|
|
532
|
-
}
|
|
533
|
-
else if (type instanceof parser_1.BytesPrimitiveType) {
|
|
534
|
-
const buffer = Buffer.from(reply.result, "base64");
|
|
535
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
536
|
-
file_type_1.default.fromBuffer(buffer)
|
|
537
|
-
.then(fileType => {
|
|
538
|
-
var _a;
|
|
539
|
-
res.setHeader("content-type", (_a = fileType === null || fileType === void 0 ? void 0 : fileType.mime) !== null && _a !== void 0 ? _a : "application/octet-stream");
|
|
540
|
-
})
|
|
541
|
-
.catch(err => {
|
|
542
|
-
console.error(err);
|
|
543
|
-
res.setHeader("content-type", "application/octet-stream");
|
|
544
|
-
})
|
|
545
|
-
.then(() => {
|
|
546
|
-
res.write(buffer);
|
|
547
|
-
res.end();
|
|
548
|
-
})
|
|
549
|
-
.catch(() => { });
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
res.setHeader("content-type", "application/json");
|
|
553
|
-
res.write(JSON.stringify(reply.result));
|
|
554
|
-
res.end();
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
catch (error) {
|
|
559
|
-
console.error(error);
|
|
560
|
-
if (!res.headersSent) {
|
|
561
|
-
res.statusCode = 500;
|
|
562
|
-
}
|
|
563
|
-
res.end();
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
catch (error) {
|
|
568
|
-
console.error(error);
|
|
569
|
-
if (!res.headersSent) {
|
|
570
|
-
res.statusCode = 500;
|
|
571
|
-
}
|
|
572
|
-
res.end();
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
async handleRequestWithBody(req, res, body, hrStart) {
|
|
579
|
-
var _a, _b;
|
|
580
|
-
const { pathname, query } = (0, url_1.parse)((_a = req.url) !== null && _a !== void 0 ? _a : "");
|
|
581
|
-
let path = pathname !== null && pathname !== void 0 ? pathname : "";
|
|
582
|
-
if (path.startsWith(this.ignoredUrlPrefix)) {
|
|
583
|
-
path = path.slice(this.ignoredUrlPrefix.length);
|
|
584
|
-
}
|
|
585
|
-
if (!((_b = req.headers["content-type"]) === null || _b === void 0 ? void 0 : _b.match(/application\/sdkgen/iu))) {
|
|
586
|
-
const externalHandler = this.findBestHandler(path, req);
|
|
587
|
-
if (externalHandler) {
|
|
588
|
-
this.log(`HTTP ${req.method} ${path}${query ? `?${query}` : ""}`);
|
|
589
|
-
externalHandler.handler(req, res, body);
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
594
|
-
if (req.method === "HEAD") {
|
|
595
|
-
res.writeHead(200);
|
|
596
|
-
res.end();
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
if (req.method === "GET") {
|
|
600
|
-
if (path !== "/") {
|
|
601
|
-
res.writeHead(404);
|
|
602
|
-
res.end();
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
let ok = true;
|
|
606
|
-
try {
|
|
607
|
-
for (const healthCheck of this.healthChecks) {
|
|
608
|
-
if (!ok) {
|
|
609
|
-
break;
|
|
610
|
-
}
|
|
611
|
-
ok = await healthCheck();
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
catch (e) {
|
|
615
|
-
ok = false;
|
|
616
|
-
}
|
|
617
|
-
res.statusCode = ok ? 200 : 500;
|
|
618
|
-
res.write(JSON.stringify({ ok }));
|
|
619
|
-
res.end();
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
if (req.method !== "POST") {
|
|
623
|
-
res.writeHead(400);
|
|
624
|
-
res.end();
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
const clientIp = (0, request_ip_1.getClientIp)(req);
|
|
628
|
-
if (!clientIp) {
|
|
629
|
-
this.writeReply(res, null, {
|
|
630
|
-
error: new error_1.Fatal("Couldn't determine client IP"),
|
|
631
|
-
}, hrStart);
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
const request = this.parseRequest(req, body.toString(), clientIp);
|
|
635
|
-
if (!request) {
|
|
636
|
-
this.writeReply(res, null, {
|
|
637
|
-
error: new error_1.Fatal("Couldn't parse request"),
|
|
638
|
-
}, hrStart);
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
await this.executeRequest(request, (ctx, reply) => this.writeReply(res, ctx, reply, hrStart));
|
|
642
|
-
}
|
|
643
|
-
async executeRequest(request, writeReply) {
|
|
644
|
-
const ctx = Object.assign(Object.assign({}, this.extraContext), { request, response: {
|
|
645
|
-
headers: new Map(),
|
|
646
|
-
} });
|
|
647
|
-
writeReply(ctx, await (0, execute_1.executeRequest)(ctx, this.apiConfig));
|
|
648
|
-
}
|
|
649
|
-
parseRequest(req, body, ip) {
|
|
650
|
-
switch (this.identifyRequestVersion(req, body)) {
|
|
651
|
-
case 1:
|
|
652
|
-
return this.parseRequestV1(req, body, ip);
|
|
653
|
-
case 2:
|
|
654
|
-
return this.parseRequestV2(req, body, ip);
|
|
655
|
-
case 3:
|
|
656
|
-
return this.parseRequestV3(req, body, ip);
|
|
657
|
-
default:
|
|
658
|
-
throw new Error("Failed to understand request");
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
identifyRequestVersion(_req, body) {
|
|
662
|
-
const parsed = JSON.parse(body);
|
|
663
|
-
if (typeof parsed === "object" && parsed && (0, utils_1.has)(parsed, "version") && typeof parsed.version === "number") {
|
|
664
|
-
return parsed.version;
|
|
665
|
-
}
|
|
666
|
-
else if (typeof parsed === "object" && parsed && (0, utils_1.has)(parsed, "requestId")) {
|
|
667
|
-
return 2;
|
|
668
|
-
}
|
|
669
|
-
else if (typeof parsed === "object" && parsed && (0, utils_1.has)(parsed, "device")) {
|
|
670
|
-
return 1;
|
|
671
|
-
}
|
|
672
|
-
return 3;
|
|
673
|
-
}
|
|
674
|
-
// Old Sdkgen format
|
|
675
|
-
parseRequestV1(req, body, ip) {
|
|
676
|
-
var _a, _b;
|
|
677
|
-
const parsed = (0, encode_decode_1.decode)({
|
|
678
|
-
Request: {
|
|
679
|
-
args: "json",
|
|
680
|
-
device: "RequestDevice",
|
|
681
|
-
id: "string",
|
|
682
|
-
name: "string",
|
|
683
|
-
},
|
|
684
|
-
RequestDevice: {
|
|
685
|
-
fingerprint: "string?",
|
|
686
|
-
id: "string?",
|
|
687
|
-
language: "string?",
|
|
688
|
-
platform: "json?",
|
|
689
|
-
timezone: "string?",
|
|
690
|
-
type: "string?",
|
|
691
|
-
version: "string?",
|
|
692
|
-
},
|
|
693
|
-
}, "root", "Request", JSON.parse(body));
|
|
694
|
-
const deviceId = (_a = parsed.device.id) !== null && _a !== void 0 ? _a : (0, crypto_1.randomBytes)(20).toString("hex");
|
|
695
|
-
if (!parsed.args || Array.isArray(parsed.args) || typeof parsed.args !== "object") {
|
|
696
|
-
throw new Error("Expected 'args' to be an object");
|
|
697
|
-
}
|
|
698
|
-
return {
|
|
699
|
-
args: parsed.args,
|
|
700
|
-
deviceInfo: {
|
|
701
|
-
fingerprint: parsed.device.fingerprint,
|
|
702
|
-
id: deviceId,
|
|
703
|
-
language: parsed.device.language,
|
|
704
|
-
platform: parsed.device.platform,
|
|
705
|
-
timezone: parsed.device.timezone,
|
|
706
|
-
type: (_b = parsed.device.type) !== null && _b !== void 0 ? _b : (typeof parsed.device.platform === "string" ? parsed.device.platform : ""),
|
|
707
|
-
version: parsed.device.version,
|
|
708
|
-
},
|
|
709
|
-
extra: {},
|
|
710
|
-
files: [],
|
|
711
|
-
headers: req.headers,
|
|
712
|
-
id: `${deviceId}-${parsed.id}`,
|
|
713
|
-
ip,
|
|
714
|
-
name: parsed.name,
|
|
715
|
-
version: 1,
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
// Maxima sdkgen format
|
|
719
|
-
parseRequestV2(req, body, ip) {
|
|
720
|
-
var _a, _b;
|
|
721
|
-
const parsed = (0, encode_decode_1.decode)({
|
|
722
|
-
Request: {
|
|
723
|
-
args: "json",
|
|
724
|
-
deviceFingerprint: "string?",
|
|
725
|
-
deviceId: "string",
|
|
726
|
-
info: "RequestInfo",
|
|
727
|
-
name: "string",
|
|
728
|
-
partnerId: "string?",
|
|
729
|
-
requestId: "string?",
|
|
730
|
-
sessionId: "string?",
|
|
731
|
-
},
|
|
732
|
-
RequestInfo: {
|
|
733
|
-
browserUserAgent: "string?",
|
|
734
|
-
language: "string",
|
|
735
|
-
type: "string",
|
|
736
|
-
},
|
|
737
|
-
}, "root", "Request", JSON.parse(body));
|
|
738
|
-
if (!parsed.args || Array.isArray(parsed.args) || typeof parsed.args !== "object") {
|
|
739
|
-
throw new Error("Expected 'args' to be an object");
|
|
740
|
-
}
|
|
741
|
-
return {
|
|
742
|
-
args: parsed.args,
|
|
743
|
-
deviceInfo: {
|
|
744
|
-
fingerprint: parsed.deviceFingerprint,
|
|
745
|
-
id: parsed.deviceId,
|
|
746
|
-
language: parsed.info.language,
|
|
747
|
-
platform: {
|
|
748
|
-
browserUserAgent: (_a = parsed.info.browserUserAgent) !== null && _a !== void 0 ? _a : null,
|
|
749
|
-
},
|
|
750
|
-
timezone: null,
|
|
751
|
-
type: parsed.info.type,
|
|
752
|
-
version: "",
|
|
753
|
-
},
|
|
754
|
-
extra: {
|
|
755
|
-
partnerId: parsed.partnerId,
|
|
756
|
-
sessionId: parsed.sessionId,
|
|
757
|
-
},
|
|
758
|
-
files: [],
|
|
759
|
-
headers: req.headers,
|
|
760
|
-
id: `${parsed.deviceId}-${(_b = parsed.requestId) !== null && _b !== void 0 ? _b : (0, crypto_1.randomBytes)(16).toString("hex")}`,
|
|
761
|
-
ip,
|
|
762
|
-
name: parsed.name,
|
|
763
|
-
version: 2,
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
// New sdkgen format
|
|
767
|
-
parseRequestV3(req, body, ip) {
|
|
768
|
-
var _a, _b, _c, _d;
|
|
769
|
-
const parsed = (0, encode_decode_1.decode)({
|
|
770
|
-
DeviceInfo: {
|
|
771
|
-
fingerprint: "string?",
|
|
772
|
-
id: "string?",
|
|
773
|
-
language: "string?",
|
|
774
|
-
platform: "json?",
|
|
775
|
-
timezone: "string?",
|
|
776
|
-
type: "string?",
|
|
777
|
-
version: "string?",
|
|
778
|
-
},
|
|
779
|
-
Request: {
|
|
780
|
-
args: "json",
|
|
781
|
-
deviceInfo: "DeviceInfo?",
|
|
782
|
-
extra: "json?",
|
|
783
|
-
name: "string",
|
|
784
|
-
requestId: "string?",
|
|
785
|
-
},
|
|
786
|
-
}, "root", "Request", JSON.parse(body));
|
|
787
|
-
const deviceInfo = (_a = parsed.deviceInfo) !== null && _a !== void 0 ? _a : {
|
|
788
|
-
fingerprint: null,
|
|
789
|
-
id: null,
|
|
790
|
-
language: null,
|
|
791
|
-
platform: null,
|
|
792
|
-
timezone: null,
|
|
793
|
-
type: null,
|
|
794
|
-
version: null,
|
|
795
|
-
};
|
|
796
|
-
const deviceId = (_b = deviceInfo.id) !== null && _b !== void 0 ? _b : (0, crypto_1.randomBytes)(16).toString("hex");
|
|
797
|
-
if (!parsed.args || Array.isArray(parsed.args) || typeof parsed.args !== "object") {
|
|
798
|
-
throw new Error("Expected 'args' to be an object");
|
|
799
|
-
}
|
|
800
|
-
return {
|
|
801
|
-
args: parsed.args,
|
|
802
|
-
deviceInfo: {
|
|
803
|
-
fingerprint: deviceInfo.fingerprint,
|
|
804
|
-
id: deviceId,
|
|
805
|
-
language: deviceInfo.language,
|
|
806
|
-
platform: typeof deviceInfo.platform === "object" ? Object.assign({}, deviceInfo.platform) : {},
|
|
807
|
-
timezone: deviceInfo.timezone,
|
|
808
|
-
type: (_c = deviceInfo.type) !== null && _c !== void 0 ? _c : "api",
|
|
809
|
-
version: deviceInfo.version,
|
|
810
|
-
},
|
|
811
|
-
extra: typeof parsed.extra === "object" ? Object.assign({}, parsed.extra) : {},
|
|
812
|
-
files: [],
|
|
813
|
-
headers: req.headers,
|
|
814
|
-
id: `${deviceId}-${(_d = parsed.requestId) !== null && _d !== void 0 ? _d : (0, crypto_1.randomBytes)(16).toString("hex")}`,
|
|
815
|
-
ip,
|
|
816
|
-
name: parsed.name,
|
|
817
|
-
version: 3,
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
makeResponseError(err) {
|
|
821
|
-
let type = "Fatal";
|
|
822
|
-
if (typeof err === "object" && err !== null && (0, utils_1.has)(err, "type") && typeof err.type === "string") {
|
|
823
|
-
({ type } = err);
|
|
824
|
-
}
|
|
825
|
-
let message;
|
|
826
|
-
if (typeof err === "object" && err !== null && (0, utils_1.has)(err, "message") && typeof err.message === "string") {
|
|
827
|
-
({ message } = err);
|
|
828
|
-
}
|
|
829
|
-
else if (err instanceof Error) {
|
|
830
|
-
message = err.toString();
|
|
831
|
-
}
|
|
832
|
-
else if (typeof err === "object") {
|
|
833
|
-
message = JSON.stringify(err);
|
|
834
|
-
}
|
|
835
|
-
else {
|
|
836
|
-
message = `${err}`;
|
|
837
|
-
}
|
|
838
|
-
let data;
|
|
839
|
-
if (typeof err === "object" && err !== null && (0, utils_1.has)(err, "data")) {
|
|
840
|
-
({ data } = err);
|
|
841
|
-
}
|
|
842
|
-
const error = this.apiConfig.ast.errors.find(x => x.name === type);
|
|
843
|
-
if (error) {
|
|
844
|
-
if (!(error.dataType instanceof parser_1.VoidPrimitiveType)) {
|
|
845
|
-
try {
|
|
846
|
-
data = (0, encode_decode_1.encode)(this.apiConfig.astJson.typeTable, `error.${type}`, error.dataType.name, data);
|
|
847
|
-
}
|
|
848
|
-
catch (encodeError) {
|
|
849
|
-
message = `Failed to encode error ${type} because: ${encodeError}. Original message: ${message}`;
|
|
850
|
-
type = "Fatal";
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
else {
|
|
855
|
-
type = "Fatal";
|
|
856
|
-
}
|
|
857
|
-
return { data, message, type };
|
|
858
|
-
}
|
|
859
|
-
writeReply(res, ctx, reply, hrStart) {
|
|
860
|
-
var _a, _b;
|
|
861
|
-
if (!ctx) {
|
|
862
|
-
res.statusCode = 500;
|
|
863
|
-
res.write(JSON.stringify({
|
|
864
|
-
error: this.makeResponseError((_a = reply.error) !== null && _a !== void 0 ? _a : new error_1.Fatal("Response without context")),
|
|
865
|
-
}));
|
|
866
|
-
res.end();
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
const deltaTime = process.hrtime(hrStart);
|
|
870
|
-
const duration = deltaTime[0] + deltaTime[1] * 1e-9;
|
|
871
|
-
if (reply.error) {
|
|
872
|
-
console.error(reply.error);
|
|
873
|
-
}
|
|
874
|
-
this.log(`${ctx.request.id} [${duration.toFixed(6)}s] ${ctx.request.name}() -> ${reply.error ? this.makeResponseError(reply.error).type : "OK"}`);
|
|
875
|
-
if (ctx.response.statusCode) {
|
|
876
|
-
res.statusCode = ctx.response.statusCode;
|
|
877
|
-
}
|
|
878
|
-
for (const [headerKey, headerValue] of ctx.response.headers.entries()) {
|
|
879
|
-
res.setHeader(headerKey, headerValue);
|
|
880
|
-
}
|
|
881
|
-
switch (ctx.request.version) {
|
|
882
|
-
case 1: {
|
|
883
|
-
const response = {
|
|
884
|
-
deviceId: ctx.request.deviceInfo.id,
|
|
885
|
-
duration,
|
|
886
|
-
error: reply.error ? this.makeResponseError(reply.error) : null,
|
|
887
|
-
host: (0, os_1.hostname)(),
|
|
888
|
-
id: ctx.request.id,
|
|
889
|
-
ok: !reply.error,
|
|
890
|
-
result: reply.error ? null : reply.result,
|
|
891
|
-
};
|
|
892
|
-
if (response.error && !ctx.response.statusCode) {
|
|
893
|
-
res.statusCode = this.makeResponseError(response.error).type === "Fatal" ? 500 : 400;
|
|
894
|
-
}
|
|
895
|
-
res.write(JSON.stringify(response));
|
|
896
|
-
res.end();
|
|
897
|
-
break;
|
|
898
|
-
}
|
|
899
|
-
case 2: {
|
|
900
|
-
const response = {
|
|
901
|
-
deviceId: ctx.request.deviceInfo.id,
|
|
902
|
-
error: reply.error ? this.makeResponseError(reply.error) : null,
|
|
903
|
-
ok: !reply.error,
|
|
904
|
-
requestId: ctx.request.id,
|
|
905
|
-
result: reply.error ? null : reply.result,
|
|
906
|
-
sessionId: ctx.request.extra.sessionId,
|
|
907
|
-
};
|
|
908
|
-
if (response.error && !ctx.response.statusCode) {
|
|
909
|
-
res.statusCode = this.makeResponseError(response.error).type === "Fatal" ? 500 : 400;
|
|
910
|
-
}
|
|
911
|
-
res.write(JSON.stringify(response));
|
|
912
|
-
res.end();
|
|
913
|
-
break;
|
|
914
|
-
}
|
|
915
|
-
case 3: {
|
|
916
|
-
const response = {
|
|
917
|
-
duration,
|
|
918
|
-
error: reply.error ? this.makeResponseError(reply.error) : null,
|
|
919
|
-
host: (0, os_1.hostname)(),
|
|
920
|
-
result: reply.error ? null : reply.result,
|
|
921
|
-
};
|
|
922
|
-
if (response.error && !ctx.response.statusCode) {
|
|
923
|
-
res.statusCode = this.makeResponseError(response.error).type === "Fatal" ? 500 : 400;
|
|
924
|
-
}
|
|
925
|
-
res.setHeader("x-request-id", ctx.request.id);
|
|
926
|
-
res.write(JSON.stringify(response));
|
|
927
|
-
res.end();
|
|
928
|
-
break;
|
|
929
|
-
}
|
|
930
|
-
default: {
|
|
931
|
-
res.statusCode = 500;
|
|
932
|
-
res.write(JSON.stringify({
|
|
933
|
-
error: this.makeResponseError((_b = reply.error) !== null && _b !== void 0 ? _b : new error_1.Fatal("Unknown request version")),
|
|
934
|
-
}));
|
|
935
|
-
res.end();
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
exports.SdkgenHttpServer = SdkgenHttpServer;
|