@opra/core 1.0.0-alpha.25 → 1.0.0-alpha.26
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/http/http-context.js +1 -20
- package/cjs/http/http-handler.js +46 -37
- package/cjs/http/impl/multipart-reader.js +10 -1
- package/esm/http/http-context.js +2 -21
- package/esm/http/http-handler.js +46 -37
- package/esm/http/impl/multipart-reader.js +10 -1
- package/package.json +2 -2
- package/types/execution-context.d.ts +2 -2
- package/types/http/http-handler.d.ts +3 -2
package/cjs/http/http-context.js
CHANGED
|
@@ -69,26 +69,7 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
69
69
|
/** Retrieve all fields */
|
|
70
70
|
const parts = await reader.getAll();
|
|
71
71
|
/** Filter fields according to configuration */
|
|
72
|
-
this._body = [];
|
|
73
|
-
const multipartFields = mediaType?.multipartFields;
|
|
74
|
-
if (mediaType && multipartFields?.length) {
|
|
75
|
-
const fieldsFound = new Map();
|
|
76
|
-
for (const item of parts) {
|
|
77
|
-
const field = mediaType.findMultipartField(item.field, item.kind);
|
|
78
|
-
if (field) {
|
|
79
|
-
fieldsFound.set(field, true);
|
|
80
|
-
this._body.push(item);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
/** Check required fields */
|
|
84
|
-
for (const field of multipartFields) {
|
|
85
|
-
if (field.required && !fieldsFound.get(field)) {
|
|
86
|
-
throw new common_1.BadRequestError({
|
|
87
|
-
message: `Multipart field (${field.fieldName}) is required`,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
72
|
+
this._body = [...parts];
|
|
92
73
|
return this._body;
|
|
93
74
|
}
|
|
94
75
|
this._body = await this.request.readBody({ limit: operation.requestBody?.maxContentSize });
|
package/cjs/http/http-handler.js
CHANGED
|
@@ -378,30 +378,26 @@ class HttpHandler {
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
async _sendErrorResponse(context) {
|
|
381
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
382
|
+
try {
|
|
383
|
+
await this.adapter.emitAsync('error', context.errors, context);
|
|
384
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
385
|
+
}
|
|
386
|
+
catch (e) {
|
|
387
|
+
context.errors = this._wrapExceptions([e, ...context.errors]);
|
|
388
|
+
}
|
|
381
389
|
const { response, errors } = context;
|
|
382
390
|
if (response.headersSent) {
|
|
383
391
|
response.end();
|
|
384
392
|
return;
|
|
385
393
|
}
|
|
386
|
-
const wrappedErrors = errors.map(wrap_exception_1.wrapException);
|
|
387
|
-
if (!wrappedErrors.length)
|
|
388
|
-
wrappedErrors.push(new common_1.InternalServerError());
|
|
389
|
-
// Sort errors from fatal to info
|
|
390
|
-
wrappedErrors.sort((a, b) => {
|
|
391
|
-
const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
|
|
392
|
-
if (i === 0)
|
|
393
|
-
return b.status - a.status;
|
|
394
|
-
return i;
|
|
395
|
-
});
|
|
396
|
-
context.errors = wrappedErrors;
|
|
397
394
|
let status = response.statusCode || 0;
|
|
398
395
|
if (!status || status < Number(common_1.HttpStatusCode.BAD_REQUEST)) {
|
|
399
|
-
status =
|
|
396
|
+
status = errors[0].status;
|
|
400
397
|
if (status < Number(common_1.HttpStatusCode.BAD_REQUEST))
|
|
401
398
|
status = common_1.HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
402
399
|
}
|
|
403
400
|
response.statusCode = status;
|
|
404
|
-
this.adapter.emitAsync('error', wrappedErrors[0], context).catch(() => undefined);
|
|
405
401
|
const { document } = this.adapter;
|
|
406
402
|
const dt = document.node.getComplexType('OperationResult');
|
|
407
403
|
let encode = this[constants_1.kAssetCache].get(dt, 'encode');
|
|
@@ -411,7 +407,7 @@ class HttpHandler {
|
|
|
411
407
|
}
|
|
412
408
|
const { i18n } = this.adapter;
|
|
413
409
|
const bodyObject = new common_1.OperationResult({
|
|
414
|
-
errors:
|
|
410
|
+
errors: errors.map(x => {
|
|
415
411
|
const o = x.toJSON();
|
|
416
412
|
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
417
413
|
delete o.stack;
|
|
@@ -427,6 +423,30 @@ class HttpHandler {
|
|
|
427
423
|
response.send(JSON.stringify(body));
|
|
428
424
|
response.end();
|
|
429
425
|
}
|
|
426
|
+
async sendDocumentSchema(context) {
|
|
427
|
+
const { request, response } = context;
|
|
428
|
+
const { document } = this.adapter;
|
|
429
|
+
response.setHeader('content-type', common_1.MimeTypes.json);
|
|
430
|
+
const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
|
|
431
|
+
const { searchParams } = url;
|
|
432
|
+
const documentId = searchParams.get('id');
|
|
433
|
+
const doc = documentId ? document.findDocument(documentId) : document;
|
|
434
|
+
if (!doc) {
|
|
435
|
+
context.errors.push(new common_1.BadRequestError({
|
|
436
|
+
message: `Document with given id [${documentId}] does not exists`,
|
|
437
|
+
}));
|
|
438
|
+
return this.sendResponse(context);
|
|
439
|
+
}
|
|
440
|
+
/** Check if response cache exists */
|
|
441
|
+
let responseBody = this[constants_1.kAssetCache].get(doc, `$schema`);
|
|
442
|
+
/** Create response if response cache does not exists */
|
|
443
|
+
if (!responseBody) {
|
|
444
|
+
const schema = doc.export();
|
|
445
|
+
responseBody = JSON.stringify(schema);
|
|
446
|
+
this[constants_1.kAssetCache].set(doc, `$schema`, responseBody);
|
|
447
|
+
}
|
|
448
|
+
response.end(responseBody);
|
|
449
|
+
}
|
|
430
450
|
/**
|
|
431
451
|
*
|
|
432
452
|
* @param context
|
|
@@ -554,29 +574,18 @@ class HttpHandler {
|
|
|
554
574
|
responseArgs.body = body;
|
|
555
575
|
return responseArgs;
|
|
556
576
|
}
|
|
557
|
-
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return this.sendResponse(context);
|
|
570
|
-
}
|
|
571
|
-
/** Check if response cache exists */
|
|
572
|
-
let responseBody = this[constants_1.kAssetCache].get(doc, `$schema`);
|
|
573
|
-
/** Create response if response cache does not exists */
|
|
574
|
-
if (!responseBody) {
|
|
575
|
-
const schema = doc.export();
|
|
576
|
-
responseBody = JSON.stringify(schema);
|
|
577
|
-
this[constants_1.kAssetCache].set(doc, `$schema`, responseBody);
|
|
578
|
-
}
|
|
579
|
-
response.end(responseBody);
|
|
577
|
+
_wrapExceptions(exceptions) {
|
|
578
|
+
const wrappedErrors = exceptions.map(wrap_exception_1.wrapException);
|
|
579
|
+
if (!wrappedErrors.length)
|
|
580
|
+
wrappedErrors.push(new common_1.InternalServerError());
|
|
581
|
+
// Sort errors from fatal to info
|
|
582
|
+
wrappedErrors.sort((a, b) => {
|
|
583
|
+
const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
|
|
584
|
+
if (i === 0)
|
|
585
|
+
return b.status - a.status;
|
|
586
|
+
return i;
|
|
587
|
+
});
|
|
588
|
+
return wrappedErrors;
|
|
580
589
|
}
|
|
581
590
|
}
|
|
582
591
|
exports.HttpHandler = HttpHandler;
|
|
@@ -76,15 +76,22 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
76
76
|
if (!item && !this._finished) {
|
|
77
77
|
this.resume();
|
|
78
78
|
item = await new Promise((resolve, reject) => {
|
|
79
|
+
let resolved = false;
|
|
79
80
|
if (this._stack.length)
|
|
80
81
|
return resolve(this._stack.shift());
|
|
81
82
|
if (this._form.ended)
|
|
82
83
|
return resolve(undefined);
|
|
83
84
|
this._form.once('close', () => {
|
|
85
|
+
if (resolved)
|
|
86
|
+
return;
|
|
87
|
+
resolved = true;
|
|
84
88
|
resolve(this._stack.shift());
|
|
85
89
|
});
|
|
86
90
|
this.once('item', () => {
|
|
87
91
|
this.pause();
|
|
92
|
+
if (resolved)
|
|
93
|
+
return;
|
|
94
|
+
resolved = true;
|
|
88
95
|
resolve(this._stack.shift());
|
|
89
96
|
});
|
|
90
97
|
this.once('error', e => reject(e));
|
|
@@ -119,6 +126,8 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
119
126
|
}
|
|
120
127
|
let issues;
|
|
121
128
|
for (const field of fieldsLeft) {
|
|
129
|
+
if (!field.required)
|
|
130
|
+
continue;
|
|
122
131
|
try {
|
|
123
132
|
(0, valgen_1.isNotNullish)(null, { onFail: () => `Multi part field "${String(field.fieldName)}" is required` });
|
|
124
133
|
}
|
|
@@ -137,7 +146,7 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
137
146
|
return item;
|
|
138
147
|
}
|
|
139
148
|
async getAll() {
|
|
140
|
-
const items = [];
|
|
149
|
+
const items = [...this._items];
|
|
141
150
|
let item;
|
|
142
151
|
while (!this._cancelled && (item = await this.getNext())) {
|
|
143
152
|
items.push(item);
|
package/esm/http/http-context.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import typeIs from '@browsery/type-is';
|
|
2
|
-
import {
|
|
2
|
+
import { InternalServerError, NotAcceptableError, } from '@opra/common';
|
|
3
3
|
import { vg } from 'valgen';
|
|
4
4
|
import { kAssetCache } from '../constants.js';
|
|
5
5
|
import { ExecutionContext } from '../execution-context.js';
|
|
@@ -65,26 +65,7 @@ export class HttpContext extends ExecutionContext {
|
|
|
65
65
|
/** Retrieve all fields */
|
|
66
66
|
const parts = await reader.getAll();
|
|
67
67
|
/** Filter fields according to configuration */
|
|
68
|
-
this._body = [];
|
|
69
|
-
const multipartFields = mediaType?.multipartFields;
|
|
70
|
-
if (mediaType && multipartFields?.length) {
|
|
71
|
-
const fieldsFound = new Map();
|
|
72
|
-
for (const item of parts) {
|
|
73
|
-
const field = mediaType.findMultipartField(item.field, item.kind);
|
|
74
|
-
if (field) {
|
|
75
|
-
fieldsFound.set(field, true);
|
|
76
|
-
this._body.push(item);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/** Check required fields */
|
|
80
|
-
for (const field of multipartFields) {
|
|
81
|
-
if (field.required && !fieldsFound.get(field)) {
|
|
82
|
-
throw new BadRequestError({
|
|
83
|
-
message: `Multipart field (${field.fieldName}) is required`,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
68
|
+
this._body = [...parts];
|
|
88
69
|
return this._body;
|
|
89
70
|
}
|
|
90
71
|
this._body = await this.request.readBody({ limit: operation.requestBody?.maxContentSize });
|
package/esm/http/http-handler.js
CHANGED
|
@@ -374,30 +374,26 @@ export class HttpHandler {
|
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
376
|
async _sendErrorResponse(context) {
|
|
377
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
378
|
+
try {
|
|
379
|
+
await this.adapter.emitAsync('error', context.errors, context);
|
|
380
|
+
context.errors = this._wrapExceptions(context.errors);
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
context.errors = this._wrapExceptions([e, ...context.errors]);
|
|
384
|
+
}
|
|
377
385
|
const { response, errors } = context;
|
|
378
386
|
if (response.headersSent) {
|
|
379
387
|
response.end();
|
|
380
388
|
return;
|
|
381
389
|
}
|
|
382
|
-
const wrappedErrors = errors.map(wrapException);
|
|
383
|
-
if (!wrappedErrors.length)
|
|
384
|
-
wrappedErrors.push(new InternalServerError());
|
|
385
|
-
// Sort errors from fatal to info
|
|
386
|
-
wrappedErrors.sort((a, b) => {
|
|
387
|
-
const i = IssueSeverity.Keys.indexOf(a.severity) - IssueSeverity.Keys.indexOf(b.severity);
|
|
388
|
-
if (i === 0)
|
|
389
|
-
return b.status - a.status;
|
|
390
|
-
return i;
|
|
391
|
-
});
|
|
392
|
-
context.errors = wrappedErrors;
|
|
393
390
|
let status = response.statusCode || 0;
|
|
394
391
|
if (!status || status < Number(HttpStatusCode.BAD_REQUEST)) {
|
|
395
|
-
status =
|
|
392
|
+
status = errors[0].status;
|
|
396
393
|
if (status < Number(HttpStatusCode.BAD_REQUEST))
|
|
397
394
|
status = HttpStatusCode.INTERNAL_SERVER_ERROR;
|
|
398
395
|
}
|
|
399
396
|
response.statusCode = status;
|
|
400
|
-
this.adapter.emitAsync('error', wrappedErrors[0], context).catch(() => undefined);
|
|
401
397
|
const { document } = this.adapter;
|
|
402
398
|
const dt = document.node.getComplexType('OperationResult');
|
|
403
399
|
let encode = this[kAssetCache].get(dt, 'encode');
|
|
@@ -407,7 +403,7 @@ export class HttpHandler {
|
|
|
407
403
|
}
|
|
408
404
|
const { i18n } = this.adapter;
|
|
409
405
|
const bodyObject = new OperationResult({
|
|
410
|
-
errors:
|
|
406
|
+
errors: errors.map(x => {
|
|
411
407
|
const o = x.toJSON();
|
|
412
408
|
if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
|
|
413
409
|
delete o.stack;
|
|
@@ -423,6 +419,30 @@ export class HttpHandler {
|
|
|
423
419
|
response.send(JSON.stringify(body));
|
|
424
420
|
response.end();
|
|
425
421
|
}
|
|
422
|
+
async sendDocumentSchema(context) {
|
|
423
|
+
const { request, response } = context;
|
|
424
|
+
const { document } = this.adapter;
|
|
425
|
+
response.setHeader('content-type', MimeTypes.json);
|
|
426
|
+
const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
|
|
427
|
+
const { searchParams } = url;
|
|
428
|
+
const documentId = searchParams.get('id');
|
|
429
|
+
const doc = documentId ? document.findDocument(documentId) : document;
|
|
430
|
+
if (!doc) {
|
|
431
|
+
context.errors.push(new BadRequestError({
|
|
432
|
+
message: `Document with given id [${documentId}] does not exists`,
|
|
433
|
+
}));
|
|
434
|
+
return this.sendResponse(context);
|
|
435
|
+
}
|
|
436
|
+
/** Check if response cache exists */
|
|
437
|
+
let responseBody = this[kAssetCache].get(doc, `$schema`);
|
|
438
|
+
/** Create response if response cache does not exists */
|
|
439
|
+
if (!responseBody) {
|
|
440
|
+
const schema = doc.export();
|
|
441
|
+
responseBody = JSON.stringify(schema);
|
|
442
|
+
this[kAssetCache].set(doc, `$schema`, responseBody);
|
|
443
|
+
}
|
|
444
|
+
response.end(responseBody);
|
|
445
|
+
}
|
|
426
446
|
/**
|
|
427
447
|
*
|
|
428
448
|
* @param context
|
|
@@ -550,28 +570,17 @@ export class HttpHandler {
|
|
|
550
570
|
responseArgs.body = body;
|
|
551
571
|
return responseArgs;
|
|
552
572
|
}
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
return this.sendResponse(context);
|
|
566
|
-
}
|
|
567
|
-
/** Check if response cache exists */
|
|
568
|
-
let responseBody = this[kAssetCache].get(doc, `$schema`);
|
|
569
|
-
/** Create response if response cache does not exists */
|
|
570
|
-
if (!responseBody) {
|
|
571
|
-
const schema = doc.export();
|
|
572
|
-
responseBody = JSON.stringify(schema);
|
|
573
|
-
this[kAssetCache].set(doc, `$schema`, responseBody);
|
|
574
|
-
}
|
|
575
|
-
response.end(responseBody);
|
|
573
|
+
_wrapExceptions(exceptions) {
|
|
574
|
+
const wrappedErrors = exceptions.map(wrapException);
|
|
575
|
+
if (!wrappedErrors.length)
|
|
576
|
+
wrappedErrors.push(new InternalServerError());
|
|
577
|
+
// Sort errors from fatal to info
|
|
578
|
+
wrappedErrors.sort((a, b) => {
|
|
579
|
+
const i = IssueSeverity.Keys.indexOf(a.severity) - IssueSeverity.Keys.indexOf(b.severity);
|
|
580
|
+
if (i === 0)
|
|
581
|
+
return b.status - a.status;
|
|
582
|
+
return i;
|
|
583
|
+
});
|
|
584
|
+
return wrappedErrors;
|
|
576
585
|
}
|
|
577
586
|
}
|
|
@@ -72,15 +72,22 @@ export class MultipartReader extends EventEmitter {
|
|
|
72
72
|
if (!item && !this._finished) {
|
|
73
73
|
this.resume();
|
|
74
74
|
item = await new Promise((resolve, reject) => {
|
|
75
|
+
let resolved = false;
|
|
75
76
|
if (this._stack.length)
|
|
76
77
|
return resolve(this._stack.shift());
|
|
77
78
|
if (this._form.ended)
|
|
78
79
|
return resolve(undefined);
|
|
79
80
|
this._form.once('close', () => {
|
|
81
|
+
if (resolved)
|
|
82
|
+
return;
|
|
83
|
+
resolved = true;
|
|
80
84
|
resolve(this._stack.shift());
|
|
81
85
|
});
|
|
82
86
|
this.once('item', () => {
|
|
83
87
|
this.pause();
|
|
88
|
+
if (resolved)
|
|
89
|
+
return;
|
|
90
|
+
resolved = true;
|
|
84
91
|
resolve(this._stack.shift());
|
|
85
92
|
});
|
|
86
93
|
this.once('error', e => reject(e));
|
|
@@ -115,6 +122,8 @@ export class MultipartReader extends EventEmitter {
|
|
|
115
122
|
}
|
|
116
123
|
let issues;
|
|
117
124
|
for (const field of fieldsLeft) {
|
|
125
|
+
if (!field.required)
|
|
126
|
+
continue;
|
|
118
127
|
try {
|
|
119
128
|
isNotNullish(null, { onFail: () => `Multi part field "${String(field.fieldName)}" is required` });
|
|
120
129
|
}
|
|
@@ -133,7 +142,7 @@ export class MultipartReader extends EventEmitter {
|
|
|
133
142
|
return item;
|
|
134
143
|
}
|
|
135
144
|
async getAll() {
|
|
136
|
-
const items = [];
|
|
145
|
+
const items = [...this._items];
|
|
137
146
|
let item;
|
|
138
147
|
while (!this._cancelled && (item = await this.getNext())) {
|
|
139
148
|
items.push(item);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/core",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.26",
|
|
4
4
|
"description": "Opra schema package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@browsery/http-parser": "^0.5.8",
|
|
35
35
|
"@browsery/type-is": "^1.6.18-r2",
|
|
36
|
-
"@opra/common": "^1.0.0-alpha.
|
|
36
|
+
"@opra/common": "^1.0.0-alpha.26",
|
|
37
37
|
"accepts": "^1.3.8",
|
|
38
38
|
"base64-stream": "^1.0.0",
|
|
39
39
|
"busboy": "^1.6.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiDocument,
|
|
1
|
+
import { ApiDocument, OpraHttpError, OpraSchema } from '@opra/common';
|
|
2
2
|
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
3
3
|
/**
|
|
4
4
|
* @namespace ExecutionContext
|
|
@@ -18,7 +18,7 @@ export declare abstract class ExecutionContext extends AsyncEventEmitter {
|
|
|
18
18
|
readonly document: ApiDocument;
|
|
19
19
|
readonly protocol: OpraSchema.Protocol;
|
|
20
20
|
readonly platform: string;
|
|
21
|
-
errors:
|
|
21
|
+
errors: OpraHttpError[];
|
|
22
22
|
protected constructor(init: ExecutionContext.Initiator);
|
|
23
23
|
addListener(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
|
|
24
24
|
removeListener(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HttpOperationResponse, OpraException } from '@opra/common';
|
|
1
|
+
import { HttpOperationResponse, OpraException, OpraHttpError } from '@opra/common';
|
|
2
2
|
import { kAssetCache } from '../constants';
|
|
3
3
|
import type { HttpAdapter } from './http-adapter';
|
|
4
4
|
import { HttpContext } from './http-context';
|
|
@@ -62,6 +62,7 @@ export declare class HttpHandler {
|
|
|
62
62
|
*/
|
|
63
63
|
sendResponse(context: HttpContext, responseValue?: any): Promise<void>;
|
|
64
64
|
protected _sendErrorResponse(context: HttpContext): Promise<void>;
|
|
65
|
+
sendDocumentSchema(context: HttpContext): Promise<void>;
|
|
65
66
|
/**
|
|
66
67
|
*
|
|
67
68
|
* @param context
|
|
@@ -69,5 +70,5 @@ export declare class HttpHandler {
|
|
|
69
70
|
* @protected
|
|
70
71
|
*/
|
|
71
72
|
protected _determineResponseArgs(context: HttpContext, body: any): HttpHandler.ResponseArgs;
|
|
72
|
-
|
|
73
|
+
protected _wrapExceptions(exceptions: any[]): OpraHttpError[];
|
|
73
74
|
}
|