@opra/core 1.0.0-alpha.8 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/augmentation/18n.augmentation.js +13 -13
- package/cjs/constants.js +1 -2
- package/cjs/execution-context.js +1 -0
- package/cjs/http/express-adapter.js +22 -21
- package/cjs/http/http-adapter.js +2 -5
- package/cjs/http/http-context.js +16 -31
- package/cjs/http/{impl/http-handler.js → http-handler.js} +194 -169
- package/cjs/http/impl/http-outgoing.host.js +2 -2
- package/cjs/http/impl/multipart-reader.js +141 -44
- package/cjs/http/utils/body-reader.js +0 -1
- package/cjs/http/utils/common.js +4 -4
- package/cjs/http/utils/concat-readable.js +1 -2
- package/cjs/http/utils/convert-to-headers.js +2 -3
- package/cjs/http/utils/convert-to-raw-headers.js +1 -2
- package/cjs/http/utils/match-known-fields.js +2 -2
- package/cjs/http/utils/wrap-exception.js +1 -2
- package/cjs/index.js +1 -1
- package/cjs/platform-adapter.js +0 -3
- package/cjs/type-guards.js +4 -5
- package/esm/augmentation/18n.augmentation.js +2 -2
- package/esm/constants.js +0 -1
- package/esm/execution-context.js +1 -0
- package/esm/http/express-adapter.js +22 -21
- package/esm/http/http-adapter.js +2 -5
- package/esm/http/http-context.js +17 -32
- package/esm/http/{impl/http-handler.js → http-handler.js} +195 -170
- package/esm/http/impl/http-outgoing.host.js +1 -1
- package/esm/http/impl/multipart-reader.js +142 -45
- package/esm/http/utils/body-reader.js +0 -1
- package/esm/index.js +1 -1
- package/esm/package.json +3 -0
- package/esm/platform-adapter.js +0 -3
- package/package.json +35 -63
- package/types/augmentation/http-controller.augmentation.d.ts +1 -2
- package/types/constants.d.ts +0 -1
- package/types/execution-context.d.ts +2 -1
- package/types/helpers/service-base.d.ts +1 -1
- package/types/http/express-adapter.d.ts +1 -1
- package/types/http/http-adapter.d.ts +35 -8
- package/types/http/http-context.d.ts +4 -4
- package/types/http/{impl/http-handler.d.ts → http-handler.d.ts} +11 -9
- package/types/http/impl/http-incoming.host.d.ts +1 -2
- package/types/http/impl/http-outgoing.host.d.ts +1 -1
- package/types/http/impl/multipart-reader.d.ts +38 -20
- package/types/http/impl/node-incoming-message.host.d.ts +3 -7
- package/types/http/impl/node-outgoing-message.host.d.ts +5 -8
- package/types/http/interfaces/http-incoming.interface.d.ts +2 -3
- package/types/http/interfaces/http-outgoing.interface.d.ts +2 -2
- package/types/http/interfaces/node-incoming-message.interface.d.ts +0 -2
- package/types/http/interfaces/node-outgoing-message.interface.d.ts +1 -3
- package/types/http/utils/body-reader.d.ts +1 -4
- package/types/http/utils/concat-readable.d.ts +0 -1
- package/types/http/utils/convert-to-raw-headers.d.ts +1 -2
- package/types/index.d.cts +28 -0
- package/types/index.d.ts +1 -1
- package/types/platform-adapter.d.ts +0 -4
- package/cjs/helpers/logger.js +0 -35
- package/esm/helpers/logger.js +0 -31
- package/i18n/i18n/en/error.json +0 -21
- package/types/helpers/logger.d.ts +0 -14
|
@@ -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 node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
4
6
|
const common_1 = require("@opra/common");
|
|
5
|
-
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
6
|
-
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
7
|
common_1.I18n.load = async function (options) {
|
|
8
8
|
const opts = {
|
|
9
9
|
...options,
|
|
@@ -11,7 +11,7 @@ common_1.I18n.load = async function (options) {
|
|
|
11
11
|
delete opts.resourceDirs;
|
|
12
12
|
const instance = common_1.I18n.createInstance(opts);
|
|
13
13
|
await instance.init();
|
|
14
|
-
await instance.loadResourceDir(
|
|
14
|
+
await instance.loadResourceDir(node_path_1.default.resolve((0, common_1.getStackFileName)(), '../../../i18n'));
|
|
15
15
|
if (options?.resourceDirs)
|
|
16
16
|
for (const dir of options.resourceDirs)
|
|
17
17
|
await instance.loadResourceDir(dir);
|
|
@@ -23,7 +23,7 @@ common_1.I18n.prototype.loadResourceBundle = async function (lang, ns, filePath,
|
|
|
23
23
|
obj = (await fetch(filePath, { headers: { accept: 'application/json' } })).json();
|
|
24
24
|
}
|
|
25
25
|
else {
|
|
26
|
-
const content =
|
|
26
|
+
const content = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
27
27
|
obj = JSON.parse(content);
|
|
28
28
|
}
|
|
29
29
|
this.addResourceBundle(lang, ns, obj, deep, overwrite);
|
|
@@ -31,18 +31,18 @@ common_1.I18n.prototype.loadResourceBundle = async function (lang, ns, filePath,
|
|
|
31
31
|
common_1.I18n.prototype.loadResourceDir = async function (dirnames, deep, overwrite) {
|
|
32
32
|
for (const dirname of Array.isArray(dirnames) ? dirnames : [dirnames]) {
|
|
33
33
|
/* istanbul ignore next */
|
|
34
|
-
if (!
|
|
34
|
+
if (!node_fs_1.default.existsSync(dirname))
|
|
35
35
|
continue;
|
|
36
|
-
const languageDirs =
|
|
36
|
+
const languageDirs = node_fs_1.default.readdirSync(dirname);
|
|
37
37
|
for (const lang of languageDirs) {
|
|
38
|
-
const langDir =
|
|
39
|
-
if (
|
|
40
|
-
const nsDirs =
|
|
38
|
+
const langDir = node_path_1.default.join(dirname, lang);
|
|
39
|
+
if (node_fs_1.default.statSync(langDir).isDirectory()) {
|
|
40
|
+
const nsDirs = node_fs_1.default.readdirSync(langDir);
|
|
41
41
|
for (const nsfile of nsDirs) {
|
|
42
|
-
const nsFilePath =
|
|
43
|
-
const ext =
|
|
44
|
-
if (ext === '.json' &&
|
|
45
|
-
const ns =
|
|
42
|
+
const nsFilePath = node_path_1.default.join(langDir, nsfile);
|
|
43
|
+
const ext = node_path_1.default.extname(nsfile);
|
|
44
|
+
if (ext === '.json' && node_fs_1.default.statSync(nsFilePath).isFile()) {
|
|
45
|
+
const ns = node_path_1.default.basename(nsfile, ext);
|
|
46
46
|
await this.loadResourceBundle(lang, ns, nsFilePath, deep, overwrite);
|
|
47
47
|
}
|
|
48
48
|
}
|
package/cjs/constants.js
CHANGED
package/cjs/execution-context.js
CHANGED
|
@@ -8,6 +8,7 @@ const strict_typed_events_1 = require("strict-typed-events");
|
|
|
8
8
|
class ExecutionContext extends strict_typed_events_1.AsyncEventEmitter {
|
|
9
9
|
constructor(init) {
|
|
10
10
|
super();
|
|
11
|
+
this.errors = [];
|
|
11
12
|
this.document = init.document;
|
|
12
13
|
this.protocol = init.protocol;
|
|
13
14
|
this.platform = init.platform;
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExpressAdapter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const nodePath = tslib_1.__importStar(require("node:path"));
|
|
5
6
|
const common_1 = require("@opra/common");
|
|
6
7
|
const express_1 = require("express");
|
|
7
|
-
const nodePath = tslib_1.__importStar(require("path"));
|
|
8
|
-
const constants_js_1 = require("../constants.js");
|
|
9
8
|
const http_adapter_js_1 = require("./http-adapter.js");
|
|
10
9
|
const http_context_js_1 = require("./http-context.js");
|
|
11
10
|
const http_incoming_interface_js_1 = require("./interfaces/http-incoming.interface.js");
|
|
12
11
|
const http_outgoing_interface_js_1 = require("./interfaces/http-outgoing.interface.js");
|
|
12
|
+
const wrap_exception_js_1 = require("./utils/wrap-exception.js");
|
|
13
13
|
class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
14
14
|
constructor(app, document, options) {
|
|
15
15
|
super(document, options);
|
|
@@ -40,7 +40,8 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
40
40
|
await resource.onShutdown.call(instance, resource);
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
|
-
this.
|
|
43
|
+
if (this.listenerCount('error'))
|
|
44
|
+
this.emit('error', (0, wrap_exception_js_1.wrapException)(e));
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -63,10 +64,10 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
63
64
|
}
|
|
64
65
|
else
|
|
65
66
|
this.app.use(router);
|
|
66
|
-
const createContext = (_req, _res, args) => {
|
|
67
|
+
const createContext = async (_req, _res, args) => {
|
|
67
68
|
const request = http_incoming_interface_js_1.HttpIncoming.from(_req);
|
|
68
69
|
const response = http_outgoing_interface_js_1.HttpOutgoing.from(_res);
|
|
69
|
-
|
|
70
|
+
const ctx = new http_context_js_1.HttpContext({
|
|
70
71
|
adapter: this,
|
|
71
72
|
platform: this.platform,
|
|
72
73
|
request,
|
|
@@ -76,12 +77,14 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
76
77
|
operation: args?.operation,
|
|
77
78
|
operationHandler: args?.operationHandler,
|
|
78
79
|
});
|
|
80
|
+
await this.emitAsync('createContext', ctx);
|
|
81
|
+
return ctx;
|
|
79
82
|
};
|
|
80
83
|
/** Add an endpoint that returns document schema */
|
|
81
84
|
router.get('/\\$schema', (_req, _res, next) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
createContext(_req, _res)
|
|
86
|
+
.then(ctx => this.handler.sendDocumentSchema(ctx).catch(next))
|
|
87
|
+
.catch(next);
|
|
85
88
|
});
|
|
86
89
|
/** Add operation endpoints */
|
|
87
90
|
if (this.api.controllers.size) {
|
|
@@ -95,19 +98,18 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
95
98
|
continue;
|
|
96
99
|
/** Define router callback */
|
|
97
100
|
router[operation.method.toLowerCase()](routePath, (_req, _res, _next) => {
|
|
98
|
-
|
|
101
|
+
createContext(_req, _res, {
|
|
99
102
|
controller,
|
|
100
103
|
controllerInstance,
|
|
101
104
|
operation,
|
|
102
105
|
operationHandler,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
.handleRequest(context)
|
|
106
|
+
})
|
|
107
|
+
.then(ctx => this.handler.handleRequest(ctx))
|
|
106
108
|
.then(() => {
|
|
107
109
|
if (!_res.headersSent)
|
|
108
110
|
_next();
|
|
109
111
|
})
|
|
110
|
-
.catch((e) => this.
|
|
112
|
+
.catch((e) => this.emit('error', e));
|
|
111
113
|
});
|
|
112
114
|
}
|
|
113
115
|
if (controller.controllers.size) {
|
|
@@ -120,18 +122,17 @@ class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
|
|
|
120
122
|
}
|
|
121
123
|
/** Add an endpoint that returns 404 error at last */
|
|
122
124
|
router.use('*', (_req, _res, next) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
new common_1.NotFoundError({
|
|
128
|
-
message: `No endpoint found for [${_req.method}]${_req.baseUrl}`,
|
|
125
|
+
createContext(_req, _res)
|
|
126
|
+
.then(ctx => {
|
|
127
|
+
ctx.errors.push(new common_1.NotFoundError({
|
|
128
|
+
message: `No endpoint found at [${_req.method}]${_req.baseUrl}`,
|
|
129
129
|
details: {
|
|
130
130
|
path: _req.baseUrl,
|
|
131
131
|
method: _req.method,
|
|
132
132
|
},
|
|
133
|
-
})
|
|
134
|
-
|
|
133
|
+
}));
|
|
134
|
+
this.handler.sendResponse(ctx).catch(next);
|
|
135
|
+
})
|
|
135
136
|
.catch(next);
|
|
136
137
|
});
|
|
137
138
|
}
|
package/cjs/http/http-adapter.js
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HttpAdapter = void 0;
|
|
4
4
|
const common_1 = require("@opra/common");
|
|
5
|
-
const constants_js_1 = require("../constants.js");
|
|
6
5
|
const platform_adapter_js_1 = require("../platform-adapter.js");
|
|
7
|
-
const http_handler_js_1 = require("./
|
|
6
|
+
const http_handler_js_1 = require("./http-handler.js");
|
|
8
7
|
/**
|
|
9
8
|
*
|
|
10
9
|
* @class HttpAdapter
|
|
@@ -15,10 +14,8 @@ class HttpAdapter extends platform_adapter_js_1.PlatformAdapter {
|
|
|
15
14
|
this.protocol = 'http';
|
|
16
15
|
if (!(document.api instanceof common_1.HttpApi))
|
|
17
16
|
throw new TypeError(`The document does not expose an HTTP Api`);
|
|
18
|
-
this
|
|
17
|
+
this.handler = new http_handler_js_1.HttpHandler(this);
|
|
19
18
|
this.interceptors = [...(options?.interceptors || [])];
|
|
20
|
-
if (options?.onRequest)
|
|
21
|
-
this.on('request', options.onRequest);
|
|
22
19
|
}
|
|
23
20
|
get api() {
|
|
24
21
|
return this.document.api;
|
package/cjs/http/http-context.js
CHANGED
|
@@ -29,6 +29,10 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
29
29
|
this.pathParams = init.pathParams || {};
|
|
30
30
|
this.queryParams = init.queryParams || {};
|
|
31
31
|
this._body = init.body;
|
|
32
|
+
this.on('finish', () => {
|
|
33
|
+
if (this._multipartReader)
|
|
34
|
+
this._multipartReader.purge().catch(() => undefined);
|
|
35
|
+
});
|
|
32
36
|
}
|
|
33
37
|
get isMultipart() {
|
|
34
38
|
return !!this.request.is('multipart');
|
|
@@ -38,21 +42,21 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
38
42
|
throw new common_1.InternalServerError('Request content is not a multipart content');
|
|
39
43
|
if (this._multipartReader)
|
|
40
44
|
return this._multipartReader;
|
|
41
|
-
const {
|
|
45
|
+
const { mediaType } = this;
|
|
42
46
|
if (mediaType?.contentType) {
|
|
43
47
|
const arr = Array.isArray(mediaType.contentType) ? mediaType.contentType : [mediaType.contentType];
|
|
44
48
|
const contentType = arr.find(ct => type_is_1.default.is(ct, ['multipart']));
|
|
45
49
|
if (!contentType)
|
|
46
50
|
throw new common_1.NotAcceptableError('This endpoint does not accept multipart requests');
|
|
47
51
|
}
|
|
48
|
-
const reader = new multipart_reader_js_1.MultipartReader(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
52
|
+
const reader = new multipart_reader_js_1.MultipartReader(this, {
|
|
53
|
+
limits: {
|
|
54
|
+
fields: mediaType?.maxFields,
|
|
55
|
+
fieldSize: mediaType?.maxFieldsSize,
|
|
56
|
+
files: mediaType?.maxFiles,
|
|
57
|
+
fileSize: mediaType?.maxFileSize,
|
|
58
|
+
},
|
|
59
|
+
}, mediaType);
|
|
56
60
|
this._multipartReader = reader;
|
|
57
61
|
return reader;
|
|
58
62
|
}
|
|
@@ -65,29 +69,10 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
65
69
|
/** Retrieve all fields */
|
|
66
70
|
const parts = await reader.getAll();
|
|
67
71
|
/** Filter fields according to configuration */
|
|
68
|
-
this._body = [];
|
|
69
|
-
const multipartFields = mediaType?.multipartFields;
|
|
70
|
-
if (mediaType && multipartFields?.length) {
|
|
71
|
-
const fieldsFound = new Map();
|
|
72
|
-
for (const item of parts) {
|
|
73
|
-
const field = mediaType.findMultipartField(item.fieldName, item.type);
|
|
74
|
-
if (field) {
|
|
75
|
-
fieldsFound.set(field, true);
|
|
76
|
-
this._body.push(item);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/** Check required fields */
|
|
80
|
-
for (const field of multipartFields) {
|
|
81
|
-
if (field.required && !fieldsFound.get(field)) {
|
|
82
|
-
throw new common_1.BadRequestError({
|
|
83
|
-
message: `Multipart field (${field.fieldName}) is required`,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
72
|
+
this._body = [...parts];
|
|
88
73
|
return this._body;
|
|
89
74
|
}
|
|
90
|
-
this._body = await this.request.readBody({ limit: operation
|
|
75
|
+
this._body = await this.request.readBody({ limit: operation?.requestBody?.maxContentSize });
|
|
91
76
|
if (this._body != null) {
|
|
92
77
|
// Convert Buffer to string if media is text
|
|
93
78
|
if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text'])) {
|
|
@@ -104,7 +89,7 @@ class HttpContext extends execution_context_js_1.ExecutionContext {
|
|
|
104
89
|
if (!decode) {
|
|
105
90
|
decode =
|
|
106
91
|
mediaType.type?.generateCodec('decode', {
|
|
107
|
-
partial: operation
|
|
92
|
+
partial: operation?.requestBody?.partial,
|
|
108
93
|
projection: '*',
|
|
109
94
|
ignoreReadonlyFields: true,
|
|
110
95
|
}) || valgen_1.vg.isAny();
|