@opra/core 1.0.0-alpha.22 → 1.0.0-alpha.24
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/cjs/constants.js +1 -2
- package/cjs/execution-context.js +1 -0
- package/cjs/http/express-adapter.js +15 -18
- package/cjs/http/http-adapter.js +2 -5
- package/cjs/http/http-context.js +14 -10
- package/cjs/http/{impl/http-handler.js → http-handler.js} +80 -93
- package/cjs/http/impl/multipart-reader.js +130 -37
- package/cjs/index.js +1 -1
- package/cjs/platform-adapter.js +0 -3
- package/esm/constants.js +0 -1
- package/esm/execution-context.js +1 -0
- package/esm/http/express-adapter.js +15 -18
- package/esm/http/http-adapter.js +2 -5
- package/esm/http/http-context.js +14 -10
- package/esm/http/{impl/http-handler.js → http-handler.js} +69 -82
- package/esm/http/impl/multipart-reader.js +132 -39
- package/esm/index.js +1 -1
- package/esm/platform-adapter.js +0 -3
- package/package.json +5 -5
- package/types/constants.d.ts +0 -1
- package/types/execution-context.d.ts +2 -1
- package/types/http/http-adapter.d.ts +23 -5
- package/types/http/{impl/http-handler.d.ts → http-handler.d.ts} +8 -8
- package/types/http/impl/multipart-reader.d.ts +38 -19
- package/types/index.d.ts +1 -1
- package/types/platform-adapter.d.ts +0 -4
- package/cjs/helpers/logger.js +0 -35
- package/esm/helpers/logger.js +0 -31
- package/i18n/i18n/en/error.json +0 -21
- package/types/helpers/logger.d.ts +0 -14
package/cjs/constants.js
CHANGED
package/cjs/execution-context.js
CHANGED
|
@@ -8,6 +8,7 @@ const strict_typed_events_1 = require("strict-typed-events");
|
|
|
8
8
|
class ExecutionContext extends strict_typed_events_1.AsyncEventEmitter {
|
|
9
9
|
constructor(init) {
|
|
10
10
|
super();
|
|
11
|
+
this.errors = [];
|
|
11
12
|
this.document = init.document;
|
|
12
13
|
this.protocol = init.protocol;
|
|
13
14
|
this.platform = init.platform;
|
|
@@ -5,11 +5,11 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const common_1 = require("@opra/common");
|
|
6
6
|
const express_1 = require("express");
|
|
7
7
|
const nodePath = tslib_1.__importStar(require("path"));
|
|
8
|
-
const constants_js_1 = require("../constants.js");
|
|
9
8
|
const http_adapter_js_1 = require("./http-adapter.js");
|
|
10
9
|
const http_context_js_1 = require("./http-context.js");
|
|
11
10
|
const http_incoming_interface_js_1 = require("./interfaces/http-incoming.interface.js");
|
|
12
11
|
const http_outgoing_interface_js_1 = require("./interfaces/http-outgoing.interface.js");
|
|
12
|
+
const wrap_exception_1 = require("./utils/wrap-exception");
|
|
13
13
|
class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
14
14
|
constructor(app, document, options) {
|
|
15
15
|
super(document, options);
|
|
@@ -40,7 +40,8 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
40
40
|
await resource.onShutdown.call(instance, resource);
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
|
-
this.
|
|
43
|
+
if (this.listenerCount('error'))
|
|
44
|
+
this.emit('error', (0, wrap_exception_1.wrapException)(e));
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -80,7 +81,7 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
80
81
|
/** Add an endpoint that returns document schema */
|
|
81
82
|
router.get('/\\$schema', (_req, _res, next) => {
|
|
82
83
|
const context = createContext(_req, _res);
|
|
83
|
-
this
|
|
84
|
+
this.handler.sendDocumentSchema(context).catch(next);
|
|
84
85
|
});
|
|
85
86
|
/** Add operation endpoints */
|
|
86
87
|
if (this.api.controllers.size) {
|
|
@@ -100,13 +101,13 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
100
101
|
operation,
|
|
101
102
|
operationHandler,
|
|
102
103
|
});
|
|
103
|
-
this
|
|
104
|
+
this.handler
|
|
104
105
|
.handleRequest(context)
|
|
105
106
|
.then(() => {
|
|
106
107
|
if (!_res.headersSent)
|
|
107
108
|
_next();
|
|
108
109
|
})
|
|
109
|
-
.catch((e) => this.
|
|
110
|
+
.catch((e) => this.emit('error', e));
|
|
110
111
|
});
|
|
111
112
|
}
|
|
112
113
|
if (controller.controllers.size) {
|
|
@@ -119,19 +120,15 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
119
120
|
}
|
|
120
121
|
/** Add an endpoint that returns 404 error at last */
|
|
121
122
|
router.use('*', (_req, _res, next) => {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
},
|
|
132
|
-
}),
|
|
133
|
-
])
|
|
134
|
-
.catch(next);
|
|
123
|
+
const context = createContext(_req, _res);
|
|
124
|
+
context.errors.push(new common_1.NotFoundError({
|
|
125
|
+
message: `No endpoint found at [${_req.method}]${_req.baseUrl}`,
|
|
126
|
+
details: {
|
|
127
|
+
path: _req.baseUrl,
|
|
128
|
+
method: _req.method,
|
|
129
|
+
},
|
|
130
|
+
}));
|
|
131
|
+
this.handler.sendResponse(context).catch(next);
|
|
135
132
|
});
|
|
136
133
|
}
|
|
137
134
|
_createControllers(controller) {
|
package/cjs/http/http-adapter.js
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HttpAdapter = void 0;
|
|
4
4
|
const common_1 = require("@opra/common");
|
|
5
|
-
const constants_js_1 = require("../constants.js");
|
|
6
5
|
const platform_adapter_js_1 = require("../platform-adapter.js");
|
|
7
|
-
const http_handler_js_1 = require("./
|
|
6
|
+
const http_handler_js_1 = require("./http-handler.js");
|
|
8
7
|
/**
|
|
9
8
|
*
|
|
10
9
|
* @class HttpAdapter
|
|
@@ -15,10 +14,8 @@ class HttpAdapter extends platform_adapter_js_1.PlatformAdapter {
|
|
|
15
14
|
this.protocol = 'http';
|
|
16
15
|
if (!(document.api instanceof common_1.HttpApi))
|
|
17
16
|
throw new TypeError(`The document does not expose an HTTP Api`);
|
|
18
|
-
this
|
|
17
|
+
this.handler = new http_handler_js_1.HttpHandler(this);
|
|
19
18
|
this.interceptors = [...(options?.interceptors || [])];
|
|
20
|
-
if (options?.onRequest)
|
|
21
|
-
this.on('request', options.onRequest);
|
|
22
19
|
}
|
|
23
20
|
get api() {
|
|
24
21
|
return this.document.api;
|
package/cjs/http/http-context.js
CHANGED
|
@@ -29,6 +29,10 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
29
29
|
this.pathParams = init.pathParams || {};
|
|
30
30
|
this.queryParams = init.queryParams || {};
|
|
31
31
|
this._body = init.body;
|
|
32
|
+
this.on('finish', () => {
|
|
33
|
+
if (this._multipartReader)
|
|
34
|
+
this._multipartReader.purge().catch(() => undefined);
|
|
35
|
+
});
|
|
32
36
|
}
|
|
33
37
|
get isMultipart() {
|
|
34
38
|
return !!this.request.is('multipart');
|
|
@@ -38,21 +42,21 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
38
42
|
throw new common_1.InternalServerError('Request content is not a multipart content');
|
|
39
43
|
if (this._multipartReader)
|
|
40
44
|
return this._multipartReader;
|
|
41
|
-
const {
|
|
45
|
+
const { mediaType } = this;
|
|
42
46
|
if (mediaType?.contentType) {
|
|
43
47
|
const arr = Array.isArray(mediaType.contentType) ? mediaType.contentType : [mediaType.contentType];
|
|
44
48
|
const contentType = arr.find(ct => type_is_1.default.is(ct, ['multipart']));
|
|
45
49
|
if (!contentType)
|
|
46
50
|
throw new common_1.NotAcceptableError('This endpoint does not accept multipart requests');
|
|
47
51
|
}
|
|
48
|
-
const reader = new multipart_reader_js_1.MultipartReader(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
52
|
+
const reader = new multipart_reader_js_1.MultipartReader(this, {
|
|
53
|
+
limits: {
|
|
54
|
+
fields: mediaType?.maxFields,
|
|
55
|
+
fieldSize: mediaType?.maxFieldsSize,
|
|
56
|
+
files: mediaType?.maxFiles,
|
|
57
|
+
fileSize: mediaType?.maxFileSize,
|
|
58
|
+
},
|
|
59
|
+
}, mediaType);
|
|
56
60
|
this._multipartReader = reader;
|
|
57
61
|
return reader;
|
|
58
62
|
}
|
|
@@ -70,7 +74,7 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
70
74
|
if (mediaType && multipartFields?.length) {
|
|
71
75
|
const fieldsFound = new Map();
|
|
72
76
|
for (const item of parts) {
|
|
73
|
-
const field = mediaType.findMultipartField(item.
|
|
77
|
+
const field = mediaType.findMultipartField(item.field, item.kind);
|
|
74
78
|
if (field) {
|
|
75
79
|
fieldsFound.set(field, true);
|
|
76
80
|
this._body.push(item);
|
|
@@ -9,15 +9,15 @@ const content_type_1 = require("content-type");
|
|
|
9
9
|
const fast_tokenizer_1 = require("fast-tokenizer");
|
|
10
10
|
const ts_gems_1 = require("ts-gems");
|
|
11
11
|
const valgen_1 = require("valgen");
|
|
12
|
-
const
|
|
13
|
-
const
|
|
12
|
+
const constants_1 = require("../constants");
|
|
13
|
+
const wrap_exception_1 = require("./utils/wrap-exception");
|
|
14
14
|
/**
|
|
15
15
|
* @class HttpHandler
|
|
16
16
|
*/
|
|
17
17
|
class HttpHandler {
|
|
18
18
|
constructor(adapter) {
|
|
19
19
|
this.adapter = adapter;
|
|
20
|
-
this[
|
|
20
|
+
this[constants_1.kAssetCache] = adapter[constants_1.kAssetCache];
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Main http request handler
|
|
@@ -42,7 +42,7 @@ class HttpHandler {
|
|
|
42
42
|
throw e;
|
|
43
43
|
if (e instanceof valgen_1.ValidationError) {
|
|
44
44
|
throw new common_1.BadRequestError({
|
|
45
|
-
message:
|
|
45
|
+
message: 'Response validation failed',
|
|
46
46
|
code: 'RESPONSE_VALIDATION',
|
|
47
47
|
details: e.issues,
|
|
48
48
|
}, e);
|
|
@@ -68,19 +68,17 @@ class HttpHandler {
|
|
|
68
68
|
let e = error;
|
|
69
69
|
if (e instanceof valgen_1.ValidationError) {
|
|
70
70
|
e = new common_1.InternalServerError({
|
|
71
|
-
message:
|
|
71
|
+
message: 'Response validation failed',
|
|
72
72
|
code: 'RESPONSE_VALIDATION',
|
|
73
73
|
details: e.issues,
|
|
74
74
|
}, e);
|
|
75
75
|
}
|
|
76
76
|
else
|
|
77
|
-
e = (0,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
response.end();
|
|
83
|
-
});
|
|
77
|
+
e = (0, wrap_exception_1.wrapException)(e);
|
|
78
|
+
if (this.onError)
|
|
79
|
+
await this.onError(context, error);
|
|
80
|
+
context.errors.push(e);
|
|
81
|
+
await this.sendResponse(context);
|
|
84
82
|
}
|
|
85
83
|
finally {
|
|
86
84
|
await context.emitAsync('finish');
|
|
@@ -121,10 +119,10 @@ class HttpHandler {
|
|
|
121
119
|
};
|
|
122
120
|
/** prepare decoders */
|
|
123
121
|
const getDecoder = (prm) => {
|
|
124
|
-
let decode = this[
|
|
122
|
+
let decode = this[constants_1.kAssetCache].get(prm, 'decode');
|
|
125
123
|
if (!decode) {
|
|
126
124
|
decode = prm.type?.generateCodec('decode', { ignoreReadonlyFields: true }) || valgen_1.vg.isAny();
|
|
127
|
-
this[
|
|
125
|
+
this[constants_1.kAssetCache].set(prm, 'decode', decode);
|
|
128
126
|
}
|
|
129
127
|
return decode;
|
|
130
128
|
};
|
|
@@ -214,6 +212,7 @@ class HttpHandler {
|
|
|
214
212
|
}
|
|
215
213
|
}
|
|
216
214
|
for (const prm of paramsLeft) {
|
|
215
|
+
key = String(prm.name);
|
|
217
216
|
// Throw error for required parameters
|
|
218
217
|
if (prm.required) {
|
|
219
218
|
const decode = getDecoder(prm);
|
|
@@ -265,7 +264,7 @@ class HttpHandler {
|
|
|
265
264
|
const responseValue = await context.operationHandler.call(context.controllerInstance, context);
|
|
266
265
|
const { response } = context;
|
|
267
266
|
if (!response.writableEnded) {
|
|
268
|
-
await this.
|
|
267
|
+
await this.sendResponse(context, responseValue).finally(() => {
|
|
269
268
|
if (!response.writableEnded)
|
|
270
269
|
response.end();
|
|
271
270
|
});
|
|
@@ -277,23 +276,25 @@ class HttpHandler {
|
|
|
277
276
|
* @param responseValue
|
|
278
277
|
* @protected
|
|
279
278
|
*/
|
|
280
|
-
async
|
|
279
|
+
async sendResponse(context, responseValue) {
|
|
280
|
+
if (context.errors.length)
|
|
281
|
+
return this.sendErrorResponse(context, context.errors);
|
|
281
282
|
const { response } = context;
|
|
282
283
|
const { document } = this.adapter;
|
|
283
284
|
const responseArgs = this._determineResponseArgs(context, responseValue);
|
|
284
285
|
const { operationResponse, statusCode } = responseArgs;
|
|
285
286
|
let { contentType, body } = responseArgs;
|
|
286
287
|
const operationResultType = document.node.getDataType(common_1.OperationResult);
|
|
287
|
-
let operationResultEncoder = this[
|
|
288
|
+
let operationResultEncoder = this[constants_1.kAssetCache].get(operationResultType, 'encode');
|
|
288
289
|
if (!operationResultEncoder) {
|
|
289
290
|
operationResultEncoder = operationResultType.generateCodec('encode', { ignoreWriteonlyFields: true });
|
|
290
|
-
this[
|
|
291
|
+
this[constants_1.kAssetCache].set(operationResultType, 'encode', operationResultEncoder);
|
|
291
292
|
}
|
|
292
293
|
/** Validate response */
|
|
293
294
|
if (operationResponse?.type) {
|
|
294
295
|
if (!(body == null && statusCode === common_1.HttpStatusCode.NO_CONTENT)) {
|
|
295
296
|
/** Generate encoder */
|
|
296
|
-
let encode = this[
|
|
297
|
+
let encode = this[constants_1.kAssetCache].get(operationResponse, 'encode');
|
|
297
298
|
if (!encode) {
|
|
298
299
|
encode = operationResponse.type.generateCodec('encode', {
|
|
299
300
|
partial: operationResponse.partial,
|
|
@@ -303,7 +304,7 @@ class HttpHandler {
|
|
|
303
304
|
if (operationResponse) {
|
|
304
305
|
if (operationResponse.isArray)
|
|
305
306
|
encode = valgen_1.vg.isArray(encode);
|
|
306
|
-
this[
|
|
307
|
+
this[constants_1.kAssetCache].set(operationResponse, 'encode', encode);
|
|
307
308
|
}
|
|
308
309
|
}
|
|
309
310
|
/** Encode body */
|
|
@@ -368,6 +369,57 @@ class HttpHandler {
|
|
|
368
369
|
x = String(body);
|
|
369
370
|
response.end(x);
|
|
370
371
|
}
|
|
372
|
+
async sendErrorResponse(context, errors) {
|
|
373
|
+
const { response } = context;
|
|
374
|
+
if (response.headersSent) {
|
|
375
|
+
response.end();
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
errors = errors || context.errors;
|
|
379
|
+
const wrappedErrors = errors.map(wrap_exception_1.wrapException);
|
|
380
|
+
if (!wrappedErrors.length)
|
|
381
|
+
wrappedErrors.push(new common_1.InternalServerError());
|
|
382
|
+
// Sort errors from fatal to info
|
|
383
|
+
wrappedErrors.sort((a, b) => {
|
|
384
|
+
const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
|
|
385
|
+
if (i === 0)
|
|
386
|
+
return b.status - a.status;
|
|
387
|
+
return i;
|
|
388
|
+
});
|
|
389
|
+
context.errors = wrappedErrors;
|
|
390
|
+
let status = response.statusCode || 0;
|
|
391
|
+
if (!status || status < Number(common_1.HttpStatusCode.BAD_REQUEST)) {
|
|
392
|
+
status = wrappedErrors[0].status;
|
|
393
|
+
if (status < Number(common_1.HttpStatusCode.BAD_REQUEST))
|
|
394
|
+
status = common_1.HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
395
|
+
}
|
|
396
|
+
response.statusCode = status;
|
|
397
|
+
this.adapter.emitAsync('error', wrappedErrors[0], context).catch(() => undefined);
|
|
398
|
+
const { document } = this.adapter;
|
|
399
|
+
const dt = document.node.getComplexType('OperationResult');
|
|
400
|
+
let encode = this[constants_1.kAssetCache].get(dt, 'encode');
|
|
401
|
+
if (!encode) {
|
|
402
|
+
encode = dt.generateCodec('encode', { ignoreWriteonlyFields: true });
|
|
403
|
+
this[constants_1.kAssetCache].set(dt, 'encode', encode);
|
|
404
|
+
}
|
|
405
|
+
const { i18n } = this.adapter;
|
|
406
|
+
const bodyObject = new common_1.OperationResult({
|
|
407
|
+
errors: wrappedErrors.map(x => {
|
|
408
|
+
const o = x.toJSON();
|
|
409
|
+
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
410
|
+
delete o.stack;
|
|
411
|
+
return i18n.deep(o);
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
414
|
+
const body = encode(bodyObject);
|
|
415
|
+
response.setHeader(common_1.HttpHeaderCodes.Content_Type, common_1.MimeTypes.opra_response_json + '; charset=utf-8');
|
|
416
|
+
response.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
417
|
+
response.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
418
|
+
response.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
419
|
+
response.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
420
|
+
response.send(JSON.stringify(body));
|
|
421
|
+
response.end();
|
|
422
|
+
}
|
|
371
423
|
/**
|
|
372
424
|
*
|
|
373
425
|
* @param context
|
|
@@ -390,7 +442,7 @@ class HttpHandler {
|
|
|
390
442
|
}
|
|
391
443
|
let operationResponse;
|
|
392
444
|
const cacheKey = `HttpOperationResponse:${statusCode}${contentType ? ':' + contentType : ''}`;
|
|
393
|
-
let responseArgs = this[
|
|
445
|
+
let responseArgs = this[constants_1.kAssetCache].get(response, cacheKey);
|
|
394
446
|
if (!responseArgs) {
|
|
395
447
|
responseArgs = { statusCode, contentType };
|
|
396
448
|
if (operation.responses.length) {
|
|
@@ -436,7 +488,7 @@ class HttpHandler {
|
|
|
436
488
|
}
|
|
437
489
|
if (!hasBody)
|
|
438
490
|
delete responseArgs.contentType;
|
|
439
|
-
this[
|
|
491
|
+
this[constants_1.kAssetCache].set(response, cacheKey, { ...responseArgs });
|
|
440
492
|
}
|
|
441
493
|
/** Fix response value according to composition */
|
|
442
494
|
const composition = operationResponse?.owner.composition;
|
|
@@ -502,85 +554,20 @@ class HttpHandler {
|
|
|
502
554
|
const documentId = searchParams.get('id');
|
|
503
555
|
const doc = documentId ? document.findDocument(documentId) : document;
|
|
504
556
|
if (!doc) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
]);
|
|
557
|
+
context.errors.push(new common_1.BadRequestError({
|
|
558
|
+
message: `Document with given id [${documentId}] does not exists`,
|
|
559
|
+
}));
|
|
560
|
+
return this.sendResponse(context);
|
|
510
561
|
}
|
|
511
562
|
/** Check if response cache exists */
|
|
512
|
-
let responseBody = this[
|
|
563
|
+
let responseBody = this[constants_1.kAssetCache].get(doc, `$schema`);
|
|
513
564
|
/** Create response if response cache does not exists */
|
|
514
565
|
if (!responseBody) {
|
|
515
566
|
const schema = doc.export();
|
|
516
567
|
responseBody = JSON.stringify(schema);
|
|
517
|
-
this[
|
|
568
|
+
this[constants_1.kAssetCache].set(doc, `$schema`, responseBody);
|
|
518
569
|
}
|
|
519
570
|
response.end(responseBody);
|
|
520
571
|
}
|
|
521
|
-
async sendErrorResponse(response, errors) {
|
|
522
|
-
if (response.headersSent) {
|
|
523
|
-
response.end();
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
if (!errors.length)
|
|
527
|
-
errors.push((0, wrap_exception_js_1.wrapException)({ status: response.statusCode || 500 }));
|
|
528
|
-
const { logger } = this.adapter;
|
|
529
|
-
errors.forEach(x => {
|
|
530
|
-
if (x instanceof common_1.OpraException) {
|
|
531
|
-
switch (x.severity) {
|
|
532
|
-
case 'fatal':
|
|
533
|
-
logger.fatal(x);
|
|
534
|
-
break;
|
|
535
|
-
case 'warning':
|
|
536
|
-
logger.warn(x);
|
|
537
|
-
break;
|
|
538
|
-
default:
|
|
539
|
-
logger.error(x);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
else
|
|
543
|
-
logger.fatal(x);
|
|
544
|
-
});
|
|
545
|
-
const wrappedErrors = errors.map(wrap_exception_js_1.wrapException);
|
|
546
|
-
// Sort errors from fatal to info
|
|
547
|
-
wrappedErrors.sort((a, b) => {
|
|
548
|
-
const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
|
|
549
|
-
if (i === 0)
|
|
550
|
-
return b.status - a.status;
|
|
551
|
-
return i;
|
|
552
|
-
});
|
|
553
|
-
let status = response.statusCode || 0;
|
|
554
|
-
if (!status || status < Number(common_1.HttpStatusCode.BAD_REQUEST)) {
|
|
555
|
-
status = wrappedErrors[0].status;
|
|
556
|
-
if (status < Number(common_1.HttpStatusCode.BAD_REQUEST))
|
|
557
|
-
status = common_1.HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
558
|
-
}
|
|
559
|
-
response.statusCode = status;
|
|
560
|
-
const { document } = this.adapter;
|
|
561
|
-
const dt = document.node.getComplexType('OperationResult');
|
|
562
|
-
let encode = this[constants_js_1.kAssetCache].get(dt, 'encode');
|
|
563
|
-
if (!encode) {
|
|
564
|
-
encode = dt.generateCodec('encode', { ignoreWriteonlyFields: true });
|
|
565
|
-
this[constants_js_1.kAssetCache].set(dt, 'encode', encode);
|
|
566
|
-
}
|
|
567
|
-
const { i18n } = this.adapter;
|
|
568
|
-
const bodyObject = new common_1.OperationResult({
|
|
569
|
-
errors: wrappedErrors.map(x => {
|
|
570
|
-
const o = x.toJSON();
|
|
571
|
-
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
572
|
-
delete o.stack;
|
|
573
|
-
return i18n.deep(o);
|
|
574
|
-
}),
|
|
575
|
-
});
|
|
576
|
-
const body = encode(bodyObject);
|
|
577
|
-
response.setHeader(common_1.HttpHeaderCodes.Content_Type, common_1.MimeTypes.opra_response_json + '; charset=utf-8');
|
|
578
|
-
response.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
579
|
-
response.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
580
|
-
response.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
581
|
-
response.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
582
|
-
response.send(JSON.stringify(body));
|
|
583
|
-
response.end();
|
|
584
|
-
}
|
|
585
572
|
}
|
|
586
573
|
exports.HttpHandler = HttpHandler;
|