@opra/core 1.0.0-alpha.9 → 1.0.0-beta.2
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/augmentation/18n.augmentation.js +13 -13
- package/cjs/constants.js +1 -2
- package/cjs/execution-context.js +1 -0
- package/cjs/http/express-adapter.js +22 -20
- package/cjs/http/http-adapter.js +2 -5
- package/cjs/http/http-context.js +16 -31
- package/cjs/http/{impl/http-handler.js → http-handler.js} +194 -169
- package/cjs/http/impl/http-outgoing.host.js +2 -2
- package/cjs/http/impl/multipart-reader.js +141 -44
- package/cjs/http/utils/body-reader.js +0 -1
- package/cjs/http/utils/common.js +4 -4
- package/cjs/http/utils/concat-readable.js +1 -2
- package/cjs/http/utils/convert-to-headers.js +2 -3
- package/cjs/http/utils/convert-to-raw-headers.js +1 -2
- package/cjs/http/utils/match-known-fields.js +2 -2
- package/cjs/http/utils/wrap-exception.js +1 -2
- package/cjs/index.js +1 -1
- package/cjs/platform-adapter.js +0 -3
- package/cjs/type-guards.js +4 -5
- package/esm/augmentation/18n.augmentation.js +2 -2
- package/esm/constants.js +0 -1
- package/esm/execution-context.js +1 -0
- package/esm/http/express-adapter.js +22 -20
- package/esm/http/http-adapter.js +2 -5
- package/esm/http/http-context.js +17 -32
- package/esm/http/{impl/http-handler.js → http-handler.js} +195 -170
- package/esm/http/impl/http-outgoing.host.js +1 -1
- package/esm/http/impl/multipart-reader.js +142 -45
- package/esm/http/utils/body-reader.js +0 -1
- package/esm/index.js +1 -1
- package/esm/package.json +3 -0
- package/esm/platform-adapter.js +0 -3
- package/package.json +35 -63
- package/types/augmentation/http-controller.augmentation.d.ts +1 -2
- package/types/constants.d.ts +0 -1
- package/types/execution-context.d.ts +2 -1
- package/types/helpers/service-base.d.ts +1 -1
- package/types/http/express-adapter.d.ts +1 -1
- package/types/http/http-adapter.d.ts +35 -8
- package/types/http/http-context.d.ts +4 -4
- package/types/http/{impl/http-handler.d.ts → http-handler.d.ts} +11 -9
- package/types/http/impl/http-incoming.host.d.ts +1 -2
- package/types/http/impl/http-outgoing.host.d.ts +1 -1
- package/types/http/impl/multipart-reader.d.ts +38 -20
- package/types/http/impl/node-incoming-message.host.d.ts +3 -7
- package/types/http/impl/node-outgoing-message.host.d.ts +5 -8
- package/types/http/interfaces/http-incoming.interface.d.ts +2 -3
- package/types/http/interfaces/http-outgoing.interface.d.ts +2 -2
- package/types/http/interfaces/node-incoming-message.interface.d.ts +0 -2
- package/types/http/interfaces/node-outgoing-message.interface.d.ts +1 -3
- package/types/http/utils/body-reader.d.ts +1 -4
- package/types/http/utils/concat-readable.d.ts +0 -1
- package/types/http/utils/convert-to-raw-headers.d.ts +1 -2
- package/types/index.d.cts +28 -0
- 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
|
@@ -7,10 +7,11 @@ const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
|
7
7
|
const common_1 = require("@opra/common");
|
|
8
8
|
const content_type_1 = require("content-type");
|
|
9
9
|
const fast_tokenizer_1 = require("fast-tokenizer");
|
|
10
|
+
const super_fast_md5_1 = require("super-fast-md5");
|
|
10
11
|
const ts_gems_1 = require("ts-gems");
|
|
11
12
|
const valgen_1 = require("valgen");
|
|
12
|
-
const constants_js_1 = require("
|
|
13
|
-
const wrap_exception_js_1 = require("
|
|
13
|
+
const constants_js_1 = require("../constants.js");
|
|
14
|
+
const wrap_exception_js_1 = require("./utils/wrap-exception.js");
|
|
14
15
|
/**
|
|
15
16
|
* @class HttpHandler
|
|
16
17
|
*/
|
|
@@ -42,7 +43,7 @@ class HttpHandler {
|
|
|
42
43
|
throw e;
|
|
43
44
|
if (e instanceof valgen_1.ValidationError) {
|
|
44
45
|
throw new common_1.BadRequestError({
|
|
45
|
-
message:
|
|
46
|
+
message: 'Response validation failed',
|
|
46
47
|
code: 'RESPONSE_VALIDATION',
|
|
47
48
|
details: e.issues,
|
|
48
49
|
}, e);
|
|
@@ -52,11 +53,14 @@ class HttpHandler {
|
|
|
52
53
|
await this.adapter.emitAsync('request', context);
|
|
53
54
|
// Call interceptors than execute request
|
|
54
55
|
if (this.adapter.interceptors) {
|
|
56
|
+
const interceptors = this.adapter.interceptors;
|
|
55
57
|
let i = 0;
|
|
56
58
|
const next = async () => {
|
|
57
|
-
const interceptor =
|
|
58
|
-
if (interceptor)
|
|
59
|
+
const interceptor = interceptors[i++];
|
|
60
|
+
if (typeof interceptor === 'function')
|
|
59
61
|
await interceptor(context, next);
|
|
62
|
+
else if (typeof interceptor?.intercept === 'function')
|
|
63
|
+
await interceptor.intercept(context, next);
|
|
60
64
|
await this._executeRequest(context);
|
|
61
65
|
};
|
|
62
66
|
await next();
|
|
@@ -68,19 +72,17 @@ class HttpHandler {
|
|
|
68
72
|
let e = error;
|
|
69
73
|
if (e instanceof valgen_1.ValidationError) {
|
|
70
74
|
e = new common_1.InternalServerError({
|
|
71
|
-
message:
|
|
75
|
+
message: 'Response validation failed',
|
|
72
76
|
code: 'RESPONSE_VALIDATION',
|
|
73
77
|
details: e.issues,
|
|
74
78
|
}, e);
|
|
75
79
|
}
|
|
76
80
|
else
|
|
77
81
|
e = (0, wrap_exception_js_1.wrapException)(e);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
response.end();
|
|
83
|
-
});
|
|
82
|
+
if (this.onError)
|
|
83
|
+
await this.onError(context, error);
|
|
84
|
+
context.errors.push(e);
|
|
85
|
+
await this.sendResponse(context);
|
|
84
86
|
}
|
|
85
87
|
finally {
|
|
86
88
|
await context.emitAsync('finish');
|
|
@@ -93,7 +95,7 @@ class HttpHandler {
|
|
|
93
95
|
async parseRequest(context) {
|
|
94
96
|
await this._parseParameters(context);
|
|
95
97
|
await this._parseContentType(context);
|
|
96
|
-
if (context.operation
|
|
98
|
+
if (context.operation?.requestBody?.immediateFetch)
|
|
97
99
|
await context.getBody();
|
|
98
100
|
/** Set default status code as the first status code between 200 and 299 */
|
|
99
101
|
if (context.operation) {
|
|
@@ -113,6 +115,8 @@ class HttpHandler {
|
|
|
113
115
|
*/
|
|
114
116
|
async _parseParameters(context) {
|
|
115
117
|
const { operation, request } = context;
|
|
118
|
+
if (!operation)
|
|
119
|
+
return;
|
|
116
120
|
let key = '';
|
|
117
121
|
try {
|
|
118
122
|
const onFail = (issue) => {
|
|
@@ -214,6 +218,7 @@ class HttpHandler {
|
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
for (const prm of paramsLeft) {
|
|
221
|
+
key = String(prm.name);
|
|
217
222
|
// Throw error for required parameters
|
|
218
223
|
if (prm.required) {
|
|
219
224
|
const decode = getDecoder(prm);
|
|
@@ -239,6 +244,8 @@ class HttpHandler {
|
|
|
239
244
|
*/
|
|
240
245
|
async _parseContentType(context) {
|
|
241
246
|
const { request, operation } = context;
|
|
247
|
+
if (!operation)
|
|
248
|
+
return;
|
|
242
249
|
if (operation.requestBody?.content.length) {
|
|
243
250
|
let mediaType;
|
|
244
251
|
let contentType = request.header('content-type');
|
|
@@ -265,7 +272,7 @@ class HttpHandler {
|
|
|
265
272
|
const responseValue = await context.operationHandler.call(context.controllerInstance, context);
|
|
266
273
|
const { response } = context;
|
|
267
274
|
if (!response.writableEnded) {
|
|
268
|
-
await this.
|
|
275
|
+
await this.sendResponse(context, responseValue).finally(() => {
|
|
269
276
|
if (!response.writableEnded)
|
|
270
277
|
response.end();
|
|
271
278
|
});
|
|
@@ -277,94 +284,182 @@ class HttpHandler {
|
|
|
277
284
|
* @param responseValue
|
|
278
285
|
* @protected
|
|
279
286
|
*/
|
|
280
|
-
async
|
|
287
|
+
async sendResponse(context, responseValue) {
|
|
288
|
+
if (context.errors.length)
|
|
289
|
+
return this._sendErrorResponse(context);
|
|
281
290
|
const { response } = context;
|
|
282
291
|
const { document } = this.adapter;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
292
|
+
try {
|
|
293
|
+
const responseArgs = this._determineResponseArgs(context, responseValue);
|
|
294
|
+
const { operationResponse, statusCode } = responseArgs;
|
|
295
|
+
let { contentType, body } = responseArgs;
|
|
296
|
+
const operationResultType = document.node.getDataType(common_1.OperationResult);
|
|
297
|
+
let operationResultEncoder = this[constants_js_1.kAssetCache].get(operationResultType, 'encode');
|
|
298
|
+
if (!operationResultEncoder) {
|
|
299
|
+
operationResultEncoder = operationResultType.generateCodec('encode', {
|
|
300
|
+
ignoreWriteonlyFields: true,
|
|
301
|
+
ignoreHiddenFields: true,
|
|
302
|
+
});
|
|
303
|
+
this[constants_js_1.kAssetCache].set(operationResultType, 'encode', operationResultEncoder);
|
|
304
|
+
}
|
|
305
|
+
/** Validate response */
|
|
306
|
+
if (operationResponse?.type) {
|
|
307
|
+
if (!(body == null && statusCode === common_1.HttpStatusCode.NO_CONTENT)) {
|
|
308
|
+
/** Generate encoder */
|
|
309
|
+
const projection = responseArgs.projection || '*';
|
|
310
|
+
const assetKey = (0, super_fast_md5_1.md5)(String(projection));
|
|
311
|
+
let encode = this[constants_js_1.kAssetCache].get(operationResponse, 'encode:' + assetKey);
|
|
312
|
+
if (!encode) {
|
|
313
|
+
encode = operationResponse.type.generateCodec('encode', {
|
|
314
|
+
partial: operationResponse.partial,
|
|
315
|
+
projection,
|
|
316
|
+
ignoreWriteonlyFields: true,
|
|
317
|
+
ignoreHiddenFields: true,
|
|
318
|
+
onFail: issue => `Response body validation failed: ` + issue.message,
|
|
319
|
+
});
|
|
320
|
+
if (operationResponse) {
|
|
321
|
+
if (operationResponse.isArray)
|
|
322
|
+
encode = valgen_1.vg.isArray(encode);
|
|
323
|
+
this[constants_js_1.kAssetCache].set(operationResponse, 'encode:' + assetKey, encode);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/** Encode body */
|
|
327
|
+
if (operationResponse.type.extendsFrom(operationResultType)) {
|
|
328
|
+
if (body instanceof common_1.OperationResult)
|
|
329
|
+
body = encode(body);
|
|
330
|
+
else {
|
|
331
|
+
body.payload = encode(body.payload);
|
|
332
|
+
body = operationResultEncoder(body);
|
|
333
|
+
}
|
|
307
334
|
}
|
|
308
|
-
}
|
|
309
|
-
/** Encode body */
|
|
310
|
-
if (operationResponse.type.extendsFrom(operationResultType)) {
|
|
311
|
-
if (body instanceof common_1.OperationResult)
|
|
312
|
-
body = encode(body);
|
|
313
335
|
else {
|
|
314
|
-
body
|
|
315
|
-
|
|
336
|
+
if (body instanceof common_1.OperationResult &&
|
|
337
|
+
contentType &&
|
|
338
|
+
type_is_1.default.is(contentType, [common_1.MimeTypes.opra_response_json])) {
|
|
339
|
+
body.payload = encode(body.payload);
|
|
340
|
+
body = operationResultEncoder(body);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
body = encode(body);
|
|
344
|
+
}
|
|
316
345
|
}
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
346
|
if (body instanceof common_1.OperationResult &&
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
body.
|
|
323
|
-
body = operationResultEncoder(body);
|
|
347
|
+
operationResponse.type &&
|
|
348
|
+
operationResponse.type !== document.node.getDataType(common_1.OperationResult)) {
|
|
349
|
+
body.type = operationResponse.type.name ? operationResponse.type.name : '#embedded';
|
|
324
350
|
}
|
|
325
|
-
else
|
|
326
|
-
body = encode(body);
|
|
327
|
-
}
|
|
328
|
-
if (body instanceof common_1.OperationResult && operationResponse.type) {
|
|
329
|
-
body.type = operationResponse.type.name ? operationResponse.type.name : '#embedded';
|
|
330
351
|
}
|
|
331
352
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
353
|
+
else if (body != null) {
|
|
354
|
+
if (body instanceof common_1.OperationResult) {
|
|
355
|
+
body = operationResultEncoder(body);
|
|
356
|
+
contentType = common_1.MimeTypes.opra_response_json;
|
|
357
|
+
}
|
|
358
|
+
else if (Buffer.isBuffer(body))
|
|
359
|
+
contentType = common_1.MimeTypes.binary;
|
|
360
|
+
else if (typeof body === 'object') {
|
|
361
|
+
contentType = contentType || common_1.MimeTypes.json;
|
|
362
|
+
if (typeof body.toJSON === 'function')
|
|
363
|
+
body = body.toJSON();
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
contentType = contentType || common_1.MimeTypes.text;
|
|
367
|
+
body = String(body);
|
|
368
|
+
}
|
|
344
369
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
370
|
+
/** Set content-type header value if not set */
|
|
371
|
+
if (contentType && contentType !== responseArgs.contentType)
|
|
372
|
+
response.setHeader('content-type', contentType);
|
|
373
|
+
response.status(statusCode);
|
|
374
|
+
if (body == null) {
|
|
375
|
+
response.end();
|
|
376
|
+
return;
|
|
348
377
|
}
|
|
378
|
+
let x;
|
|
379
|
+
if (Buffer.isBuffer(body) || (0, common_1.isReadableStream)(body))
|
|
380
|
+
x = body;
|
|
381
|
+
else if ((0, common_1.isBlob)(body))
|
|
382
|
+
x = body.stream();
|
|
383
|
+
else if (typeof body === 'object')
|
|
384
|
+
x = JSON.stringify(body);
|
|
385
|
+
else
|
|
386
|
+
x = String(body);
|
|
387
|
+
response.end(x);
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
context.errors.push(error);
|
|
391
|
+
return this._sendErrorResponse(context);
|
|
349
392
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
393
|
+
}
|
|
394
|
+
async _sendErrorResponse(context) {
|
|
395
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
396
|
+
try {
|
|
397
|
+
await this.adapter.emitAsync('error', context);
|
|
398
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
399
|
+
}
|
|
400
|
+
catch (e) {
|
|
401
|
+
context.errors = this._wrapExceptions([e, ...context.errors]);
|
|
402
|
+
}
|
|
403
|
+
const { response, errors } = context;
|
|
404
|
+
if (response.headersSent) {
|
|
355
405
|
response.end();
|
|
356
406
|
return;
|
|
357
407
|
}
|
|
358
|
-
let
|
|
359
|
-
if (
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
408
|
+
let status = response.statusCode || 0;
|
|
409
|
+
if (!status || status < Number(common_1.HttpStatusCode.BAD_REQUEST)) {
|
|
410
|
+
status = errors[0].status;
|
|
411
|
+
if (status < Number(common_1.HttpStatusCode.BAD_REQUEST))
|
|
412
|
+
status = common_1.HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
413
|
+
}
|
|
414
|
+
response.statusCode = status;
|
|
415
|
+
const { document } = this.adapter;
|
|
416
|
+
const dt = document.node.getComplexType('OperationResult');
|
|
417
|
+
let encode = this[constants_js_1.kAssetCache].get(dt, 'encode');
|
|
418
|
+
if (!encode) {
|
|
419
|
+
encode = dt.generateCodec('encode', { ignoreWriteonlyFields: true });
|
|
420
|
+
this[constants_js_1.kAssetCache].set(dt, 'encode', encode);
|
|
421
|
+
}
|
|
422
|
+
// const { i18n } = this.adapter;
|
|
423
|
+
const bodyObject = new common_1.OperationResult({
|
|
424
|
+
errors: errors.map(x => {
|
|
425
|
+
const o = x.toJSON();
|
|
426
|
+
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
427
|
+
delete o.stack;
|
|
428
|
+
return o; // i18n.deep(o);
|
|
429
|
+
}),
|
|
430
|
+
});
|
|
431
|
+
const body = encode(bodyObject);
|
|
432
|
+
response.setHeader(common_1.HttpHeaderCodes.Content_Type, common_1.MimeTypes.opra_response_json + '; charset=utf-8');
|
|
433
|
+
response.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
434
|
+
response.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
435
|
+
response.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
436
|
+
response.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
437
|
+
response.send((0, common_1.safeJsonStringify)(body));
|
|
438
|
+
response.end();
|
|
439
|
+
}
|
|
440
|
+
async sendDocumentSchema(context) {
|
|
441
|
+
const { request, response } = context;
|
|
442
|
+
const { document } = this.adapter;
|
|
443
|
+
response.setHeader('content-type', common_1.MimeTypes.json);
|
|
444
|
+
const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
|
|
445
|
+
const { searchParams } = url;
|
|
446
|
+
const documentId = searchParams.get('id');
|
|
447
|
+
const doc = documentId ? document.findDocument(documentId) : document;
|
|
448
|
+
if (!doc) {
|
|
449
|
+
context.errors.push(new common_1.BadRequestError({
|
|
450
|
+
message: `Document with given id [${documentId}] does not exists`,
|
|
451
|
+
}));
|
|
452
|
+
return this.sendResponse(context);
|
|
453
|
+
}
|
|
454
|
+
/** Check if response cache exists */
|
|
455
|
+
let responseBody = this[constants_js_1.kAssetCache].get(doc, `$schema`);
|
|
456
|
+
/** Create response if response cache does not exists */
|
|
457
|
+
if (!responseBody) {
|
|
458
|
+
const schema = doc.export();
|
|
459
|
+
responseBody = JSON.stringify(schema);
|
|
460
|
+
this[constants_js_1.kAssetCache].set(doc, `$schema`, responseBody);
|
|
461
|
+
}
|
|
462
|
+
response.end(responseBody);
|
|
368
463
|
}
|
|
369
464
|
/**
|
|
370
465
|
*
|
|
@@ -391,7 +486,7 @@ class HttpHandler {
|
|
|
391
486
|
let responseArgs = this[constants_js_1.kAssetCache].get(response, cacheKey);
|
|
392
487
|
if (!responseArgs) {
|
|
393
488
|
responseArgs = { statusCode, contentType };
|
|
394
|
-
if (operation
|
|
489
|
+
if (operation?.responses.length) {
|
|
395
490
|
/** Filter available HttpOperationResponse instances according to status code. */
|
|
396
491
|
const filteredResponses = operation.responses.filter(r => r.statusCode.find(sc => sc.start <= statusCode && sc.end >= statusCode));
|
|
397
492
|
/** Throw InternalServerError if controller returns non-configured status code */
|
|
@@ -423,6 +518,8 @@ class HttpHandler {
|
|
|
423
518
|
: operationResponse.contentType);
|
|
424
519
|
if (typeof ct === 'string')
|
|
425
520
|
responseArgs.contentType = contentType = ct;
|
|
521
|
+
else if (operationResponse.type)
|
|
522
|
+
responseArgs.contentType = common_1.MimeTypes.opra_response_json;
|
|
426
523
|
}
|
|
427
524
|
}
|
|
428
525
|
}
|
|
@@ -434,6 +531,10 @@ class HttpHandler {
|
|
|
434
531
|
}
|
|
435
532
|
if (!hasBody)
|
|
436
533
|
delete responseArgs.contentType;
|
|
534
|
+
if (operation?.composition?.startsWith('Entity.')) {
|
|
535
|
+
if (context.queryParams.projection)
|
|
536
|
+
responseArgs.projection = context.queryParams.projection;
|
|
537
|
+
}
|
|
437
538
|
this[constants_js_1.kAssetCache].set(response, cacheKey, { ...responseArgs });
|
|
438
539
|
}
|
|
439
540
|
/** Fix response value according to composition */
|
|
@@ -491,56 +592,10 @@ class HttpHandler {
|
|
|
491
592
|
responseArgs.body = body;
|
|
492
593
|
return responseArgs;
|
|
493
594
|
}
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
|
|
499
|
-
const { searchParams } = url;
|
|
500
|
-
const documentId = searchParams.get('id');
|
|
501
|
-
const doc = documentId ? document.findDocument(documentId) : document;
|
|
502
|
-
if (!doc) {
|
|
503
|
-
return this.sendErrorResponse(response, [
|
|
504
|
-
new common_1.BadRequestError({
|
|
505
|
-
message: `Document with given id [${documentId}] does not exists`,
|
|
506
|
-
}),
|
|
507
|
-
]);
|
|
508
|
-
}
|
|
509
|
-
/** Check if response cache exists */
|
|
510
|
-
let responseBody = this[constants_js_1.kAssetCache].get(doc, `$schema`);
|
|
511
|
-
/** Create response if response cache does not exists */
|
|
512
|
-
if (!responseBody) {
|
|
513
|
-
const schema = doc.export();
|
|
514
|
-
responseBody = JSON.stringify(schema);
|
|
515
|
-
this[constants_js_1.kAssetCache].set(doc, `$schema`, responseBody);
|
|
516
|
-
}
|
|
517
|
-
response.end(responseBody);
|
|
518
|
-
}
|
|
519
|
-
async sendErrorResponse(response, errors) {
|
|
520
|
-
if (response.headersSent) {
|
|
521
|
-
response.end();
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
if (!errors.length)
|
|
525
|
-
errors.push((0, wrap_exception_js_1.wrapException)({ status: response.statusCode || 500 }));
|
|
526
|
-
const { logger } = this.adapter;
|
|
527
|
-
errors.forEach(x => {
|
|
528
|
-
if (x instanceof common_1.OpraException) {
|
|
529
|
-
switch (x.severity) {
|
|
530
|
-
case 'fatal':
|
|
531
|
-
logger.fatal(x);
|
|
532
|
-
break;
|
|
533
|
-
case 'warning':
|
|
534
|
-
logger.warn(x);
|
|
535
|
-
break;
|
|
536
|
-
default:
|
|
537
|
-
logger.error(x);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
else
|
|
541
|
-
logger.fatal(x);
|
|
542
|
-
});
|
|
543
|
-
const wrappedErrors = errors.map(wrap_exception_js_1.wrapException);
|
|
595
|
+
_wrapExceptions(exceptions) {
|
|
596
|
+
const wrappedErrors = exceptions.map(wrap_exception_js_1.wrapException);
|
|
597
|
+
if (!wrappedErrors.length)
|
|
598
|
+
wrappedErrors.push(new common_1.InternalServerError());
|
|
544
599
|
// Sort errors from fatal to info
|
|
545
600
|
wrappedErrors.sort((a, b) => {
|
|
546
601
|
const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
|
|
@@ -548,37 +603,7 @@ class HttpHandler {
|
|
|
548
603
|
return b.status - a.status;
|
|
549
604
|
return i;
|
|
550
605
|
});
|
|
551
|
-
|
|
552
|
-
if (!status || status < Number(common_1.HttpStatusCode.BAD_REQUEST)) {
|
|
553
|
-
status = wrappedErrors[0].status;
|
|
554
|
-
if (status < Number(common_1.HttpStatusCode.BAD_REQUEST))
|
|
555
|
-
status = common_1.HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
556
|
-
}
|
|
557
|
-
response.statusCode = status;
|
|
558
|
-
const { document } = this.adapter;
|
|
559
|
-
const dt = document.node.getComplexType('OperationResult');
|
|
560
|
-
let encode = this[constants_js_1.kAssetCache].get(dt, 'encode');
|
|
561
|
-
if (!encode) {
|
|
562
|
-
encode = dt.generateCodec('encode', { ignoreWriteonlyFields: true });
|
|
563
|
-
this[constants_js_1.kAssetCache].set(dt, 'encode', encode);
|
|
564
|
-
}
|
|
565
|
-
const { i18n } = this.adapter;
|
|
566
|
-
const bodyObject = new common_1.OperationResult({
|
|
567
|
-
errors: wrappedErrors.map(x => {
|
|
568
|
-
const o = x.toJSON();
|
|
569
|
-
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
570
|
-
delete o.stack;
|
|
571
|
-
return i18n.deep(o);
|
|
572
|
-
}),
|
|
573
|
-
});
|
|
574
|
-
const body = encode(bodyObject);
|
|
575
|
-
response.setHeader(common_1.HttpHeaderCodes.Content_Type, common_1.MimeTypes.opra_response_json + '; charset=utf-8');
|
|
576
|
-
response.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
577
|
-
response.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
578
|
-
response.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
579
|
-
response.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
580
|
-
response.send(JSON.stringify(body));
|
|
581
|
-
response.end();
|
|
606
|
+
return wrappedErrors;
|
|
582
607
|
}
|
|
583
608
|
}
|
|
584
609
|
exports.HttpHandler = HttpHandler;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.HttpOutgoingHost = void 0;
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
9
10
|
const common_1 = require("@opra/common");
|
|
10
11
|
const content_disposition_1 = tslib_1.__importDefault(require("content-disposition"));
|
|
11
12
|
const content_type_1 = tslib_1.__importDefault(require("content-type"));
|
|
@@ -13,14 +14,13 @@ const cookie_1 = tslib_1.__importDefault(require("cookie"));
|
|
|
13
14
|
const cookie_signature_1 = tslib_1.__importDefault(require("cookie-signature"));
|
|
14
15
|
const encodeurl_1 = tslib_1.__importDefault(require("encodeurl"));
|
|
15
16
|
const mime_types_1 = tslib_1.__importDefault(require("mime-types"));
|
|
16
|
-
const path_1 = tslib_1.__importDefault(require("path"));
|
|
17
17
|
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
18
18
|
const vary_1 = tslib_1.__importDefault(require("vary"));
|
|
19
19
|
const charsetRegExp = /;\s*charset\s*=/;
|
|
20
20
|
class HttpOutgoingHost {
|
|
21
21
|
attachment(filename) {
|
|
22
22
|
if (filename)
|
|
23
|
-
this.contentType(
|
|
23
|
+
this.contentType(node_path_1.default.extname(filename));
|
|
24
24
|
this.setHeader('Content-Disposition', (0, content_disposition_1.default)(filename));
|
|
25
25
|
return this;
|
|
26
26
|
}
|