@opra/core 1.0.0-alpha.7 → 1.0.0-alpha.9
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 +1 -1
- package/cjs/http/express-adapter.js +6 -12
- package/cjs/http/http-context.js +5 -3
- package/cjs/http/impl/http-handler.js +53 -39
- package/cjs/http/impl/http-incoming.host.js +3 -3
- package/cjs/http/impl/http-outgoing.host.js +2 -2
- package/cjs/http/impl/multipart-reader.js +4 -10
- package/cjs/http/impl/node-incoming-message.host.js +5 -3
- package/cjs/http/interfaces/node-incoming-message.interface.js +3 -2
- package/cjs/http/utils/body-reader.js +6 -4
- package/cjs/http/utils/common.js +2 -1
- package/cjs/index.js +3 -3
- package/cjs/platform-adapter.js +1 -1
- package/esm/augmentation/18n.augmentation.js +1 -1
- package/esm/http/express-adapter.js +6 -12
- package/esm/http/http-context.js +5 -3
- package/esm/http/impl/http-handler.js +53 -39
- package/esm/http/impl/http-incoming.host.js +3 -3
- package/esm/http/impl/http-outgoing.host.js +2 -2
- package/esm/http/impl/multipart-reader.js +4 -10
- package/esm/http/impl/node-incoming-message.host.js +5 -3
- package/esm/http/interfaces/node-incoming-message.interface.js +3 -2
- package/esm/http/utils/body-reader.js +6 -4
- package/esm/http/utils/common.js +2 -1
- package/esm/index.js +3 -3
- package/esm/platform-adapter.js +1 -1
- package/package.json +10 -4
- package/types/augmentation/18n.augmentation.d.ts +1 -1
- package/types/execution-context.d.ts +1 -1
- package/types/http/express-adapter.d.ts +1 -1
- package/types/http/impl/node-incoming-message.host.d.ts +1 -1
- package/types/http/utils/body-reader.d.ts +1 -1
- package/types/index.d.ts +3 -3
- package/types/platform-adapter.d.ts +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
4
5
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
5
6
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
6
|
-
const common_1 = require("@opra/common");
|
|
7
7
|
common_1.I18n.load = async function (options) {
|
|
8
8
|
const opts = {
|
|
9
9
|
...options,
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExpressAdapter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@opra/common");
|
|
5
6
|
const express_1 = require("express");
|
|
6
7
|
const nodePath = tslib_1.__importStar(require("path"));
|
|
7
|
-
const common_1 = require("@opra/common");
|
|
8
8
|
const constants_js_1 = require("../constants.js");
|
|
9
9
|
const http_adapter_js_1 = require("./http-adapter.js");
|
|
10
10
|
const http_context_js_1 = require("./http-context.js");
|
|
@@ -35,13 +35,14 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
35
35
|
}
|
|
36
36
|
if (resource.onShutdown) {
|
|
37
37
|
const instance = this._controllerInstances.get(resource) || resource.instance;
|
|
38
|
-
if (instance)
|
|
38
|
+
if (instance) {
|
|
39
39
|
try {
|
|
40
40
|
await resource.onShutdown.call(instance, resource);
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
43
|
this.logger.error(e);
|
|
44
44
|
}
|
|
45
|
+
}
|
|
45
46
|
}
|
|
46
47
|
};
|
|
47
48
|
for (const c of this.api.controllers.values())
|
|
@@ -77,16 +78,9 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
77
78
|
});
|
|
78
79
|
};
|
|
79
80
|
/** Add an endpoint that returns document schema */
|
|
80
|
-
router.get('
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (url === '/$schema') {
|
|
84
|
-
const context = createContext(_req, _res);
|
|
85
|
-
this[constants_js_1.kHandler].sendDocumentSchema(context).catch(next);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
next();
|
|
81
|
+
router.get('/\\$schema', (_req, _res, next) => {
|
|
82
|
+
const context = createContext(_req, _res);
|
|
83
|
+
this[constants_js_1.kHandler].sendDocumentSchema(context).catch(next);
|
|
90
84
|
});
|
|
91
85
|
/** Add operation endpoints */
|
|
92
86
|
if (this.api.controllers.size) {
|
package/cjs/http/http-context.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HttpContext = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const valgen_1 = require("valgen");
|
|
6
5
|
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
7
6
|
const common_1 = require("@opra/common");
|
|
7
|
+
const valgen_1 = require("valgen");
|
|
8
8
|
const constants_js_1 = require("../constants.js");
|
|
9
9
|
const execution_context_js_1 = require("../execution-context.js");
|
|
10
10
|
const multipart_reader_js_1 = require("./impl/multipart-reader.js");
|
|
@@ -78,10 +78,11 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
78
78
|
}
|
|
79
79
|
/** Check required fields */
|
|
80
80
|
for (const field of multipartFields) {
|
|
81
|
-
if (field.required && !fieldsFound.get(field))
|
|
81
|
+
if (field.required && !fieldsFound.get(field)) {
|
|
82
82
|
throw new common_1.BadRequestError({
|
|
83
83
|
message: `Multipart field (${field.fieldName}) is required`,
|
|
84
84
|
});
|
|
85
|
+
}
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
return this._body;
|
|
@@ -89,8 +90,9 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
89
90
|
this._body = await this.request.readBody({ limit: operation.requestBody?.maxContentSize });
|
|
90
91
|
if (this._body != null) {
|
|
91
92
|
// Convert Buffer to string if media is text
|
|
92
|
-
if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text']))
|
|
93
|
+
if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text'])) {
|
|
93
94
|
this._body = this._body.toString('utf-8');
|
|
95
|
+
}
|
|
94
96
|
// Transform text to Object if media is JSON
|
|
95
97
|
if (typeof this._body === 'string' && request.is(['json']))
|
|
96
98
|
this._body = JSON.parse(this._body);
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HttpHandler = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const process = tslib_1.__importStar(require("node:process"));
|
|
6
|
+
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
7
|
+
const common_1 = require("@opra/common");
|
|
5
8
|
const content_type_1 = require("content-type");
|
|
6
9
|
const fast_tokenizer_1 = require("fast-tokenizer");
|
|
7
|
-
const process = tslib_1.__importStar(require("node:process"));
|
|
8
10
|
const ts_gems_1 = require("ts-gems");
|
|
9
11
|
const valgen_1 = require("valgen");
|
|
10
|
-
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
11
|
-
const common_1 = require("@opra/common");
|
|
12
12
|
const constants_js_1 = require("../../constants.js");
|
|
13
13
|
const wrap_exception_js_1 = require("../utils/wrap-exception.js");
|
|
14
14
|
/**
|
|
@@ -64,7 +64,8 @@ class HttpHandler {
|
|
|
64
64
|
else
|
|
65
65
|
await this._executeRequest(context);
|
|
66
66
|
}
|
|
67
|
-
catch (
|
|
67
|
+
catch (error) {
|
|
68
|
+
let e = error;
|
|
68
69
|
if (e instanceof valgen_1.ValidationError) {
|
|
69
70
|
e = new common_1.InternalServerError({
|
|
70
71
|
message: (0, common_1.translate)('error:RESPONSE_VALIDATION,', 'Response validation failed'),
|
|
@@ -112,10 +113,10 @@ class HttpHandler {
|
|
|
112
113
|
*/
|
|
113
114
|
async _parseParameters(context) {
|
|
114
115
|
const { operation, request } = context;
|
|
115
|
-
let
|
|
116
|
+
let key = '';
|
|
116
117
|
try {
|
|
117
118
|
const onFail = (issue) => {
|
|
118
|
-
issue.location =
|
|
119
|
+
issue.location = key;
|
|
119
120
|
return issue;
|
|
120
121
|
};
|
|
121
122
|
/** prepare decoders */
|
|
@@ -130,9 +131,9 @@ class HttpHandler {
|
|
|
130
131
|
const paramsLeft = new Set([...operation.parameters, ...operation.owner.parameters]);
|
|
131
132
|
/** parse cookie parameters */
|
|
132
133
|
if (request.cookies) {
|
|
133
|
-
for (
|
|
134
|
-
const oprPrm = operation.findParameter(
|
|
135
|
-
const cntPrm = operation.owner.findParameter(
|
|
134
|
+
for (key of Object.keys(request.cookies)) {
|
|
135
|
+
const oprPrm = operation.findParameter(key, 'cookie');
|
|
136
|
+
const cntPrm = operation.owner.findParameter(key, 'cookie');
|
|
136
137
|
const prm = oprPrm || cntPrm;
|
|
137
138
|
if (!prm)
|
|
138
139
|
continue;
|
|
@@ -141,16 +142,17 @@ class HttpHandler {
|
|
|
141
142
|
if (cntPrm)
|
|
142
143
|
paramsLeft.delete(cntPrm);
|
|
143
144
|
const decode = getDecoder(prm);
|
|
144
|
-
const v = decode(request.cookies[
|
|
145
|
+
const v = decode(request.cookies[key], { coerce: true, label: key, onFail });
|
|
146
|
+
const prmName = typeof prm.name === 'string' ? prm.name : key;
|
|
145
147
|
if (v !== undefined)
|
|
146
148
|
context.cookies[prmName] = v;
|
|
147
149
|
}
|
|
148
150
|
}
|
|
149
151
|
/** parse headers */
|
|
150
152
|
if (request.headers) {
|
|
151
|
-
for (
|
|
152
|
-
const oprPrm = operation.findParameter(
|
|
153
|
-
const cntPrm = operation.owner.findParameter(
|
|
153
|
+
for (key of Object.keys(request.headers)) {
|
|
154
|
+
const oprPrm = operation.findParameter(key, 'header');
|
|
155
|
+
const cntPrm = operation.owner.findParameter(key, 'header');
|
|
154
156
|
const prm = oprPrm || cntPrm;
|
|
155
157
|
if (!prm)
|
|
156
158
|
continue;
|
|
@@ -159,16 +161,17 @@ class HttpHandler {
|
|
|
159
161
|
if (cntPrm)
|
|
160
162
|
paramsLeft.delete(cntPrm);
|
|
161
163
|
const decode = getDecoder(prm);
|
|
162
|
-
const v = decode(request.headers[
|
|
164
|
+
const v = decode(request.headers[key], { coerce: true, label: key, onFail });
|
|
165
|
+
const prmName = typeof prm.name === 'string' ? prm.name : key;
|
|
163
166
|
if (v !== undefined)
|
|
164
167
|
context.headers[prmName] = v;
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
/** parse path parameters */
|
|
168
171
|
if (request.params) {
|
|
169
|
-
for (
|
|
170
|
-
const oprPrm = operation.findParameter(
|
|
171
|
-
const cntPrm = operation.owner.findParameter(
|
|
172
|
+
for (key of Object.keys(request.params)) {
|
|
173
|
+
const oprPrm = operation.findParameter(key, 'path');
|
|
174
|
+
const cntPrm = operation.owner.findParameter(key, 'path');
|
|
172
175
|
const prm = oprPrm || cntPrm;
|
|
173
176
|
if (!prm)
|
|
174
177
|
continue;
|
|
@@ -177,17 +180,17 @@ class HttpHandler {
|
|
|
177
180
|
if (cntPrm)
|
|
178
181
|
paramsLeft.delete(cntPrm);
|
|
179
182
|
const decode = getDecoder(prm);
|
|
180
|
-
const v = decode(request.params[
|
|
183
|
+
const v = decode(request.params[key], { coerce: true, label: key, onFail });
|
|
181
184
|
if (v !== undefined)
|
|
182
|
-
context.pathParams[
|
|
185
|
+
context.pathParams[key] = v;
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
/** parse query parameters */
|
|
186
189
|
const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
|
|
187
190
|
const { searchParams } = url;
|
|
188
|
-
for (
|
|
189
|
-
const oprPrm = operation.findParameter(
|
|
190
|
-
const cntPrm = operation.owner.findParameter(
|
|
191
|
+
for (key of searchParams.keys()) {
|
|
192
|
+
const oprPrm = operation.findParameter(key, 'query');
|
|
193
|
+
const cntPrm = operation.owner.findParameter(key, 'query');
|
|
191
194
|
const prm = oprPrm || cntPrm;
|
|
192
195
|
if (!prm)
|
|
193
196
|
continue;
|
|
@@ -196,15 +199,16 @@ class HttpHandler {
|
|
|
196
199
|
if (cntPrm)
|
|
197
200
|
paramsLeft.delete(cntPrm);
|
|
198
201
|
const decode = getDecoder(prm);
|
|
199
|
-
let values = searchParams?.getAll(
|
|
202
|
+
let values = searchParams?.getAll(key);
|
|
203
|
+
const prmName = typeof prm.name === 'string' ? prm.name : key;
|
|
200
204
|
if (values?.length && prm.isArray) {
|
|
201
205
|
values = values.map(v => (0, fast_tokenizer_1.splitString)(v, { delimiters: prm.arraySeparator, quotes: true })).flat();
|
|
202
|
-
values = values.map(v => decode(v, { coerce: true, label:
|
|
206
|
+
values = values.map(v => decode(v, { coerce: true, label: key, onFail }));
|
|
203
207
|
if (values.length)
|
|
204
208
|
context.queryParams[prmName] = values;
|
|
205
209
|
}
|
|
206
210
|
else {
|
|
207
|
-
const v = decode(values[0], { coerce: true, label:
|
|
211
|
+
const v = decode(values[0], { coerce: true, label: key, onFail });
|
|
208
212
|
if (values.length)
|
|
209
213
|
context.queryParams[prmName] = v;
|
|
210
214
|
}
|
|
@@ -219,8 +223,8 @@ class HttpHandler {
|
|
|
219
223
|
}
|
|
220
224
|
catch (e) {
|
|
221
225
|
if (e instanceof valgen_1.ValidationError) {
|
|
222
|
-
|
|
223
|
-
message: `Invalid parameter (${
|
|
226
|
+
throw new common_1.BadRequestError({
|
|
227
|
+
message: `Invalid parameter (${key}) value. ` + e.message,
|
|
224
228
|
code: 'REQUEST_VALIDATION',
|
|
225
229
|
details: e.issues,
|
|
226
230
|
}, e);
|
|
@@ -240,9 +244,8 @@ class HttpHandler {
|
|
|
240
244
|
let contentType = request.header('content-type');
|
|
241
245
|
if (contentType) {
|
|
242
246
|
contentType = (0, content_type_1.parse)(contentType).type;
|
|
243
|
-
mediaType = operation.requestBody.content.find(mc =>
|
|
244
|
-
|
|
245
|
-
});
|
|
247
|
+
mediaType = operation.requestBody.content.find(mc => mc.contentType &&
|
|
248
|
+
type_is_1.default.is(contentType, Array.isArray(mc.contentType) ? mc.contentType : [mc.contentType]));
|
|
246
249
|
}
|
|
247
250
|
if (!mediaType) {
|
|
248
251
|
const contentTypes = operation.requestBody.content.map(mc => mc.contentType).flat();
|
|
@@ -261,11 +264,12 @@ class HttpHandler {
|
|
|
261
264
|
throw new common_1.MethodNotAllowedError();
|
|
262
265
|
const responseValue = await context.operationHandler.call(context.controllerInstance, context);
|
|
263
266
|
const { response } = context;
|
|
264
|
-
if (!response.writableEnded)
|
|
267
|
+
if (!response.writableEnded) {
|
|
265
268
|
await this._sendResponse(context, responseValue).finally(() => {
|
|
266
269
|
if (!response.writableEnded)
|
|
267
270
|
response.end();
|
|
268
271
|
});
|
|
272
|
+
}
|
|
269
273
|
}
|
|
270
274
|
/**
|
|
271
275
|
*
|
|
@@ -391,8 +395,9 @@ class HttpHandler {
|
|
|
391
395
|
/** Filter available HttpOperationResponse instances according to status code. */
|
|
392
396
|
const filteredResponses = operation.responses.filter(r => r.statusCode.find(sc => sc.start <= statusCode && sc.end >= statusCode));
|
|
393
397
|
/** Throw InternalServerError if controller returns non-configured status code */
|
|
394
|
-
if (!filteredResponses.length && statusCode < 400)
|
|
398
|
+
if (!filteredResponses.length && statusCode < 400) {
|
|
395
399
|
throw new common_1.InternalServerError(`No responses defined for status code ${statusCode} in operation "${operation.name}"`);
|
|
400
|
+
}
|
|
396
401
|
/** We search for content-type in filtered HttpOperationResponse array */
|
|
397
402
|
if (filteredResponses.length) {
|
|
398
403
|
/** If no response returned, and content-type has not been set (No response wants to be returned by operation) */
|
|
@@ -405,8 +410,9 @@ class HttpHandler {
|
|
|
405
410
|
if (contentType) {
|
|
406
411
|
// Find HttpEndpointResponse instance according to content-type header
|
|
407
412
|
operationResponse = filteredResponses.find(r => type_is_1.default.is(contentType, (0, valgen_1.toArray)(r.contentType)));
|
|
408
|
-
if (!operationResponse)
|
|
413
|
+
if (!operationResponse) {
|
|
409
414
|
throw new common_1.InternalServerError(`Operation didn't configured to return "${contentType}" content`);
|
|
415
|
+
}
|
|
410
416
|
}
|
|
411
417
|
else {
|
|
412
418
|
/** Select first HttpOperationResponse if content-type header has not been set */
|
|
@@ -438,23 +444,26 @@ class HttpHandler {
|
|
|
438
444
|
case 'Entity.Get':
|
|
439
445
|
case 'Entity.FindMany':
|
|
440
446
|
case 'Entity.Update': {
|
|
441
|
-
if (!(body instanceof common_1.OperationResult))
|
|
447
|
+
if (!(body instanceof common_1.OperationResult)) {
|
|
442
448
|
body = new common_1.OperationResult({
|
|
443
449
|
payload: body,
|
|
444
450
|
});
|
|
451
|
+
}
|
|
445
452
|
if ((composition === 'Entity.Create' || composition === 'Entity.Update') &&
|
|
446
453
|
composition &&
|
|
447
|
-
body.affected == null)
|
|
454
|
+
body.affected == null) {
|
|
448
455
|
body.affected = 1;
|
|
456
|
+
}
|
|
449
457
|
break;
|
|
450
458
|
}
|
|
451
459
|
case 'Entity.Delete':
|
|
452
460
|
case 'Entity.DeleteMany':
|
|
453
461
|
case 'Entity.UpdateMany': {
|
|
454
|
-
if (!(body instanceof common_1.OperationResult))
|
|
462
|
+
if (!(body instanceof common_1.OperationResult)) {
|
|
455
463
|
body = new common_1.OperationResult({
|
|
456
464
|
affected: body,
|
|
457
465
|
});
|
|
466
|
+
}
|
|
458
467
|
body.affected =
|
|
459
468
|
typeof body.affected === 'number'
|
|
460
469
|
? body.affected
|
|
@@ -465,15 +474,19 @@ class HttpHandler {
|
|
|
465
474
|
: undefined;
|
|
466
475
|
break;
|
|
467
476
|
}
|
|
477
|
+
default:
|
|
478
|
+
break;
|
|
468
479
|
}
|
|
469
480
|
}
|
|
470
|
-
if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type)
|
|
481
|
+
if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type) {
|
|
471
482
|
response.setHeader('content-type', responseArgs.contentType);
|
|
483
|
+
}
|
|
472
484
|
if (responseArgs.contentType &&
|
|
473
485
|
body != null &&
|
|
474
486
|
!(body instanceof common_1.OperationResult) &&
|
|
475
|
-
type_is_1.default.is(responseArgs.contentType, [common_1.MimeTypes.opra_response_json]))
|
|
487
|
+
type_is_1.default.is(responseArgs.contentType, [common_1.MimeTypes.opra_response_json])) {
|
|
476
488
|
body = new common_1.OperationResult({ payload: body });
|
|
489
|
+
}
|
|
477
490
|
if (hasBody)
|
|
478
491
|
responseArgs.body = body;
|
|
479
492
|
return responseArgs;
|
|
@@ -486,12 +499,13 @@ class HttpHandler {
|
|
|
486
499
|
const { searchParams } = url;
|
|
487
500
|
const documentId = searchParams.get('id');
|
|
488
501
|
const doc = documentId ? document.findDocument(documentId) : document;
|
|
489
|
-
if (!doc)
|
|
502
|
+
if (!doc) {
|
|
490
503
|
return this.sendErrorResponse(response, [
|
|
491
504
|
new common_1.BadRequestError({
|
|
492
505
|
message: `Document with given id [${documentId}] does not exists`,
|
|
493
506
|
}),
|
|
494
507
|
]);
|
|
508
|
+
}
|
|
495
509
|
/** Check if response cache exists */
|
|
496
510
|
let responseBody = this[constants_js_1.kAssetCache].get(doc, `$schema`);
|
|
497
511
|
/** Create response if response cache does not exists */
|
|
@@ -6,10 +6,10 @@ const tslib_1 = require("tslib");
|
|
|
6
6
|
Some parts of this file contains codes from open source express library
|
|
7
7
|
https://github.com/expressjs
|
|
8
8
|
*/
|
|
9
|
+
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
9
10
|
const accepts_1 = tslib_1.__importDefault(require("accepts"));
|
|
10
11
|
const fresh_1 = tslib_1.__importDefault(require("fresh"));
|
|
11
12
|
const range_parser_1 = tslib_1.__importDefault(require("range-parser"));
|
|
12
|
-
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
13
13
|
const body_reader_js_1 = require("../utils/body-reader.js");
|
|
14
14
|
class HttpIncomingHost {
|
|
15
15
|
get protocol() {
|
|
@@ -41,11 +41,11 @@ class HttpIncomingHost {
|
|
|
41
41
|
get fresh() {
|
|
42
42
|
const method = this.method;
|
|
43
43
|
// GET or HEAD for weak freshness validation only
|
|
44
|
-
if ('GET'
|
|
44
|
+
if (method !== 'GET' && method !== 'HEAD')
|
|
45
45
|
return false;
|
|
46
46
|
const status = this.res?.statusCode;
|
|
47
47
|
// 2xx or 304 as per rfc2616 14.26
|
|
48
|
-
if ((status >= 200 && status < 300) ||
|
|
48
|
+
if ((status >= 200 && status < 300) || status === 304) {
|
|
49
49
|
return (0, fresh_1.default)(this.headers, {
|
|
50
50
|
etag: this.res.getHeader('ETag'),
|
|
51
51
|
'last-modified': this.res.getHeader('Last-Modified'),
|
|
@@ -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 common_1 = require("@opra/common");
|
|
9
10
|
const content_disposition_1 = tslib_1.__importDefault(require("content-disposition"));
|
|
10
11
|
const content_type_1 = tslib_1.__importDefault(require("content-type"));
|
|
11
12
|
const cookie_1 = tslib_1.__importDefault(require("cookie"));
|
|
@@ -15,7 +16,6 @@ const mime_types_1 = tslib_1.__importDefault(require("mime-types"));
|
|
|
15
16
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
16
17
|
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
17
18
|
const vary_1 = tslib_1.__importDefault(require("vary"));
|
|
18
|
-
const common_1 = require("@opra/common");
|
|
19
19
|
const charsetRegExp = /;\s*charset\s*=/;
|
|
20
20
|
class HttpOutgoingHost {
|
|
21
21
|
attachment(filename) {
|
|
@@ -164,7 +164,7 @@ class HttpOutgoingHost {
|
|
|
164
164
|
if (req?.fresh)
|
|
165
165
|
this.statusCode = 304;
|
|
166
166
|
// strip irrelevant headers
|
|
167
|
-
if (
|
|
167
|
+
if (this.statusCode === 204 || this.statusCode === 304) {
|
|
168
168
|
this.removeHeader('Content-Type');
|
|
169
169
|
this.removeHeader('Content-Length');
|
|
170
170
|
this.removeHeader('Transfer-Encoding');
|
|
@@ -16,9 +16,7 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
16
16
|
this._incoming = incoming;
|
|
17
17
|
const form = (this._form = (0, formidable_1.default)({
|
|
18
18
|
...options,
|
|
19
|
-
filter: (part) =>
|
|
20
|
-
return !this._cancelled && (!options?.filter || options.filter(part));
|
|
21
|
-
},
|
|
19
|
+
filter: (part) => !this._cancelled && (!options?.filter || options.filter(part)),
|
|
22
20
|
}));
|
|
23
21
|
form.once('error', () => {
|
|
24
22
|
this._cancelled = true;
|
|
@@ -73,7 +71,7 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
73
71
|
}
|
|
74
72
|
resume() {
|
|
75
73
|
if (!this._started)
|
|
76
|
-
this._form.parse(this._incoming, () =>
|
|
74
|
+
this._form.parse(this._incoming, () => undefined);
|
|
77
75
|
if (this._form.req)
|
|
78
76
|
this._form.resume();
|
|
79
77
|
}
|
|
@@ -92,12 +90,8 @@ class MultipartReader extends events_1.EventEmitter {
|
|
|
92
90
|
return resolve();
|
|
93
91
|
file._writeStream.once('close', resolve);
|
|
94
92
|
})
|
|
95
|
-
.then(() =>
|
|
96
|
-
|
|
97
|
-
})
|
|
98
|
-
.then(() => {
|
|
99
|
-
return 0;
|
|
100
|
-
}));
|
|
93
|
+
.then(() => promises_1.default.unlink(file.filepath))
|
|
94
|
+
.then(() => 0));
|
|
101
95
|
});
|
|
102
96
|
return Promise.allSettled(promises);
|
|
103
97
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NodeIncomingMessageHost = exports.kHttpParser = exports.kTrailersDistinct = exports.kTrailers = exports.kHeadersDistinct = exports.kHeaders = exports.CRLF = void 0;
|
|
4
|
-
const stream_1 = require("stream");
|
|
5
4
|
const common_1 = require("@opra/common");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
6
|
const convert_to_headers_js_1 = require("../utils/convert-to-headers.js");
|
|
7
7
|
const convert_to_raw_headers_js_1 = require("../utils/convert-to-raw-headers.js");
|
|
8
8
|
exports.CRLF = Buffer.from('\r\n');
|
|
@@ -36,10 +36,12 @@ class NodeIncomingMessageHost extends stream_1.Duplex {
|
|
|
36
36
|
else
|
|
37
37
|
this.body = Buffer.from(JSON.stringify(init.body), 'utf-8');
|
|
38
38
|
}
|
|
39
|
-
if (init.headers)
|
|
39
|
+
if (init.headers) {
|
|
40
40
|
this.rawHeaders = Array.isArray(init.headers) ? init.headers : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.headers);
|
|
41
|
-
|
|
41
|
+
}
|
|
42
|
+
if (init.trailers) {
|
|
42
43
|
this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.trailers);
|
|
44
|
+
}
|
|
43
45
|
this.ip = init.ip || '';
|
|
44
46
|
this.ips = init.ips || (this.ip ? [this.ip] : []);
|
|
45
47
|
if (this.body && !this.headers['content-length'])
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NodeIncomingMessage = void 0;
|
|
4
|
-
const stream_1 = require("stream");
|
|
5
4
|
const http_parser_1 = require("@browsery/http-parser");
|
|
6
5
|
const common_1 = require("@opra/common");
|
|
6
|
+
const stream_1 = require("stream");
|
|
7
7
|
const node_incoming_message_host_js_1 = require("../impl/node-incoming-message.host.js");
|
|
8
8
|
const concat_readable_js_1 = require("../utils/concat-readable.js");
|
|
9
9
|
/**
|
|
@@ -17,8 +17,9 @@ var NodeIncomingMessage;
|
|
|
17
17
|
* @param iterable
|
|
18
18
|
*/
|
|
19
19
|
function from(iterable) {
|
|
20
|
-
if (typeof iterable === 'object' && !((0, common_1.isIterable)(iterable) || (0, common_1.isAsyncIterable)(iterable)))
|
|
20
|
+
if (typeof iterable === 'object' && !((0, common_1.isIterable)(iterable) || (0, common_1.isAsyncIterable)(iterable))) {
|
|
21
21
|
return new node_incoming_message_host_js_1.NodeIncomingMessageHost(iterable);
|
|
22
|
+
}
|
|
22
23
|
const msg = new node_incoming_message_host_js_1.NodeIncomingMessageHost();
|
|
23
24
|
const parser = (msg[node_incoming_message_host_js_1.kHttpParser] = new http_parser_1.HTTPParser(http_parser_1.HTTPParser.REQUEST));
|
|
24
25
|
let bodyChunks;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BodyReader = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
6
|
+
const common_1 = require("@opra/common");
|
|
5
7
|
const base64_stream_1 = require("base64-stream");
|
|
6
8
|
const bytes_1 = tslib_1.__importDefault(require("bytes"));
|
|
7
9
|
const content_type_1 = require("content-type");
|
|
@@ -9,8 +11,6 @@ const events_1 = require("events");
|
|
|
9
11
|
const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
|
|
10
12
|
const stream_1 = require("stream");
|
|
11
13
|
const zlib = tslib_1.__importStar(require("zlib"));
|
|
12
|
-
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
13
|
-
const common_1 = require("@opra/common");
|
|
14
14
|
/**
|
|
15
15
|
*
|
|
16
16
|
* @class BodyReader
|
|
@@ -33,11 +33,12 @@ class BodyReader extends events_1.EventEmitter {
|
|
|
33
33
|
}
|
|
34
34
|
async read() {
|
|
35
35
|
/* istanbul ignore next */
|
|
36
|
-
if (this._completed)
|
|
36
|
+
if (this._completed) {
|
|
37
37
|
throw new common_1.InternalServerError({
|
|
38
38
|
message: 'Stream already read',
|
|
39
39
|
code: 'STREAM_ALREADY_READ',
|
|
40
40
|
});
|
|
41
|
+
}
|
|
41
42
|
if (!this.req.readable) {
|
|
42
43
|
throw new common_1.InternalServerError({
|
|
43
44
|
message: 'Stream is not readable',
|
|
@@ -61,8 +62,9 @@ class BodyReader extends events_1.EventEmitter {
|
|
|
61
62
|
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
|
62
63
|
*/
|
|
63
64
|
const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
|
|
64
|
-
if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength)))
|
|
65
|
+
if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength))) {
|
|
65
66
|
return this.onEnd();
|
|
67
|
+
}
|
|
66
68
|
// check the length and limit options.
|
|
67
69
|
// note: we intentionally leave the stream paused,
|
|
68
70
|
// so users should handle the stream themselves.
|
package/cjs/http/utils/common.js
CHANGED
|
@@ -60,7 +60,8 @@ exports.validateHeaderValue = hideStackFrames((name, value) => {
|
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
function validateString(value, name) {
|
|
63
|
-
if (typeof value !== 'string')
|
|
63
|
+
if (typeof value !== 'string') {
|
|
64
64
|
throw new TypeError(`Invalid ${name ? name + ' ' : ''}argument. Value must be a string`);
|
|
65
|
+
}
|
|
65
66
|
}
|
|
66
67
|
exports.validateString = validateString;
|
package/cjs/index.js
CHANGED
|
@@ -10,20 +10,20 @@ const HttpOutgoingHost_ = tslib_1.__importStar(require("./http/impl/http-outgoin
|
|
|
10
10
|
const NodeIncomingMessageHost_ = tslib_1.__importStar(require("./http/impl/node-incoming-message.host.js"));
|
|
11
11
|
const NodeOutgoingMessageHost_ = tslib_1.__importStar(require("./http/impl/node-outgoing-message.host.js"));
|
|
12
12
|
tslib_1.__exportStar(require("./execution-context.js"), exports);
|
|
13
|
-
tslib_1.__exportStar(require("./platform-adapter.js"), exports);
|
|
14
|
-
tslib_1.__exportStar(require("./type-guards.js"), exports);
|
|
15
13
|
tslib_1.__exportStar(require("./helpers/logger.js"), exports);
|
|
16
14
|
tslib_1.__exportStar(require("./helpers/service-base.js"), exports);
|
|
17
15
|
tslib_1.__exportStar(require("./http/express-adapter.js"), exports);
|
|
18
16
|
tslib_1.__exportStar(require("./http/http-adapter.js"), exports);
|
|
19
17
|
tslib_1.__exportStar(require("./http/http-context.js"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./http/impl/multipart-reader.js"), exports);
|
|
20
19
|
tslib_1.__exportStar(require("./http/interfaces/http-incoming.interface.js"), exports);
|
|
21
20
|
tslib_1.__exportStar(require("./http/interfaces/http-outgoing.interface.js"), exports);
|
|
22
21
|
tslib_1.__exportStar(require("./http/interfaces/node-incoming-message.interface.js"), exports);
|
|
23
22
|
tslib_1.__exportStar(require("./http/interfaces/node-outgoing-message.interface.js"), exports);
|
|
24
|
-
tslib_1.__exportStar(require("./http/impl/multipart-reader.js"), exports);
|
|
25
23
|
tslib_1.__exportStar(require("./http/utils/wrap-exception.js"), exports);
|
|
26
24
|
tslib_1.__exportStar(require("./interfaces/logger.interface.js"), exports);
|
|
25
|
+
tslib_1.__exportStar(require("./platform-adapter.js"), exports);
|
|
26
|
+
tslib_1.__exportStar(require("./type-guards.js"), exports);
|
|
27
27
|
var classes;
|
|
28
28
|
(function (classes) {
|
|
29
29
|
classes.HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
|
package/cjs/platform-adapter.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PlatformAdapter = void 0;
|
|
4
4
|
require("./augmentation/18n.augmentation.js");
|
|
5
|
-
const strict_typed_events_1 = require("strict-typed-events");
|
|
6
5
|
const common_1 = require("@opra/common");
|
|
6
|
+
const strict_typed_events_1 = require("strict-typed-events");
|
|
7
7
|
const constants_js_1 = require("./constants.js");
|
|
8
8
|
const logger_js_1 = require("./helpers/logger.js");
|
|
9
9
|
const asset_cache_js_1 = require("./http/impl/asset-cache.js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { HttpApi, NotFoundError } from '@opra/common';
|
|
1
2
|
import { Router } from 'express';
|
|
2
3
|
import * as nodePath from 'path';
|
|
3
|
-
import { HttpApi, NotFoundError } from '@opra/common';
|
|
4
4
|
import { kHandler } from '../constants.js';
|
|
5
5
|
import { HttpAdapter } from './http-adapter.js';
|
|
6
6
|
import { HttpContext } from './http-context.js';
|
|
@@ -31,13 +31,14 @@ export class ExpressAdapter extends HttpAdapter {
|
|
|
31
31
|
}
|
|
32
32
|
if (resource.onShutdown) {
|
|
33
33
|
const instance = this._controllerInstances.get(resource) || resource.instance;
|
|
34
|
-
if (instance)
|
|
34
|
+
if (instance) {
|
|
35
35
|
try {
|
|
36
36
|
await resource.onShutdown.call(instance, resource);
|
|
37
37
|
}
|
|
38
38
|
catch (e) {
|
|
39
39
|
this.logger.error(e);
|
|
40
40
|
}
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
for (const c of this.api.controllers.values())
|
|
@@ -73,16 +74,9 @@ export class ExpressAdapter extends HttpAdapter {
|
|
|
73
74
|
});
|
|
74
75
|
};
|
|
75
76
|
/** Add an endpoint that returns document schema */
|
|
76
|
-
router.get('
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (url === '/$schema') {
|
|
80
|
-
const context = createContext(_req, _res);
|
|
81
|
-
this[kHandler].sendDocumentSchema(context).catch(next);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
next();
|
|
77
|
+
router.get('/\\$schema', (_req, _res, next) => {
|
|
78
|
+
const context = createContext(_req, _res);
|
|
79
|
+
this[kHandler].sendDocumentSchema(context).catch(next);
|
|
86
80
|
});
|
|
87
81
|
/** Add operation endpoints */
|
|
88
82
|
if (this.api.controllers.size) {
|