@opra/core 0.33.13 → 1.0.0-alpha.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 +17 -4
- package/cjs/augmentation/http-controller.augmentation.js +25 -0
- package/cjs/constants.js +5 -0
- package/cjs/execution-context.js +25 -12
- package/cjs/{services → helpers}/logger.js +1 -2
- package/cjs/{services/api-service.js → helpers/service-base.js} +8 -8
- package/cjs/http/express-adapter.js +164 -0
- package/cjs/http/http-adapter.js +27 -0
- package/cjs/http/http-context.js +116 -0
- package/cjs/http/impl/asset-cache.js +21 -0
- package/cjs/http/impl/http-handler.js +575 -0
- package/cjs/http/{http-server-request.js → impl/http-incoming.host.js} +21 -46
- package/cjs/http/{http-server-response.js → impl/http-outgoing.host.js} +7 -26
- package/cjs/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +24 -22
- package/cjs/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +13 -54
- package/cjs/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +11 -14
- package/cjs/http/interfaces/http-incoming.interface.js +25 -0
- package/cjs/http/interfaces/http-outgoing.interface.js +22 -0
- package/cjs/http/interfaces/node-incoming-message.interface.js +63 -0
- package/cjs/http/interfaces/node-outgoing-message.interface.js +15 -0
- package/cjs/http/utils/body-reader.js +215 -0
- package/cjs/http/{helpers → utils}/convert-to-raw-headers.js +1 -2
- package/cjs/http/{helpers → utils}/match-known-fields.js +11 -9
- package/cjs/http/utils/wrap-exception.js +34 -0
- package/cjs/index.js +25 -25
- package/cjs/platform-adapter.js +21 -0
- package/cjs/type-guards.js +23 -0
- package/esm/augmentation/18n.augmentation.js +20 -7
- package/esm/augmentation/http-controller.augmentation.js +23 -0
- package/esm/constants.js +2 -0
- package/esm/execution-context.js +25 -13
- package/esm/{services → helpers}/logger.js +1 -2
- package/esm/{services/api-service.js → helpers/service-base.js} +6 -6
- package/esm/http/express-adapter.js +159 -0
- package/esm/http/http-adapter.js +23 -0
- package/esm/http/http-context.js +111 -0
- package/esm/http/impl/asset-cache.js +17 -0
- package/esm/http/impl/http-handler.js +570 -0
- package/esm/http/{http-server-request.js → impl/http-incoming.host.js} +17 -43
- package/esm/http/{http-server-response.js → impl/http-outgoing.host.js} +6 -26
- package/esm/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +22 -20
- package/esm/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +11 -52
- package/esm/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +9 -12
- package/esm/http/interfaces/http-incoming.interface.js +22 -0
- package/esm/http/interfaces/http-outgoing.interface.js +19 -0
- package/esm/http/interfaces/node-incoming-message.interface.js +60 -0
- package/esm/http/interfaces/node-outgoing-message.interface.js +12 -0
- package/esm/http/utils/body-reader.js +210 -0
- package/esm/http/{helpers → utils}/convert-to-headers.js +1 -1
- package/esm/http/{helpers → utils}/convert-to-raw-headers.js +2 -3
- package/esm/http/{helpers → utils}/match-known-fields.js +11 -9
- package/esm/http/utils/wrap-exception.js +30 -0
- package/esm/index.js +25 -26
- package/esm/platform-adapter.js +19 -1
- package/esm/type-guards.js +16 -0
- package/package.json +22 -10
- package/types/augmentation/18n.augmentation.d.ts +32 -2
- package/types/augmentation/http-controller.augmentation.d.ts +21 -0
- package/types/constants.d.ts +2 -0
- package/types/execution-context.d.ts +24 -26
- package/types/helpers/service-base.d.ts +10 -0
- package/types/http/express-adapter.d.ts +13 -0
- package/types/http/http-adapter.d.ts +27 -0
- package/types/http/http-context.d.ts +44 -0
- package/types/http/impl/asset-cache.d.ts +5 -0
- package/types/http/impl/http-handler.d.ts +73 -0
- package/types/http/impl/http-incoming.host.d.ts +23 -0
- package/types/http/impl/http-outgoing.host.d.ts +17 -0
- package/types/http/{helpers/multipart-helper.d.ts → impl/multipart-reader.d.ts} +8 -6
- package/types/http/impl/{http-incoming-message.host.d.ts → node-incoming-message.host.d.ts} +9 -22
- package/types/http/impl/{http-outgoing-message.host.d.ts → node-outgoing-message.host.d.ts} +11 -27
- package/types/http/{http-server-request.d.ts → interfaces/http-incoming.interface.d.ts} +28 -17
- package/types/http/{http-server-response.d.ts → interfaces/http-outgoing.interface.d.ts} +17 -10
- package/types/http/interfaces/node-incoming-message.interface.d.ts +38 -0
- package/types/http/interfaces/node-outgoing-message.interface.d.ts +29 -0
- package/types/http/utils/body-reader.d.ts +41 -0
- package/types/http/utils/wrap-exception.d.ts +2 -0
- package/types/index.d.ts +24 -26
- package/types/platform-adapter.d.ts +20 -48
- package/types/type-guards.d.ts +8 -0
- package/cjs/augmentation/collection.augmentation.js +0 -2
- package/cjs/augmentation/container.augmentation.js +0 -2
- package/cjs/augmentation/resource.augmentation.js +0 -26
- package/cjs/augmentation/singleton.augmentation.js +0 -2
- package/cjs/augmentation/storage.augmentation.js +0 -2
- package/cjs/execution-context.host.js +0 -46
- package/cjs/http/adapters/express-adapter.host.js +0 -34
- package/cjs/http/adapters/express-adapter.js +0 -14
- package/cjs/http/adapters/node-http-adapter.host.js +0 -70
- package/cjs/http/adapters/node-http-adapter.js +0 -14
- package/cjs/http/helpers/json-body-loader.js +0 -29
- package/cjs/http/helpers/query-parsers.js +0 -16
- package/cjs/http/http-adapter-host.js +0 -715
- package/cjs/interfaces/interceptor.interface.js +0 -2
- package/cjs/interfaces/request-handler.interface.js +0 -2
- package/cjs/platform-adapter.host.js +0 -154
- package/cjs/request-context.js +0 -25
- package/cjs/request.host.js +0 -24
- package/cjs/request.js +0 -2
- package/cjs/response.host.js +0 -22
- package/cjs/response.js +0 -2
- package/esm/augmentation/collection.augmentation.js +0 -1
- package/esm/augmentation/container.augmentation.js +0 -1
- package/esm/augmentation/resource.augmentation.js +0 -24
- package/esm/augmentation/singleton.augmentation.js +0 -1
- package/esm/augmentation/storage.augmentation.js +0 -1
- package/esm/execution-context.host.js +0 -42
- package/esm/http/adapters/express-adapter.host.js +0 -30
- package/esm/http/adapters/express-adapter.js +0 -11
- package/esm/http/adapters/node-http-adapter.host.js +0 -65
- package/esm/http/adapters/node-http-adapter.js +0 -11
- package/esm/http/helpers/json-body-loader.js +0 -24
- package/esm/http/helpers/query-parsers.js +0 -12
- package/esm/http/http-adapter-host.js +0 -710
- package/esm/interfaces/interceptor.interface.js +0 -1
- package/esm/interfaces/request-handler.interface.js +0 -1
- package/esm/platform-adapter.host.js +0 -149
- package/esm/request-context.js +0 -22
- package/esm/request.host.js +0 -20
- package/esm/request.js +0 -1
- package/esm/response.host.js +0 -18
- package/esm/response.js +0 -1
- package/i18n/i18n/en/error.json +0 -21
- package/types/augmentation/collection.augmentation.d.ts +0 -146
- package/types/augmentation/container.augmentation.d.ts +0 -14
- package/types/augmentation/resource.augmentation.d.ts +0 -38
- package/types/augmentation/singleton.augmentation.d.ts +0 -83
- package/types/augmentation/storage.augmentation.d.ts +0 -50
- package/types/execution-context.host.d.ts +0 -25
- package/types/http/adapters/express-adapter.d.ts +0 -15
- package/types/http/adapters/express-adapter.host.d.ts +0 -12
- package/types/http/adapters/node-http-adapter.d.ts +0 -17
- package/types/http/adapters/node-http-adapter.host.d.ts +0 -19
- package/types/http/helpers/json-body-loader.d.ts +0 -5
- package/types/http/helpers/query-parsers.d.ts +0 -1
- package/types/http/http-adapter-host.d.ts +0 -34
- package/types/interfaces/interceptor.interface.d.ts +0 -2
- package/types/interfaces/request-handler.interface.d.ts +0 -4
- package/types/platform-adapter.host.d.ts +0 -43
- package/types/request-context.d.ts +0 -13
- package/types/request.d.ts +0 -14
- package/types/request.host.d.ts +0 -27
- package/types/response.d.ts +0 -22
- package/types/response.host.d.ts +0 -22
- package/types/services/api-service.d.ts +0 -10
- /package/cjs/http/{helpers → utils}/common.js +0 -0
- /package/cjs/http/{helpers → utils}/concat-readable.js +0 -0
- /package/cjs/http/{helpers → utils}/convert-to-headers.js +0 -0
- /package/esm/http/{helpers → utils}/common.js +0 -0
- /package/esm/http/{helpers → utils}/concat-readable.js +0 -0
- /package/types/{services → helpers}/logger.d.ts +0 -0
- /package/types/http/{helpers → utils}/common.d.ts +0 -0
- /package/types/http/{helpers → utils}/concat-readable.d.ts +0 -0
- /package/types/http/{helpers → utils}/convert-to-headers.d.ts +0 -0
- /package/types/http/{helpers → utils}/convert-to-raw-headers.d.ts +0 -0
- /package/types/http/{helpers → utils}/match-known-fields.d.ts +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BodyReader = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const base64_stream_1 = require("base64-stream");
|
|
6
|
+
const bytes_1 = tslib_1.__importDefault(require("bytes"));
|
|
7
|
+
const content_type_1 = require("content-type");
|
|
8
|
+
const events_1 = require("events");
|
|
9
|
+
const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
|
|
10
|
+
const stream_1 = require("stream");
|
|
11
|
+
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
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @class BodyReader
|
|
17
|
+
*/
|
|
18
|
+
class BodyReader extends events_1.EventEmitter {
|
|
19
|
+
constructor(req, options) {
|
|
20
|
+
super();
|
|
21
|
+
this.req = req;
|
|
22
|
+
this._completed = false;
|
|
23
|
+
this._receivedSize = 0;
|
|
24
|
+
this.onAborted = () => this._onAborted();
|
|
25
|
+
this.onData = (chunk) => this._onData(chunk);
|
|
26
|
+
this.onEnd = (err) => this._onEnd(err);
|
|
27
|
+
this.cleanup = () => this._cleanup();
|
|
28
|
+
this.limit = options?.limit
|
|
29
|
+
? typeof options.limit === 'number'
|
|
30
|
+
? options.limit
|
|
31
|
+
: (0, bytes_1.default)(options.limit)
|
|
32
|
+
: undefined;
|
|
33
|
+
}
|
|
34
|
+
async read() {
|
|
35
|
+
/* istanbul ignore next */
|
|
36
|
+
if (this._completed)
|
|
37
|
+
throw new common_1.InternalServerError({
|
|
38
|
+
message: 'Stream already read',
|
|
39
|
+
code: 'STREAM_ALREADY_READ',
|
|
40
|
+
});
|
|
41
|
+
if (!this.req.readable) {
|
|
42
|
+
throw new common_1.InternalServerError({
|
|
43
|
+
message: 'Stream is not readable',
|
|
44
|
+
code: 'STREAM_NOT_READABLE',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
// eslint-disable-next-line prefer-const
|
|
49
|
+
let sizeStream;
|
|
50
|
+
this.once('finish', (error, data) => {
|
|
51
|
+
if (sizeStream)
|
|
52
|
+
this.req.unpipe(sizeStream);
|
|
53
|
+
if (error)
|
|
54
|
+
return reject(error);
|
|
55
|
+
resolve(data);
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Check if a request has a request body.
|
|
59
|
+
* A request with a body __must__ either have `transfer-encoding`
|
|
60
|
+
* or `content-length` headers set.
|
|
61
|
+
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
|
62
|
+
*/
|
|
63
|
+
const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
|
|
64
|
+
if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength)))
|
|
65
|
+
return this.onEnd();
|
|
66
|
+
// check the length and limit options.
|
|
67
|
+
// note: we intentionally leave the stream paused,
|
|
68
|
+
// so users should handle the stream themselves.
|
|
69
|
+
if (this.limit != null && contentLength != null && contentLength > this.limit) {
|
|
70
|
+
return this.onEnd(new common_1.OpraHttpError({
|
|
71
|
+
message: 'Content Too Large',
|
|
72
|
+
code: 'HTTP.CONTENT_TOO_LARGE',
|
|
73
|
+
details: {
|
|
74
|
+
length: contentLength,
|
|
75
|
+
limit: this.limit,
|
|
76
|
+
},
|
|
77
|
+
}, 413));
|
|
78
|
+
}
|
|
79
|
+
// Pipe to a Writable stream to count received bytes
|
|
80
|
+
const _this = this;
|
|
81
|
+
sizeStream = new stream_1.Writable({
|
|
82
|
+
write(chunk, encoding, callback) {
|
|
83
|
+
if (_this._completed)
|
|
84
|
+
return;
|
|
85
|
+
_this._receivedSize += chunk.length;
|
|
86
|
+
if (_this.limit != null && _this._receivedSize > _this.limit) {
|
|
87
|
+
callback(new common_1.OpraHttpError({
|
|
88
|
+
message: 'Content Too Large',
|
|
89
|
+
code: 'HTTP.CONTENT_TOO_LARGE',
|
|
90
|
+
details: {
|
|
91
|
+
limit: _this.limit,
|
|
92
|
+
received: _this._receivedSize,
|
|
93
|
+
},
|
|
94
|
+
}, 413));
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
this.req.pipe(sizeStream);
|
|
99
|
+
let stream = BodyReader.encoderPipeline(this.req);
|
|
100
|
+
const mediaType = (0, content_type_1.parse)(this.req.headers['content-type'] || '');
|
|
101
|
+
let charset = (mediaType.parameters.charset || '').toLowerCase();
|
|
102
|
+
if (!charset && type_is_1.default.is(mediaType.type, ['json', 'xml', 'txt']))
|
|
103
|
+
charset = 'utf-8';
|
|
104
|
+
if (charset) {
|
|
105
|
+
const newStream = iconv_lite_1.default.decodeStream(charset);
|
|
106
|
+
stream.pipe(newStream);
|
|
107
|
+
stream = newStream;
|
|
108
|
+
}
|
|
109
|
+
this._stream = stream;
|
|
110
|
+
// attach listeners
|
|
111
|
+
stream.on('aborted', this.onAborted);
|
|
112
|
+
stream.on('close', this.cleanup);
|
|
113
|
+
stream.on('data', this.onData);
|
|
114
|
+
stream.on('end', this.onEnd);
|
|
115
|
+
stream.on('error', this.onEnd);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
_onEnd(error) {
|
|
119
|
+
if (this._completed)
|
|
120
|
+
return;
|
|
121
|
+
this._completed = true;
|
|
122
|
+
if (error) {
|
|
123
|
+
this._stream?.unpipe();
|
|
124
|
+
this._stream?.pause();
|
|
125
|
+
}
|
|
126
|
+
if (error)
|
|
127
|
+
this.emit('finish', error);
|
|
128
|
+
else if (Array.isArray(this._buffer))
|
|
129
|
+
this.emit('finish', error, Buffer.concat(this._buffer));
|
|
130
|
+
else
|
|
131
|
+
this.emit('finish', error, this._buffer);
|
|
132
|
+
this._cleanup();
|
|
133
|
+
}
|
|
134
|
+
_cleanup() {
|
|
135
|
+
if (this._stream) {
|
|
136
|
+
this._stream.removeListener('aborted', this.onAborted);
|
|
137
|
+
this._stream.removeListener('close', this.cleanup);
|
|
138
|
+
this._stream.removeListener('data', this.onData);
|
|
139
|
+
this._stream.removeListener('end', this.onEnd);
|
|
140
|
+
this._stream.removeListener('error', this.onEnd);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
_onAborted() {
|
|
144
|
+
if (this._completed)
|
|
145
|
+
return;
|
|
146
|
+
this.onEnd(new common_1.BadRequestError({
|
|
147
|
+
message: 'request aborted',
|
|
148
|
+
code: 'ECONNABORTED',
|
|
149
|
+
details: {
|
|
150
|
+
length,
|
|
151
|
+
received: this._receivedSize,
|
|
152
|
+
},
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
_onData(chunk) {
|
|
156
|
+
if (this._completed)
|
|
157
|
+
return;
|
|
158
|
+
if (typeof chunk === 'string') {
|
|
159
|
+
this._buffer = this._buffer || '';
|
|
160
|
+
this._buffer += chunk;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this._buffer = this._buffer || [];
|
|
164
|
+
this._buffer.push(chunk);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
static async read(req, options) {
|
|
168
|
+
const bodyReady = new BodyReader(req, options);
|
|
169
|
+
return bodyReady.read();
|
|
170
|
+
}
|
|
171
|
+
static encoderPipeline(req) {
|
|
172
|
+
const contentEncoding = req.headers['content-encoding'] || 'identity';
|
|
173
|
+
const contentEncodings = (Array.isArray(contentEncoding) ? contentEncoding : contentEncoding.split(/\s*,\s*/))
|
|
174
|
+
.map(s => s.toLowerCase())
|
|
175
|
+
.reverse();
|
|
176
|
+
return contentEncodings.reduce((prev, encoding) => {
|
|
177
|
+
switch (encoding) {
|
|
178
|
+
case 'gzip':
|
|
179
|
+
case 'x-gzip': {
|
|
180
|
+
const newStream = zlib.createGunzip();
|
|
181
|
+
prev.pipe(newStream);
|
|
182
|
+
return newStream;
|
|
183
|
+
}
|
|
184
|
+
case 'deflate':
|
|
185
|
+
case 'x-deflate': {
|
|
186
|
+
const newStream = zlib.createInflate();
|
|
187
|
+
prev.pipe(newStream);
|
|
188
|
+
return newStream;
|
|
189
|
+
}
|
|
190
|
+
case 'br': {
|
|
191
|
+
const newStream = zlib.createBrotliDecompress();
|
|
192
|
+
prev.pipe(newStream);
|
|
193
|
+
return newStream;
|
|
194
|
+
}
|
|
195
|
+
case 'base64': {
|
|
196
|
+
const newStream = new base64_stream_1.Base64Decode();
|
|
197
|
+
prev.pipe(newStream);
|
|
198
|
+
return newStream;
|
|
199
|
+
}
|
|
200
|
+
case 'identity':
|
|
201
|
+
// prev.length = 0;
|
|
202
|
+
return prev;
|
|
203
|
+
default:
|
|
204
|
+
throw new common_1.BadRequestError({
|
|
205
|
+
message: 'unsupported content encoding "' + encoding + '"',
|
|
206
|
+
code: '',
|
|
207
|
+
details: {
|
|
208
|
+
encoding,
|
|
209
|
+
},
|
|
210
|
+
}, 415);
|
|
211
|
+
}
|
|
212
|
+
}, req);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
exports.BodyReader = BodyReader;
|
|
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.convertToRawHeaders = void 0;
|
|
4
4
|
const match_known_fields_js_1 = require("./match-known-fields.js");
|
|
5
5
|
function convertToRawHeaders(src) {
|
|
6
|
-
return Object.entries(src)
|
|
7
|
-
.reduce((a, [field, v]) => {
|
|
6
|
+
return Object.entries(src).reduce((a, [field, v]) => {
|
|
8
7
|
const [name, flag] = (0, match_known_fields_js_1.matchKnownFields)(field);
|
|
9
8
|
if (flag === match_known_fields_js_1.ARRAY_FIELD) {
|
|
10
9
|
if (Array.isArray(v))
|
|
@@ -6,9 +6,7 @@ exports.NO_DUPLICATES_FIELD = 0;
|
|
|
6
6
|
exports.COMMA_DELIMITED_FIELD = 1;
|
|
7
7
|
exports.SEMICOLON_DELIMITED_FIELD = 2;
|
|
8
8
|
exports.ARRAY_FIELD = 3;
|
|
9
|
-
const ARRAY_HEADERS = [
|
|
10
|
-
'set-cookie'
|
|
11
|
-
];
|
|
9
|
+
const ARRAY_HEADERS = ['set-cookie'];
|
|
12
10
|
const NO_DUPLICATES_HEADERS = [
|
|
13
11
|
'age',
|
|
14
12
|
'from',
|
|
@@ -30,13 +28,17 @@ const NO_DUPLICATES_HEADERS = [
|
|
|
30
28
|
'if-unmodified-since',
|
|
31
29
|
];
|
|
32
30
|
const SEMICOLON_DELIMITED_HEADERS = ['cookie'];
|
|
33
|
-
const KNOWN_FIELDS = Object.values(common_1.HttpHeaderCodes)
|
|
34
|
-
.reduce((o, k) => {
|
|
31
|
+
const KNOWN_FIELDS = Object.values(common_1.HttpHeaderCodes).reduce((o, k) => {
|
|
35
32
|
const n = k.toLowerCase();
|
|
36
|
-
o[n] = [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
o[n] = [
|
|
34
|
+
k,
|
|
35
|
+
NO_DUPLICATES_HEADERS.includes(n)
|
|
36
|
+
? exports.NO_DUPLICATES_FIELD
|
|
37
|
+
: ARRAY_HEADERS.includes(n)
|
|
38
|
+
? exports.ARRAY_FIELD
|
|
39
|
+
: SEMICOLON_DELIMITED_HEADERS.includes(n)
|
|
40
|
+
? exports.SEMICOLON_DELIMITED_FIELD
|
|
41
|
+
: exports.COMMA_DELIMITED_FIELD,
|
|
40
42
|
];
|
|
41
43
|
return o;
|
|
42
44
|
}, {});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapException = void 0;
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
5
|
+
function wrapException(error) {
|
|
6
|
+
if (error instanceof common_1.OpraHttpError)
|
|
7
|
+
return error;
|
|
8
|
+
let status = 500;
|
|
9
|
+
if (typeof error.status === 'number')
|
|
10
|
+
status = error.status;
|
|
11
|
+
else if (typeof error.getStatus === 'function')
|
|
12
|
+
status = error.getStatus();
|
|
13
|
+
switch (status) {
|
|
14
|
+
case 400:
|
|
15
|
+
return new common_1.BadRequestError(error);
|
|
16
|
+
case 401:
|
|
17
|
+
return new common_1.UnauthorizedError(error);
|
|
18
|
+
case 403:
|
|
19
|
+
return new common_1.ForbiddenError(error);
|
|
20
|
+
case 404:
|
|
21
|
+
return new common_1.NotFoundError(error);
|
|
22
|
+
case 405:
|
|
23
|
+
return new common_1.MethodNotAllowedError(error);
|
|
24
|
+
case 406:
|
|
25
|
+
return new common_1.NotAcceptableError(error);
|
|
26
|
+
case 422:
|
|
27
|
+
return new common_1.UnprocessableEntityError(error);
|
|
28
|
+
case 424:
|
|
29
|
+
return new common_1.FailedDependencyError(error);
|
|
30
|
+
default:
|
|
31
|
+
return new common_1.InternalServerError(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.wrapException = wrapException;
|
package/cjs/index.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classes = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
4
5
|
require("reflect-metadata");
|
|
5
6
|
require("./augmentation/18n.augmentation.js");
|
|
6
|
-
require("./augmentation/
|
|
7
|
-
require("./
|
|
8
|
-
require("./
|
|
9
|
-
require("./
|
|
10
|
-
require("./
|
|
7
|
+
require("./augmentation/http-controller.augmentation.js");
|
|
8
|
+
const HttpIncomingHost_ = tslib_1.__importStar(require("./http/impl/http-incoming.host.js"));
|
|
9
|
+
const HttpOutgoingHost_ = tslib_1.__importStar(require("./http/impl/http-outgoing.host.js"));
|
|
10
|
+
const NodeIncomingMessageHost_ = tslib_1.__importStar(require("./http/impl/node-incoming-message.host.js"));
|
|
11
|
+
const NodeOutgoingMessageHost_ = tslib_1.__importStar(require("./http/impl/node-outgoing-message.host.js"));
|
|
11
12
|
tslib_1.__exportStar(require("./execution-context.js"), exports);
|
|
12
|
-
tslib_1.__exportStar(require("./execution-context.host.js"), exports);
|
|
13
13
|
tslib_1.__exportStar(require("./platform-adapter.js"), exports);
|
|
14
|
-
tslib_1.__exportStar(require("./
|
|
15
|
-
tslib_1.__exportStar(require("./
|
|
16
|
-
tslib_1.__exportStar(require("./
|
|
17
|
-
tslib_1.__exportStar(require("./
|
|
18
|
-
tslib_1.__exportStar(require("./
|
|
19
|
-
tslib_1.__exportStar(require("./
|
|
20
|
-
tslib_1.__exportStar(require("./http/
|
|
21
|
-
tslib_1.__exportStar(require("./http/
|
|
22
|
-
tslib_1.__exportStar(require("./http/
|
|
23
|
-
tslib_1.__exportStar(require("./http/
|
|
24
|
-
tslib_1.__exportStar(require("./http/impl/
|
|
25
|
-
tslib_1.__exportStar(require("./http/
|
|
26
|
-
tslib_1.__exportStar(require("./http/http-server-request.js"), exports);
|
|
27
|
-
tslib_1.__exportStar(require("./http/http-server-response.js"), exports);
|
|
28
|
-
tslib_1.__exportStar(require("./http/helpers/multipart-helper.js"), exports);
|
|
29
|
-
tslib_1.__exportStar(require("./interfaces/interceptor.interface.js"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./type-guards.js"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./helpers/logger.js"), exports);
|
|
16
|
+
tslib_1.__exportStar(require("./helpers/service-base.js"), exports);
|
|
17
|
+
tslib_1.__exportStar(require("./http/express-adapter.js"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./http/http-adapter.js"), exports);
|
|
19
|
+
tslib_1.__exportStar(require("./http/http-context.js"), exports);
|
|
20
|
+
tslib_1.__exportStar(require("./http/interfaces/http-incoming.interface.js"), exports);
|
|
21
|
+
tslib_1.__exportStar(require("./http/interfaces/http-outgoing.interface.js"), exports);
|
|
22
|
+
tslib_1.__exportStar(require("./http/interfaces/node-incoming-message.interface.js"), exports);
|
|
23
|
+
tslib_1.__exportStar(require("./http/interfaces/node-outgoing-message.interface.js"), exports);
|
|
24
|
+
tslib_1.__exportStar(require("./http/impl/multipart-reader.js"), exports);
|
|
25
|
+
tslib_1.__exportStar(require("./http/utils/wrap-exception.js"), exports);
|
|
30
26
|
tslib_1.__exportStar(require("./interfaces/logger.interface.js"), exports);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
var classes;
|
|
28
|
+
(function (classes) {
|
|
29
|
+
classes.HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
|
|
30
|
+
classes.HttpOutgoingHost = HttpOutgoingHost_.HttpOutgoingHost;
|
|
31
|
+
classes.NodeIncomingMessageHost = NodeIncomingMessageHost_.NodeIncomingMessageHost;
|
|
32
|
+
classes.NodeOutgoingMessageHost = NodeOutgoingMessageHost_.NodeOutgoingMessageHost;
|
|
33
|
+
})(classes || (exports.classes = classes = {}));
|
package/cjs/platform-adapter.js
CHANGED
|
@@ -1,2 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PlatformAdapter = void 0;
|
|
4
|
+
require("./augmentation/18n.augmentation.js");
|
|
5
|
+
const strict_typed_events_1 = require("strict-typed-events");
|
|
6
|
+
const common_1 = require("@opra/common");
|
|
7
|
+
const constants_js_1 = require("./constants.js");
|
|
8
|
+
const logger_js_1 = require("./helpers/logger.js");
|
|
9
|
+
const asset_cache_js_1 = require("./http/impl/asset-cache.js");
|
|
10
|
+
/**
|
|
11
|
+
* @class PlatformAdapter
|
|
12
|
+
*/
|
|
13
|
+
class PlatformAdapter extends strict_typed_events_1.AsyncEventEmitter {
|
|
14
|
+
constructor(document, options) {
|
|
15
|
+
super();
|
|
16
|
+
this[constants_js_1.kAssetCache] = new asset_cache_js_1.AssetCache();
|
|
17
|
+
this.document = document;
|
|
18
|
+
this.logger =
|
|
19
|
+
options?.logger && options.logger instanceof logger_js_1.Logger ? options.logger : new logger_js_1.Logger({ instance: options?.logger });
|
|
20
|
+
this.i18n = options?.i18n || common_1.I18n.defaultInstance;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.PlatformAdapter = PlatformAdapter;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isHttpOutgoing = exports.isNodeOutgoingMessage = exports.isHttpIncoming = exports.isNodeIncomingMessage = void 0;
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
5
|
+
function isNodeIncomingMessage(v) {
|
|
6
|
+
return v && typeof v.method === 'string' && Array.isArray(v.rawHeaders) && (0, common_1.isReadable)(v);
|
|
7
|
+
}
|
|
8
|
+
exports.isNodeIncomingMessage = isNodeIncomingMessage;
|
|
9
|
+
function isHttpIncoming(v) {
|
|
10
|
+
return (isNodeIncomingMessage(v) &&
|
|
11
|
+
typeof v.header === 'function' &&
|
|
12
|
+
typeof v.acceptsLanguages === 'function' &&
|
|
13
|
+
typeof v.readBody === 'function');
|
|
14
|
+
}
|
|
15
|
+
exports.isHttpIncoming = isHttpIncoming;
|
|
16
|
+
function isNodeOutgoingMessage(v) {
|
|
17
|
+
return v && typeof v.getHeaders === 'function' && (0, common_1.isStream)(v);
|
|
18
|
+
}
|
|
19
|
+
exports.isNodeOutgoingMessage = isNodeOutgoingMessage;
|
|
20
|
+
function isHttpOutgoing(v) {
|
|
21
|
+
return isNodeOutgoingMessage(v) && typeof v.clearCookie === 'function' && typeof v.cookie === 'function';
|
|
22
|
+
}
|
|
23
|
+
exports.isHttpOutgoing = isHttpOutgoing;
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { getStackFileName, I18n as I18n_ } from '@opra/common';
|
|
4
|
+
I18n_.load = async function (options) {
|
|
5
|
+
const opts = {
|
|
6
|
+
...options,
|
|
7
|
+
};
|
|
8
|
+
delete opts.resourceDirs;
|
|
9
|
+
const instance = I18n_.createInstance(opts);
|
|
10
|
+
await instance.init();
|
|
11
|
+
await instance.loadResourceDir(path.resolve(getStackFileName(), '../../../i18n'));
|
|
12
|
+
if (options?.resourceDirs)
|
|
13
|
+
for (const dir of options.resourceDirs)
|
|
14
|
+
await instance.loadResourceDir(dir);
|
|
15
|
+
return instance;
|
|
16
|
+
};
|
|
17
|
+
I18n_.prototype.loadResourceBundle = async function (lang, ns, filePath, deep, overwrite) {
|
|
5
18
|
let obj;
|
|
6
|
-
if (
|
|
19
|
+
if (URL.canParse(filePath)) {
|
|
7
20
|
obj = (await fetch(filePath, { headers: { accept: 'application/json' } })).json();
|
|
8
21
|
}
|
|
9
22
|
else {
|
|
@@ -12,20 +25,20 @@ I18n.prototype.loadResourceBundle = async function (lang, ns, filePath, deep, ov
|
|
|
12
25
|
}
|
|
13
26
|
this.addResourceBundle(lang, ns, obj, deep, overwrite);
|
|
14
27
|
};
|
|
15
|
-
|
|
28
|
+
I18n_.prototype.loadResourceDir = async function (dirnames, deep, overwrite) {
|
|
16
29
|
for (const dirname of Array.isArray(dirnames) ? dirnames : [dirnames]) {
|
|
17
30
|
/* istanbul ignore next */
|
|
18
|
-
if (!
|
|
31
|
+
if (!fs.existsSync(dirname))
|
|
19
32
|
continue;
|
|
20
33
|
const languageDirs = fs.readdirSync(dirname);
|
|
21
34
|
for (const lang of languageDirs) {
|
|
22
35
|
const langDir = path.join(dirname, lang);
|
|
23
|
-
if (
|
|
36
|
+
if (fs.statSync(langDir).isDirectory()) {
|
|
24
37
|
const nsDirs = fs.readdirSync(langDir);
|
|
25
38
|
for (const nsfile of nsDirs) {
|
|
26
39
|
const nsFilePath = path.join(langDir, nsfile);
|
|
27
40
|
const ext = path.extname(nsfile);
|
|
28
|
-
if (ext === '.json' &&
|
|
41
|
+
if (ext === '.json' && fs.statSync(nsFilePath).isFile()) {
|
|
29
42
|
const ns = path.basename(nsfile, ext);
|
|
30
43
|
await this.loadResourceBundle(lang, ns, nsFilePath, deep, overwrite);
|
|
31
44
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HTTP_CONTROLLER_METADATA, HttpController } from '@opra/common';
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
const oldInitialize = HttpController.prototype._initialize;
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
HttpController.prototype._initialize = function (initArgs) {
|
|
6
|
+
oldInitialize?.call(this, initArgs);
|
|
7
|
+
this.onInit = initArgs.onInit;
|
|
8
|
+
this.onShutdown = initArgs.onShutdown;
|
|
9
|
+
};
|
|
10
|
+
HttpController.OnInit = function () {
|
|
11
|
+
return (target, propertyKey) => {
|
|
12
|
+
const sourceMetadata = (Reflect.getOwnMetadata(HTTP_CONTROLLER_METADATA, target.constructor) || {});
|
|
13
|
+
sourceMetadata.onInit = target[propertyKey];
|
|
14
|
+
Reflect.defineMetadata(HTTP_CONTROLLER_METADATA, target.constructor, sourceMetadata);
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
HttpController.OnShutdown = function () {
|
|
18
|
+
return (target, propertyKey) => {
|
|
19
|
+
const sourceMetadata = (Reflect.getOwnMetadata(HTTP_CONTROLLER_METADATA, target.constructor) || {});
|
|
20
|
+
sourceMetadata.onShutdown = target[propertyKey];
|
|
21
|
+
Reflect.defineMetadata(HTTP_CONTROLLER_METADATA, target.constructor, sourceMetadata);
|
|
22
|
+
};
|
|
23
|
+
};
|
package/esm/constants.js
ADDED
package/esm/execution-context.js
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
|
+
/**
|
|
3
|
+
* @class ExecutionContext
|
|
4
|
+
*/
|
|
5
|
+
export class ExecutionContext extends AsyncEventEmitter {
|
|
6
|
+
constructor(init) {
|
|
7
|
+
super();
|
|
8
|
+
this.document = init.document;
|
|
9
|
+
this.protocol = init.protocol;
|
|
10
|
+
this.platform = init.platform;
|
|
11
|
+
this.platformArgs = init.platformArgs;
|
|
12
|
+
}
|
|
13
|
+
addListener(event, listener) {
|
|
14
|
+
return super.addListener(event, listener);
|
|
15
|
+
}
|
|
16
|
+
removeListener(event, listener) {
|
|
17
|
+
return super.removeListener(event, listener);
|
|
18
|
+
}
|
|
19
|
+
on(event, listener) {
|
|
20
|
+
return super.on(event, listener);
|
|
21
|
+
}
|
|
22
|
+
off(event, listener) {
|
|
23
|
+
return super.off(event, listener);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export class Logger {
|
|
2
2
|
constructor(options = {}) {
|
|
3
|
-
this._instance = options.instance ||
|
|
4
|
-
(!(process.env.NODE_ENV || '').includes('test') ? globalThis.console : {});
|
|
3
|
+
this._instance = options.instance || (!(process.env.NODE_ENV || '').includes('test') ? globalThis.console : {});
|
|
5
4
|
}
|
|
6
5
|
info(message, ...optionalParams) {
|
|
7
6
|
(this._instance.info || this._instance.log)?.(message, ...optionalParams);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class ServiceBase {
|
|
2
2
|
get context() {
|
|
3
3
|
if (!this._context)
|
|
4
4
|
throw new Error(`No context assigned for ${Object.getPrototypeOf(this).constructor.name}`);
|
|
@@ -15,11 +15,11 @@ export class ApiService {
|
|
|
15
15
|
Object.setPrototypeOf(instance, this);
|
|
16
16
|
if (overwriteProperties)
|
|
17
17
|
Object.assign(instance, overwriteProperties);
|
|
18
|
-
if (this[
|
|
19
|
-
this[
|
|
18
|
+
if (this[ServiceBase.extendSymbol])
|
|
19
|
+
this[ServiceBase.extendSymbol](instance);
|
|
20
20
|
return instance;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
(function (
|
|
24
|
-
|
|
25
|
-
})(
|
|
23
|
+
(function (ServiceBase) {
|
|
24
|
+
ServiceBase.extendSymbol = Symbol('extend');
|
|
25
|
+
})(ServiceBase || (ServiceBase = {}));
|