@opra/core 0.21.0 → 0.23.0
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/adapter/execution-context.host.js +48 -0
- package/cjs/adapter/http/express-adapter.host.js +24 -0
- package/cjs/adapter/http/express-adapter.js +12 -45
- package/cjs/adapter/http/helpers/concat-readable.js +20 -0
- package/cjs/adapter/http/helpers/multipart-helper.js +96 -0
- package/cjs/adapter/http/helpers/query-parsers.js +16 -0
- package/cjs/adapter/http/http-adapter-base.js +127 -0
- package/cjs/adapter/http/http-adapter.host.js +57 -0
- package/cjs/adapter/http/http-adapter.js +11 -129
- package/cjs/adapter/http/{impl/http-server-request.js → http-server-request.js} +11 -5
- package/cjs/adapter/http/{impl/http-server-response.js → http-server-response.js} +22 -22
- package/cjs/adapter/http/impl/http-incoming-message.host.js +148 -0
- package/cjs/adapter/http/impl/{http-outgoing-message-host.js → http-outgoing-message.host.js} +26 -38
- package/cjs/adapter/http/request-handlers/entity-request-handler.js +378 -0
- package/cjs/adapter/http/request-handlers/request-handler-base.js +27 -0
- package/cjs/adapter/http/request-handlers/storage-request-handler.js +134 -0
- package/cjs/adapter/operation-context.js +16 -0
- package/cjs/adapter/platform-adapter.host.js +107 -0
- package/cjs/adapter/request.host.js +1 -2
- package/cjs/adapter/request.js +2 -0
- package/cjs/adapter/response.js +2 -0
- package/cjs/adapter/services/logger.js +36 -0
- package/cjs/augmentation/collection.augmentation.js +2 -0
- package/cjs/augmentation/singleton.augmentation.js +2 -0
- package/cjs/augmentation/storage.augmentation.js +2 -0
- package/cjs/index.js +15 -9
- package/esm/adapter/execution-context.host.js +44 -0
- package/esm/adapter/http/express-adapter.host.js +20 -0
- package/esm/adapter/http/express-adapter.js +11 -20
- package/esm/adapter/http/helpers/concat-readable.js +16 -0
- package/esm/adapter/http/helpers/multipart-helper.js +91 -0
- package/esm/adapter/http/helpers/query-parsers.js +12 -0
- package/esm/adapter/http/http-adapter-base.js +123 -0
- package/esm/adapter/http/http-adapter.host.js +52 -0
- package/esm/adapter/http/http-adapter.js +11 -128
- package/esm/adapter/http/{impl/http-server-request.js → http-server-request.js} +12 -6
- package/esm/adapter/http/{impl/http-server-response.js → http-server-response.js} +22 -22
- package/esm/adapter/http/impl/http-incoming-message.host.js +144 -0
- package/esm/adapter/http/impl/{http-outgoing-message-host.js → http-outgoing-message.host.js} +25 -36
- package/esm/adapter/http/request-handlers/entity-request-handler.js +373 -0
- package/esm/adapter/http/request-handlers/request-handler-base.js +23 -0
- package/esm/adapter/http/request-handlers/storage-request-handler.js +129 -0
- package/esm/adapter/operation-context.js +13 -0
- package/esm/adapter/platform-adapter.host.js +102 -0
- package/esm/adapter/request.host.js +1 -2
- package/esm/adapter/request.js +1 -0
- package/esm/adapter/response.js +1 -0
- package/esm/adapter/services/logger.js +32 -0
- package/esm/augmentation/collection.augmentation.js +1 -0
- package/esm/augmentation/singleton.augmentation.js +1 -0
- package/esm/augmentation/storage.augmentation.js +1 -0
- package/esm/index.js +15 -9
- package/i18n/en/error.json +5 -2
- package/package.json +8 -7
- package/types/adapter/execution-context.d.ts +31 -0
- package/types/adapter/execution-context.host.d.ts +27 -0
- package/types/adapter/http/express-adapter.d.ts +12 -8
- package/types/adapter/http/express-adapter.host.d.ts +11 -0
- package/types/adapter/http/helpers/concat-readable.d.ts +3 -0
- package/types/adapter/http/helpers/multipart-helper.d.ts +25 -0
- package/types/adapter/http/helpers/query-parsers.d.ts +1 -0
- package/types/adapter/http/http-adapter-base.d.ts +23 -0
- package/types/adapter/http/http-adapter.d.ts +13 -29
- package/types/adapter/http/http-adapter.host.d.ts +18 -0
- package/types/adapter/http/{impl/http-server-request.d.ts → http-server-request.d.ts} +7 -6
- package/types/adapter/http/{impl/http-server-response.d.ts → http-server-response.d.ts} +2 -2
- package/types/adapter/http/impl/{http-incoming-message-host.d.ts → http-incoming-message.host.d.ts} +16 -12
- package/types/adapter/http/impl/{http-outgoing-message-host.d.ts → http-outgoing-message.host.d.ts} +12 -16
- package/types/adapter/http/request-handlers/entity-request-handler.d.ts +24 -0
- package/types/adapter/http/request-handlers/request-handler-base.d.ts +15 -0
- package/types/adapter/http/request-handlers/storage-request-handler.d.ts +23 -0
- package/types/adapter/interfaces/logger.interface.d.ts +7 -6
- package/types/adapter/interfaces/request-handler.interface.d.ts +4 -0
- package/types/adapter/operation-context.d.ts +11 -0
- package/types/adapter/{adapter.d.ts → platform-adapter.d.ts} +18 -28
- package/types/adapter/platform-adapter.host.d.ts +31 -0
- package/types/adapter/request.d.ts +11 -0
- package/types/adapter/request.host.d.ts +12 -21
- package/types/adapter/{interfaces/response.interface.d.ts → response.d.ts} +2 -2
- package/types/adapter/response.host.d.ts +2 -2
- package/types/adapter/services/logger.d.ts +14 -0
- package/types/augmentation/collection.augmentation.d.ts +112 -0
- package/types/augmentation/singleton.augmentation.d.ts +64 -0
- package/types/augmentation/storage.augmentation.d.ts +39 -0
- package/types/index.d.ts +15 -9
- package/cjs/adapter/adapter.js +0 -118
- package/cjs/adapter/http/impl/http-incoming-message-host.js +0 -127
- package/cjs/adapter/http/request-parsers/parse-collection-request.js +0 -165
- package/cjs/adapter/http/request-parsers/parse-request.js +0 -24
- package/cjs/adapter/http/request-parsers/parse-singleton-request.js +0 -96
- package/cjs/adapter/internal/metadata.resource.js +0 -26
- package/cjs/adapter/request-context.host.js +0 -44
- package/cjs/shared/collection-resource-base.js +0 -20
- package/esm/adapter/adapter.js +0 -113
- package/esm/adapter/http/impl/http-incoming-message-host.js +0 -122
- package/esm/adapter/http/request-parsers/parse-collection-request.js +0 -161
- package/esm/adapter/http/request-parsers/parse-request.js +0 -20
- package/esm/adapter/http/request-parsers/parse-singleton-request.js +0 -92
- package/esm/adapter/internal/metadata.resource.js +0 -23
- package/esm/adapter/request-context.host.js +0 -40
- package/esm/shared/collection-resource-base.js +0 -16
- package/types/adapter/http/request-parsers/parse-collection-request.d.ts +0 -4
- package/types/adapter/http/request-parsers/parse-request.d.ts +0 -4
- package/types/adapter/http/request-parsers/parse-singleton-request.d.ts +0 -4
- package/types/adapter/interfaces/request-context.interface.d.ts +0 -31
- package/types/adapter/interfaces/request.interface.d.ts +0 -15
- package/types/adapter/internal/metadata.resource.d.ts +0 -7
- package/types/adapter/request-context.host.d.ts +0 -22
- package/types/shared/collection-resource-base.d.ts +0 -11
- /package/cjs/adapter/{interfaces/request-context.interface.js → execution-context.js} +0 -0
- /package/cjs/adapter/http/{request-parsers/batch-request-parser.js → request-handlers/parse-batch-request.js} +0 -0
- /package/cjs/adapter/interfaces/{request.interface.js → request-handler.interface.js} +0 -0
- /package/cjs/adapter/{interfaces/response.interface.js → platform-adapter.js} +0 -0
- /package/esm/adapter/{interfaces/request-context.interface.js → execution-context.js} +0 -0
- /package/esm/adapter/http/{request-parsers/batch-request-parser.js → request-handlers/parse-batch-request.js} +0 -0
- /package/esm/adapter/interfaces/{request.interface.js → request-handler.interface.js} +0 -0
- /package/esm/adapter/{interfaces/response.interface.js → platform-adapter.js} +0 -0
- /package/types/adapter/http/{request-parsers/batch-request-parser.d.ts → request-handlers/parse-batch-request.d.ts} +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutionContextHost = void 0;
|
|
4
|
+
const strict_typed_events_1 = require("strict-typed-events");
|
|
5
|
+
class ExecutionContextHost extends strict_typed_events_1.AsyncEventEmitter {
|
|
6
|
+
constructor(api, platform, protocol) {
|
|
7
|
+
super();
|
|
8
|
+
this.api = api;
|
|
9
|
+
this.platform = platform;
|
|
10
|
+
this.errors = [];
|
|
11
|
+
this.executionScope = {};
|
|
12
|
+
this.ws = protocol.ws;
|
|
13
|
+
this.rpc = protocol.rpc;
|
|
14
|
+
if (protocol.http) {
|
|
15
|
+
this.protocol = 'http';
|
|
16
|
+
this.http = {
|
|
17
|
+
platform,
|
|
18
|
+
incoming: protocol.http.incoming,
|
|
19
|
+
outgoing: protocol.http.outgoing,
|
|
20
|
+
switchToContext: () => this
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
else if (protocol.ws) {
|
|
24
|
+
this.protocol = 'ws';
|
|
25
|
+
this.ws = protocol.ws;
|
|
26
|
+
}
|
|
27
|
+
else if (protocol.rpc) {
|
|
28
|
+
this.protocol = 'rpc';
|
|
29
|
+
this.rpc = protocol.rpc;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
switchToHttp() {
|
|
33
|
+
if (this.http)
|
|
34
|
+
return this.http;
|
|
35
|
+
throw new TypeError('Not executing in an "Http" context');
|
|
36
|
+
}
|
|
37
|
+
switchToWs() {
|
|
38
|
+
if (this.ws)
|
|
39
|
+
return this.ws;
|
|
40
|
+
throw new TypeError('Not executing in an "WebSocket" context');
|
|
41
|
+
}
|
|
42
|
+
switchToRpc() {
|
|
43
|
+
if (this.rpc)
|
|
44
|
+
return this.rpc;
|
|
45
|
+
throw new TypeError('Not executing in an "RPC" context');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ExecutionContextHost = ExecutionContextHost;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpressAdapterHost = void 0;
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
5
|
+
const http_adapter_base_js_1 = require("./http-adapter-base.js");
|
|
6
|
+
const http_server_request_js_1 = require("./http-server-request.js");
|
|
7
|
+
const http_server_response_js_1 = require("./http-server-response.js");
|
|
8
|
+
class ExpressAdapterHost extends http_adapter_base_js_1.HttpAdapterBase {
|
|
9
|
+
constructor(app, api, options) {
|
|
10
|
+
super(api, options);
|
|
11
|
+
this._platform = 'express';
|
|
12
|
+
const basePath = new common_1.OpraURLPath(options?.basePath);
|
|
13
|
+
app.use(basePath.toString(), (_req, _res) => {
|
|
14
|
+
const req = http_server_request_js_1.HttpServerRequest.from(_req);
|
|
15
|
+
const res = http_server_response_js_1.HttpServerResponse.from(_res);
|
|
16
|
+
this.handleIncoming(req, res)
|
|
17
|
+
.catch(() => void 0);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
get app() {
|
|
21
|
+
return this._app;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ExpressAdapterHost = ExpressAdapterHost;
|
|
@@ -1,49 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
static async create(app, document, options) {
|
|
37
|
-
const express = await Promise.resolve().then(() => __importStar(require('express')));
|
|
38
|
-
const adapter = new OpraExpressAdapter(document);
|
|
39
|
-
await adapter.init(options);
|
|
40
|
-
const prefix = '/' + (0, common_1.normalizePath)(options?.prefix, true);
|
|
41
|
-
app.use(prefix, express.json());
|
|
42
|
-
app.use(prefix, (req, res, next) => {
|
|
43
|
-
adapter.handler(http_server_request_js_1.HttpServerRequest.create(req), http_server_response_js_1.HttpServerResponse.create(res))
|
|
44
|
-
.catch(e => next(e));
|
|
45
|
-
});
|
|
3
|
+
exports.ExpressAdapter = void 0;
|
|
4
|
+
const express_adapter_host_js_1 = require("./express-adapter.host.js");
|
|
5
|
+
/**
|
|
6
|
+
* @namespace
|
|
7
|
+
*/
|
|
8
|
+
var ExpressAdapter;
|
|
9
|
+
(function (ExpressAdapter) {
|
|
10
|
+
async function create(app, api, options) {
|
|
11
|
+
const adapter = new express_adapter_host_js_1.ExpressAdapterHost(app, api, options);
|
|
12
|
+
await adapter.init();
|
|
46
13
|
return adapter;
|
|
47
14
|
}
|
|
48
|
-
|
|
49
|
-
exports.
|
|
15
|
+
ExpressAdapter.create = create;
|
|
16
|
+
})(ExpressAdapter || (exports.ExpressAdapter = ExpressAdapter = {}));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.concatReadable = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
function concatReadable(...streams) {
|
|
6
|
+
const out = new stream_1.PassThrough();
|
|
7
|
+
const pipeNext = () => {
|
|
8
|
+
const nextStream = streams.shift();
|
|
9
|
+
if (nextStream) {
|
|
10
|
+
nextStream.pipe(out, { end: false });
|
|
11
|
+
nextStream.once('end', () => pipeNext());
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
out.end();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
pipeNext();
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
exports.concatReadable = concatReadable;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultipartIterator = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const events_1 = require("events");
|
|
6
|
+
const formidable_1 = tslib_1.__importDefault(require("formidable"));
|
|
7
|
+
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
|
|
8
|
+
const noOp = () => void 0;
|
|
9
|
+
class MultipartIterator extends events_1.EventEmitter {
|
|
10
|
+
constructor(incoming, options) {
|
|
11
|
+
super();
|
|
12
|
+
this._cancelled = false;
|
|
13
|
+
this._items = [];
|
|
14
|
+
this._stack = [];
|
|
15
|
+
this.setMaxListeners(1000);
|
|
16
|
+
const form = this._form = (0, formidable_1.default)({
|
|
17
|
+
...options,
|
|
18
|
+
filter: (part) => {
|
|
19
|
+
return !this._cancelled && (!options?.filter || options.filter(part));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
form.once('error', () => {
|
|
23
|
+
this._cancelled = true;
|
|
24
|
+
if (this.listenerCount('error') > 0)
|
|
25
|
+
this.emit('error');
|
|
26
|
+
});
|
|
27
|
+
form.on('field', (field, value) => {
|
|
28
|
+
const item = { field, value };
|
|
29
|
+
this._items.push(item);
|
|
30
|
+
this._stack.push(item);
|
|
31
|
+
this.emit('item', item);
|
|
32
|
+
});
|
|
33
|
+
form.on('file', (field, file) => {
|
|
34
|
+
const item = { field, file };
|
|
35
|
+
this._items.push(item);
|
|
36
|
+
this._stack.push(item);
|
|
37
|
+
this.emit('item', item);
|
|
38
|
+
});
|
|
39
|
+
form.parse(incoming).catch(noOp);
|
|
40
|
+
}
|
|
41
|
+
get items() {
|
|
42
|
+
return this._items;
|
|
43
|
+
}
|
|
44
|
+
getNext() {
|
|
45
|
+
if (this._form.ended)
|
|
46
|
+
return Promise.resolve(undefined);
|
|
47
|
+
this.resume();
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
if (this._stack.length)
|
|
50
|
+
return resolve(this._stack.shift());
|
|
51
|
+
this.once('item', () => resolve(this._stack.shift()));
|
|
52
|
+
this.once('error', (e) => reject(e));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getAll() {
|
|
56
|
+
if (this._form.ended)
|
|
57
|
+
return Promise.resolve([...this._items]);
|
|
58
|
+
this.resume();
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
this._form.once('error', reject);
|
|
61
|
+
this._form.once('end', () => {
|
|
62
|
+
resolve([...this._items]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
cancel() {
|
|
67
|
+
this._cancelled = true;
|
|
68
|
+
this.resume();
|
|
69
|
+
}
|
|
70
|
+
resume() {
|
|
71
|
+
this._form.resume();
|
|
72
|
+
}
|
|
73
|
+
pause() {
|
|
74
|
+
this._form.pause();
|
|
75
|
+
}
|
|
76
|
+
async deleteFiles() {
|
|
77
|
+
const promises = [];
|
|
78
|
+
this._items
|
|
79
|
+
.forEach(item => {
|
|
80
|
+
if (!item.file)
|
|
81
|
+
return;
|
|
82
|
+
const file = item.file;
|
|
83
|
+
promises.push(new Promise(resolve => {
|
|
84
|
+
if (file._writeStream.closed)
|
|
85
|
+
return resolve();
|
|
86
|
+
file._writeStream.once('close', resolve);
|
|
87
|
+
}).then(() => {
|
|
88
|
+
return promises_1.default.unlink(file.filepath);
|
|
89
|
+
}).then(() => {
|
|
90
|
+
return 0;
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
return Promise.allSettled(promises);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.MultipartIterator = MultipartIterator;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArrayParam = void 0;
|
|
4
|
+
const fast_tokenizer_1 = require("fast-tokenizer");
|
|
5
|
+
function parseArrayParam(v) {
|
|
6
|
+
if (!v)
|
|
7
|
+
return;
|
|
8
|
+
return (0, fast_tokenizer_1.splitString)(v, {
|
|
9
|
+
delimiters: ',',
|
|
10
|
+
quotes: true,
|
|
11
|
+
brackets: true,
|
|
12
|
+
keepBrackets: true,
|
|
13
|
+
keepQuotes: true
|
|
14
|
+
}).map(x => x.trim());
|
|
15
|
+
}
|
|
16
|
+
exports.parseArrayParam = parseArrayParam;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpAdapterBase = void 0;
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
5
|
+
const execution_context_host_js_1 = require("../execution-context.host.js");
|
|
6
|
+
const platform_adapter_host_js_1 = require("../platform-adapter.host.js");
|
|
7
|
+
const entity_request_handler_js_1 = require("./request-handlers/entity-request-handler.js");
|
|
8
|
+
const storage_request_handler_js_1 = require("./request-handlers/storage-request-handler.js");
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @class HttpAdapterBase
|
|
12
|
+
*/
|
|
13
|
+
class HttpAdapterBase extends platform_adapter_host_js_1.PlatformAdapterHost {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this._protocol = 'http';
|
|
17
|
+
this._requestHandlers = [
|
|
18
|
+
new entity_request_handler_js_1.EntityRequestHandler(this),
|
|
19
|
+
new storage_request_handler_js_1.StorageRequestHandler(this)
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Main http request handler
|
|
24
|
+
* @param incoming
|
|
25
|
+
* @param outgoing
|
|
26
|
+
* @protected
|
|
27
|
+
*/
|
|
28
|
+
async handleIncoming(incoming, outgoing) {
|
|
29
|
+
const context = new execution_context_host_js_1.ExecutionContextHost(this.api, this.platform, { http: { incoming, outgoing } });
|
|
30
|
+
try {
|
|
31
|
+
/* istanbul ignore next */
|
|
32
|
+
if (!this._initialized)
|
|
33
|
+
throw new common_1.InternalServerError(`${Object.getPrototypeOf(this).constructor.name} has not been initialized yet`);
|
|
34
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
35
|
+
// Expose headers if cors enabled
|
|
36
|
+
if (outgoing.getHeader(common_1.HttpHeaderCodes.Access_Control_Allow_Origin)) {
|
|
37
|
+
// Expose X-Opra-* headers
|
|
38
|
+
outgoing.appendHeader(common_1.HttpHeaderCodes.Access_Control_Expose_Headers, Object.values(common_1.HttpHeaderCodes)
|
|
39
|
+
.filter(k => k.toLowerCase().startsWith('x-opra-')));
|
|
40
|
+
}
|
|
41
|
+
await this.processRequest(context);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
context.errors.push((0, common_1.wrapException)(error));
|
|
45
|
+
}
|
|
46
|
+
// If no response returned to the client we send an error
|
|
47
|
+
if (!outgoing.writableEnded) {
|
|
48
|
+
if (!context.errors.length)
|
|
49
|
+
context.errors.push(new common_1.BadRequestError(`Server can not process this request`));
|
|
50
|
+
await this.handleError(context);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async processRequest(context) {
|
|
54
|
+
try {
|
|
55
|
+
const { incoming, outgoing } = context.switchToHttp();
|
|
56
|
+
if (incoming.method === 'GET' &&
|
|
57
|
+
incoming.parsedUrl.path.length &&
|
|
58
|
+
incoming.parsedUrl.path[0].resource === '$metadata') {
|
|
59
|
+
outgoing.setHeader('content-type', 'application/json');
|
|
60
|
+
outgoing.end(JSON.stringify(this.api.exportSchema({ webSafe: true })));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const { parsedUrl } = incoming;
|
|
64
|
+
if (!parsedUrl.path.length) {
|
|
65
|
+
// Batch
|
|
66
|
+
if (incoming.headers['content-type'] === 'multipart/mixed') {
|
|
67
|
+
// todo
|
|
68
|
+
}
|
|
69
|
+
throw new common_1.BadRequestError();
|
|
70
|
+
}
|
|
71
|
+
// Iterate through request handlers until one of them sends response (end outgoing stream)
|
|
72
|
+
for (const requestHandler of this._requestHandlers) {
|
|
73
|
+
await requestHandler.processRequest(context);
|
|
74
|
+
if (outgoing.writableEnded)
|
|
75
|
+
return;
|
|
76
|
+
if (context.errors.length) {
|
|
77
|
+
await this.handleError(context);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await context.emitAsync('finish');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async handleError(context) {
|
|
87
|
+
const { errors } = context;
|
|
88
|
+
const { outgoing } = context.switchToHttp();
|
|
89
|
+
if (outgoing.headersSent) {
|
|
90
|
+
outgoing.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
errors.forEach(x => {
|
|
94
|
+
// todo. implement a better log mechanism
|
|
95
|
+
if (x instanceof common_1.OpraException)
|
|
96
|
+
this._logger.fatal(x);
|
|
97
|
+
else
|
|
98
|
+
this._logger.error(x);
|
|
99
|
+
});
|
|
100
|
+
const wrappedErrors = errors.map(common_1.wrapException);
|
|
101
|
+
// Sort errors from fatal to info
|
|
102
|
+
wrappedErrors.sort((a, b) => {
|
|
103
|
+
const i = common_1.IssueSeverity.Keys.indexOf(a.issue.severity) - common_1.IssueSeverity.Keys.indexOf(b.issue.severity);
|
|
104
|
+
if (i === 0)
|
|
105
|
+
return b.status - a.status;
|
|
106
|
+
return i;
|
|
107
|
+
});
|
|
108
|
+
let status = outgoing.statusCode || 0;
|
|
109
|
+
if (!status || status < Number(common_1.HttpStatusCodes.BAD_REQUEST)) {
|
|
110
|
+
status = wrappedErrors[0].status;
|
|
111
|
+
if (status < Number(common_1.HttpStatusCodes.BAD_REQUEST))
|
|
112
|
+
status = common_1.HttpStatusCodes.INTERNAL_SERVER_ERROR;
|
|
113
|
+
}
|
|
114
|
+
outgoing.statusCode = status;
|
|
115
|
+
const body = this._i18n.deep({
|
|
116
|
+
errors: wrappedErrors.map(x => x.issue)
|
|
117
|
+
});
|
|
118
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
119
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
120
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
121
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
122
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
123
|
+
outgoing.send(JSON.stringify(body));
|
|
124
|
+
outgoing.end();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.HttpAdapterBase = HttpAdapterBase;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpAdapterHost = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const http_1 = tslib_1.__importDefault(require("http"));
|
|
6
|
+
const common_1 = require("@opra/common");
|
|
7
|
+
const http_adapter_base_js_1 = require("./http-adapter-base.js");
|
|
8
|
+
const http_server_request_js_1 = require("./http-server-request.js");
|
|
9
|
+
const http_server_response_js_1 = require("./http-server-response.js");
|
|
10
|
+
/**
|
|
11
|
+
* @class HttpAdapterHost
|
|
12
|
+
*/
|
|
13
|
+
class HttpAdapterHost extends http_adapter_base_js_1.HttpAdapterBase {
|
|
14
|
+
constructor(api, options) {
|
|
15
|
+
super(api, options);
|
|
16
|
+
this._platform = 'http';
|
|
17
|
+
this._basePath = new common_1.OpraURLPath(options?.basePath);
|
|
18
|
+
this._server = http_1.default.createServer((incomingMessage, serverResponse) => this._serverListener(incomingMessage, serverResponse));
|
|
19
|
+
}
|
|
20
|
+
get basePath() {
|
|
21
|
+
return this._basePath;
|
|
22
|
+
}
|
|
23
|
+
get server() {
|
|
24
|
+
return this._server;
|
|
25
|
+
}
|
|
26
|
+
_serverListener(incomingMessage, serverResponse) {
|
|
27
|
+
const originalUrl = incomingMessage.url;
|
|
28
|
+
const parsedUrl = new common_1.OpraURL(originalUrl);
|
|
29
|
+
const relativePath = common_1.OpraURLPath.relative(parsedUrl.path, this.basePath);
|
|
30
|
+
if (!relativePath) {
|
|
31
|
+
serverResponse.statusCode = common_1.HttpStatusCodes.NOT_FOUND;
|
|
32
|
+
serverResponse.statusMessage = common_1.HttpStatusMessages[common_1.HttpStatusCodes.NOT_FOUND];
|
|
33
|
+
serverResponse.end();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
parsedUrl.path = relativePath;
|
|
37
|
+
incomingMessage.originalUrl = originalUrl;
|
|
38
|
+
incomingMessage.baseUrl = this.basePath.toString();
|
|
39
|
+
incomingMessage.parsedUrl = parsedUrl;
|
|
40
|
+
const req = http_server_request_js_1.HttpServerRequest.from(incomingMessage);
|
|
41
|
+
const res = http_server_response_js_1.HttpServerResponse.from(serverResponse);
|
|
42
|
+
this.handleIncoming(req, res)
|
|
43
|
+
.catch((e) => this._logger.fatal(e));
|
|
44
|
+
}
|
|
45
|
+
async close() {
|
|
46
|
+
await super.close();
|
|
47
|
+
if (this.server.listening)
|
|
48
|
+
await new Promise((resolve, reject) => {
|
|
49
|
+
this.server.close((err) => {
|
|
50
|
+
if (err)
|
|
51
|
+
return reject(err);
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.HttpAdapterHost = HttpAdapterHost;
|
|
@@ -1,134 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
const common_1 = require("@opra/common");
|
|
6
|
-
const adapter_js_1 = require("../adapter.js");
|
|
7
|
-
const request_context_host_js_1 = require("../request-context.host.js");
|
|
8
|
-
const response_host_js_1 = require("../response.host.js");
|
|
9
|
-
const parse_request_js_1 = require("./request-parsers/parse-request.js");
|
|
3
|
+
exports.HttpAdapter = void 0;
|
|
4
|
+
const http_adapter_host_js_1 = require("./http-adapter.host.js");
|
|
10
5
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @class OpraHttpAdapter
|
|
6
|
+
* @namespace HttpAdapter
|
|
13
7
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*/
|
|
21
|
-
async handler(incoming, outgoing) {
|
|
22
|
-
try {
|
|
23
|
-
try {
|
|
24
|
-
const request = await (0, parse_request_js_1.parseRequest)(this._apiRoot, incoming);
|
|
25
|
-
const task = this.createRequestTask(request, outgoing);
|
|
26
|
-
await task.toPromise();
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
if (e instanceof common_1.OpraException)
|
|
30
|
-
throw e;
|
|
31
|
-
throw new common_1.BadRequestError(e);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
await this.handleError(incoming, outgoing, [error]);
|
|
36
|
-
}
|
|
8
|
+
var HttpAdapter;
|
|
9
|
+
(function (HttpAdapter) {
|
|
10
|
+
async function create(api, options) {
|
|
11
|
+
const adapter = new http_adapter_host_js_1.HttpAdapterHost(api, options);
|
|
12
|
+
await adapter.init();
|
|
13
|
+
return adapter;
|
|
37
14
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const response = new response_host_js_1.ResponseHost({ http: outgoing });
|
|
41
|
-
const context = new request_context_host_js_1.RequestContextHost('http', this.platform, this.api, request, response);
|
|
42
|
-
return this.executeRequest(context);
|
|
43
|
-
}, {
|
|
44
|
-
id: request.contentId,
|
|
45
|
-
exclusive: request.crud !== 'read'
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
async executeRequest(context) {
|
|
49
|
-
const { request, response } = context;
|
|
50
|
-
await super.executeRequest(context)
|
|
51
|
-
.catch(e => {
|
|
52
|
-
response.errors = response.errors || [];
|
|
53
|
-
response.errors.push(e);
|
|
54
|
-
});
|
|
55
|
-
const outgoing = response.switchToHttp();
|
|
56
|
-
if (response.errors?.length) {
|
|
57
|
-
const errors = response.errors.map(e => (0, common_1.wrapException)(e));
|
|
58
|
-
await this.handleError(request.switchToHttp(), outgoing, errors);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (request.resource instanceof common_1.Singleton || request.resource instanceof common_1.Collection) {
|
|
62
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Data_Type, String(request.resource.type.name));
|
|
63
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Operation, request.operation);
|
|
64
|
-
}
|
|
65
|
-
if (request.crud === 'create') {
|
|
66
|
-
if (!response.value)
|
|
67
|
-
throw new common_1.InternalServerError();
|
|
68
|
-
// todo validate
|
|
69
|
-
outgoing.statusCode = 201;
|
|
70
|
-
}
|
|
71
|
-
if (request.resource instanceof common_1.Collection &&
|
|
72
|
-
request.crud === 'read' && request.many && request.args.count >= 0) {
|
|
73
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Total_Matches, String(response.count));
|
|
74
|
-
}
|
|
75
|
-
outgoing.statusCode = outgoing.statusCode || common_1.HttpStatusCodes.OK;
|
|
76
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
77
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
78
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
79
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
80
|
-
if (response.value) {
|
|
81
|
-
if (typeof response.value === 'object') {
|
|
82
|
-
if ((0, common_1.isReadable)(response.value) || Buffer.isBuffer(response.value))
|
|
83
|
-
outgoing.send(response.value);
|
|
84
|
-
else {
|
|
85
|
-
const body = this.i18n.deep(response.value);
|
|
86
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
87
|
-
outgoing.send(JSON.stringify(body));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else
|
|
91
|
-
outgoing.send(JSON.stringify(response.value));
|
|
92
|
-
}
|
|
93
|
-
outgoing.end();
|
|
94
|
-
}
|
|
95
|
-
async handleError(incoming, outgoing, errors) {
|
|
96
|
-
errors.forEach(e => {
|
|
97
|
-
this.log((e instanceof common_1.OpraException) ? 'error' : 'fatal', incoming, e); // todo. implement a better logger
|
|
98
|
-
});
|
|
99
|
-
errors = errors.map(common_1.wrapException);
|
|
100
|
-
let status = outgoing.statusCode || 0;
|
|
101
|
-
// Sort errors from fatal to info
|
|
102
|
-
errors.sort((a, b) => {
|
|
103
|
-
const i = common_1.IssueSeverity.Keys.indexOf(a.issue.severity) - common_1.IssueSeverity.Keys.indexOf(b.issue.severity);
|
|
104
|
-
if (i === 0)
|
|
105
|
-
return b.status - a.status;
|
|
106
|
-
return i;
|
|
107
|
-
});
|
|
108
|
-
if (!status || status < common_1.HttpStatusCodes.BAD_REQUEST) {
|
|
109
|
-
status = errors[0].status;
|
|
110
|
-
if (status < common_1.HttpStatusCodes.BAD_REQUEST)
|
|
111
|
-
status = common_1.HttpStatusCodes.INTERNAL_SERVER_ERROR;
|
|
112
|
-
}
|
|
113
|
-
const body = this.i18n.deep({
|
|
114
|
-
errors: errors.map(e => e.issue)
|
|
115
|
-
});
|
|
116
|
-
outgoing.statusCode = status;
|
|
117
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
118
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
119
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
120
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
121
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
|
|
122
|
-
outgoing.send(JSON.stringify(body));
|
|
123
|
-
outgoing.end();
|
|
124
|
-
}
|
|
125
|
-
log(logType, incoming, message, ...optionalParams) {
|
|
126
|
-
const logFn = logType === 'fatal'
|
|
127
|
-
? this.logger?.fatal || this.logger?.error
|
|
128
|
-
: this.logger?.[logType];
|
|
129
|
-
if (!logFn)
|
|
130
|
-
return;
|
|
131
|
-
logFn.apply(this.logger, [String(message), ...optionalParams]);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
exports.OpraHttpAdapter = OpraHttpAdapter;
|
|
15
|
+
HttpAdapter.create = create;
|
|
16
|
+
})(HttpAdapter || (exports.HttpAdapter = HttpAdapter = {}));
|
|
@@ -11,21 +11,27 @@ const fresh_1 = tslib_1.__importDefault(require("fresh"));
|
|
|
11
11
|
const range_parser_1 = tslib_1.__importDefault(require("range-parser"));
|
|
12
12
|
const type_is_1 = tslib_1.__importDefault(require("type-is"));
|
|
13
13
|
const common_1 = require("@opra/common");
|
|
14
|
-
const http_incoming_message_host_js_1 = require("./http-incoming-message
|
|
14
|
+
const http_incoming_message_host_js_1 = require("./impl/http-incoming-message.host.js");
|
|
15
15
|
function isHttpIncomingMessage(v) {
|
|
16
16
|
return v && Array.isArray(v.rawHeaders) && (0, common_1.isReadable)(v);
|
|
17
17
|
}
|
|
18
18
|
var HttpServerRequest;
|
|
19
19
|
(function (HttpServerRequest) {
|
|
20
|
-
function
|
|
20
|
+
function from(instance) {
|
|
21
21
|
if (!isHttpIncomingMessage(instance))
|
|
22
|
-
instance = http_incoming_message_host_js_1.HttpIncomingMessageHost.
|
|
22
|
+
instance = http_incoming_message_host_js_1.HttpIncomingMessageHost.from(instance);
|
|
23
23
|
(0, common_1.mergePrototype)(instance, HttpServerRequestHost.prototype);
|
|
24
|
-
|
|
24
|
+
const req = instance;
|
|
25
|
+
req.baseUrl = req.baseUrl || '';
|
|
26
|
+
req.parsedUrl = req.parsedUrl || new common_1.OpraURL(req.url);
|
|
27
|
+
return req;
|
|
25
28
|
}
|
|
26
|
-
HttpServerRequest.
|
|
29
|
+
HttpServerRequest.from = from;
|
|
27
30
|
})(HttpServerRequest || (exports.HttpServerRequest = HttpServerRequest = {}));
|
|
28
31
|
class HttpServerRequestHost {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.basePath = '/';
|
|
34
|
+
}
|
|
29
35
|
get protocol() {
|
|
30
36
|
const proto = this.header('X-Forwarded-Proto') || 'http';
|
|
31
37
|
const index = proto.indexOf(',');
|