@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,23 @@
|
|
|
1
|
+
import { ForbiddenError, translate } from '@opra/common';
|
|
2
|
+
/**
|
|
3
|
+
* @class RequestHandlerBase
|
|
4
|
+
*/
|
|
5
|
+
export class RequestHandlerBase {
|
|
6
|
+
constructor(adapter) {
|
|
7
|
+
this.adapter = adapter;
|
|
8
|
+
}
|
|
9
|
+
async assertOperation(resource, operation) {
|
|
10
|
+
const controller = await this.adapter.getController(resource);
|
|
11
|
+
const operationMeta = (typeof controller?.[operation] === 'function') && resource.operations[operation];
|
|
12
|
+
if (operationMeta)
|
|
13
|
+
return {
|
|
14
|
+
...operationMeta,
|
|
15
|
+
controller
|
|
16
|
+
};
|
|
17
|
+
throw new ForbiddenError({
|
|
18
|
+
message: translate('RESOLVER_FORBIDDEN', { resource: resource.name, operation }, `'{{resource}}' endpoint does not accept '{{operation}}' operations`),
|
|
19
|
+
severity: 'error',
|
|
20
|
+
code: 'RESOLVER_FORBIDDEN'
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import { BadRequestError, HttpStatusCodes, isReadable, OpraException, Storage, uid } from '@opra/common';
|
|
4
|
+
import { OperationContext } from '../../operation-context.js';
|
|
5
|
+
import { RequestHost } from '../../request.host.js';
|
|
6
|
+
import { ResponseHost } from '../../response.host.js';
|
|
7
|
+
import { MultipartIterator } from '../helpers/multipart-helper.js';
|
|
8
|
+
import { RequestHandlerBase } from './request-handler-base.js';
|
|
9
|
+
/**
|
|
10
|
+
* @class StorageRequestHandler
|
|
11
|
+
*/
|
|
12
|
+
export class StorageRequestHandler extends RequestHandlerBase {
|
|
13
|
+
constructor(adapter, options) {
|
|
14
|
+
super(adapter);
|
|
15
|
+
this.adapter = adapter;
|
|
16
|
+
this._uploadDir = options?.uploadDir || os.tmpdir();
|
|
17
|
+
}
|
|
18
|
+
async processRequest(executionContext) {
|
|
19
|
+
const { incoming, outgoing } = executionContext.switchToHttp();
|
|
20
|
+
// Parse incoming message and create Request object
|
|
21
|
+
const request = await this.parseRequest(executionContext, incoming);
|
|
22
|
+
if (!request)
|
|
23
|
+
return;
|
|
24
|
+
const response = new ResponseHost({ http: outgoing });
|
|
25
|
+
const context = OperationContext.from(executionContext, request, response);
|
|
26
|
+
// Execute operation
|
|
27
|
+
await this.executeOperation(context);
|
|
28
|
+
if (response.errors.length) {
|
|
29
|
+
context.errors.push(...response.errors);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await this.sendResponse(context);
|
|
33
|
+
}
|
|
34
|
+
async parseRequest(executionContext, incoming) {
|
|
35
|
+
const contentId = incoming.headers['content-id'];
|
|
36
|
+
const p = incoming.parsedUrl.path[0];
|
|
37
|
+
const resource = this.adapter.api.getResource(p.resource);
|
|
38
|
+
try {
|
|
39
|
+
if (!(resource instanceof Storage))
|
|
40
|
+
return;
|
|
41
|
+
switch (incoming.method) {
|
|
42
|
+
case 'GET': {
|
|
43
|
+
const operationMeta = await this.assertOperation(resource, 'get');
|
|
44
|
+
return new RequestHost({
|
|
45
|
+
controller: operationMeta.controller,
|
|
46
|
+
http: incoming,
|
|
47
|
+
resource,
|
|
48
|
+
operation: 'get',
|
|
49
|
+
contentId
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
case 'DELETE': {
|
|
53
|
+
const operationMeta = await this.assertOperation(resource, 'delete');
|
|
54
|
+
return new RequestHost({
|
|
55
|
+
controller: operationMeta.controller,
|
|
56
|
+
http: incoming,
|
|
57
|
+
resource,
|
|
58
|
+
operation: 'delete',
|
|
59
|
+
contentId
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
case 'POST': {
|
|
63
|
+
const operationMeta = await this.assertOperation(resource, 'post');
|
|
64
|
+
await fs.mkdir(this._uploadDir, { recursive: true });
|
|
65
|
+
const multipartIterator = new MultipartIterator(incoming, {
|
|
66
|
+
...operationMeta,
|
|
67
|
+
filename: () => this.adapter.serviceName + '_p' + process.pid +
|
|
68
|
+
't' + String(Date.now()).substring(8) + 'r' + uid(12)
|
|
69
|
+
});
|
|
70
|
+
multipartIterator.pause();
|
|
71
|
+
// Add an hook to clean up files after request finished
|
|
72
|
+
executionContext.on('finish', async () => {
|
|
73
|
+
multipartIterator.cancel();
|
|
74
|
+
await multipartIterator.deleteFiles().catch(() => void 0);
|
|
75
|
+
});
|
|
76
|
+
return new RequestHost({
|
|
77
|
+
controller: operationMeta.controller,
|
|
78
|
+
http: incoming,
|
|
79
|
+
resource,
|
|
80
|
+
operation: 'post',
|
|
81
|
+
contentId,
|
|
82
|
+
parts: multipartIterator
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
if (e instanceof OpraException)
|
|
89
|
+
throw e;
|
|
90
|
+
throw new BadRequestError(e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async executeOperation(context) {
|
|
94
|
+
const request = context.request;
|
|
95
|
+
const { response } = context;
|
|
96
|
+
// Call operation handler method
|
|
97
|
+
let value;
|
|
98
|
+
try {
|
|
99
|
+
value = await request.controller[request.operation].call(request.controller, context);
|
|
100
|
+
if (response.value == null)
|
|
101
|
+
response.value = value;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
response.errors.push(error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async sendResponse(context) {
|
|
108
|
+
const { response } = context;
|
|
109
|
+
const outgoing = response.switchToHttp();
|
|
110
|
+
outgoing.statusCode = outgoing.statusCode || HttpStatusCodes.OK;
|
|
111
|
+
if (response.value != null) {
|
|
112
|
+
if (typeof response.value === 'string') {
|
|
113
|
+
if (!outgoing.hasHeader('content-type'))
|
|
114
|
+
outgoing.setHeader('content-type', 'text/plain');
|
|
115
|
+
outgoing.send(response.value);
|
|
116
|
+
}
|
|
117
|
+
else if (Buffer.isBuffer(response.value) || isReadable(response.value)) {
|
|
118
|
+
if (!outgoing.hasHeader('content-type'))
|
|
119
|
+
outgoing.setHeader('content-type', 'application/octet-stream');
|
|
120
|
+
outgoing.send(response.value);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
outgoing.setHeader('content-type', 'application/json; charset=utf-8');
|
|
124
|
+
outgoing.send(JSON.stringify(response.value));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
outgoing.end();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export var OperationContext;
|
|
2
|
+
(function (OperationContext) {
|
|
3
|
+
function from(executionContext, request, response) {
|
|
4
|
+
const out = {
|
|
5
|
+
request,
|
|
6
|
+
response,
|
|
7
|
+
requestScope: {}
|
|
8
|
+
};
|
|
9
|
+
Object.setPrototypeOf(out, executionContext);
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
OperationContext.from = from;
|
|
13
|
+
})(OperationContext || (OperationContext = {}));
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { pascalCase } from 'putil-varhelpers';
|
|
3
|
+
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
4
|
+
import { getStackFileName, I18n, Resource } from '@opra/common';
|
|
5
|
+
import { Logger } from './services/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* @class PlatformAdapterHost
|
|
8
|
+
*/
|
|
9
|
+
export class PlatformAdapterHost extends AsyncEventEmitter {
|
|
10
|
+
constructor(api, options) {
|
|
11
|
+
super();
|
|
12
|
+
this.api = api;
|
|
13
|
+
this._controllers = new WeakMap();
|
|
14
|
+
this._initialized = false;
|
|
15
|
+
this._options = options || {};
|
|
16
|
+
this._logger = options?.logger && options.logger instanceof Logger
|
|
17
|
+
? options.logger
|
|
18
|
+
: new Logger({ instance: options?.logger });
|
|
19
|
+
// Assign events
|
|
20
|
+
if (options?.on) {
|
|
21
|
+
for (const [event, fn] of Object.entries(options.on)) {
|
|
22
|
+
/* istanbul ignore next */
|
|
23
|
+
if (typeof fn === 'function')
|
|
24
|
+
this.on(event, fn);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Make a safe service name
|
|
28
|
+
this._serviceName = pascalCase((api.info.title || '').replace(/[^a-z0-9_ ]/ig, '')) || 'OpraService';
|
|
29
|
+
if (!/^[a-z]/i.test(this._serviceName))
|
|
30
|
+
this._serviceName = 'X' + this._serviceName;
|
|
31
|
+
}
|
|
32
|
+
get platform() {
|
|
33
|
+
return this._platform;
|
|
34
|
+
}
|
|
35
|
+
get protocol() {
|
|
36
|
+
return this._protocol;
|
|
37
|
+
}
|
|
38
|
+
get serviceName() {
|
|
39
|
+
return this.api.info.title;
|
|
40
|
+
}
|
|
41
|
+
async close() {
|
|
42
|
+
const promises = [];
|
|
43
|
+
for (const r of this.api.resources.values()) {
|
|
44
|
+
const onShutdown = r.onShutdown;
|
|
45
|
+
if (onShutdown)
|
|
46
|
+
promises.push((async () => onShutdown.call(r.controller, r))());
|
|
47
|
+
}
|
|
48
|
+
await Promise.allSettled(promises);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initializes the adapter
|
|
52
|
+
*/
|
|
53
|
+
async init() {
|
|
54
|
+
if (this._initialized)
|
|
55
|
+
return;
|
|
56
|
+
// Init I18n
|
|
57
|
+
if (this._options?.i18n instanceof I18n)
|
|
58
|
+
this._i18n = this._options.i18n;
|
|
59
|
+
else if (typeof this._options?.i18n === 'function')
|
|
60
|
+
this._i18n = await this._options.i18n();
|
|
61
|
+
else
|
|
62
|
+
this._i18n = await this._createI18n(this._options?.i18n);
|
|
63
|
+
this._i18n = this._i18n || I18n.defaultInstance;
|
|
64
|
+
if (!this._i18n.isInitialized)
|
|
65
|
+
await this._i18n.init();
|
|
66
|
+
// Initialize all controllers
|
|
67
|
+
for (const resource of this.api.resources.values()) {
|
|
68
|
+
await this.getController(resource);
|
|
69
|
+
}
|
|
70
|
+
this._initialized = true;
|
|
71
|
+
}
|
|
72
|
+
async getController(resource) {
|
|
73
|
+
resource = typeof resource === 'object' && resource instanceof Resource
|
|
74
|
+
? resource : this.api.getResource(resource);
|
|
75
|
+
let controller = this._controllers.get(resource);
|
|
76
|
+
if (!controller) {
|
|
77
|
+
if (resource.controller) {
|
|
78
|
+
controller = typeof resource.controller === 'function' ?
|
|
79
|
+
new resource.controller()
|
|
80
|
+
: resource.controller;
|
|
81
|
+
// Initialize controller
|
|
82
|
+
if (typeof controller.onInit === 'function')
|
|
83
|
+
await controller.onInit.call(controller);
|
|
84
|
+
this._controllers.set(resource, controller);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return controller;
|
|
88
|
+
}
|
|
89
|
+
async _createI18n(options) {
|
|
90
|
+
const opts = {
|
|
91
|
+
...options,
|
|
92
|
+
};
|
|
93
|
+
delete opts.resourceDirs;
|
|
94
|
+
const instance = I18n.createInstance(opts);
|
|
95
|
+
await instance.init();
|
|
96
|
+
await instance.loadResourceDir(path.resolve(getStackFileName(), '../../../i18n'));
|
|
97
|
+
if (options?.resourceDirs)
|
|
98
|
+
for (const dir of options.resourceDirs)
|
|
99
|
+
await instance.loadResourceDir(dir);
|
|
100
|
+
return instance;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class Logger {
|
|
2
|
+
constructor(options = {}) {
|
|
3
|
+
this._instance = options.instance ||
|
|
4
|
+
(!(process.env.NODE_ENV || '').includes('test') ? globalThis.console : {});
|
|
5
|
+
}
|
|
6
|
+
info(message, ...optionalParams) {
|
|
7
|
+
(this._instance.info || this._instance.log)?.(message, ...optionalParams);
|
|
8
|
+
}
|
|
9
|
+
error(message, ...optionalParams) {
|
|
10
|
+
if (this._instance.error) {
|
|
11
|
+
this._instance.error(message, ...optionalParams);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
this.info(message, ...optionalParams);
|
|
15
|
+
}
|
|
16
|
+
fatal(message, ...optionalParams) {
|
|
17
|
+
if (this._instance.fatal) {
|
|
18
|
+
this._instance.fatal(message, ...optionalParams);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.error(message, ...optionalParams);
|
|
22
|
+
}
|
|
23
|
+
warn(message, ...optionalParams) {
|
|
24
|
+
this._instance.warn?.(message, ...optionalParams);
|
|
25
|
+
}
|
|
26
|
+
debug(message, ...optionalParams) {
|
|
27
|
+
this._instance.debug?.(message, ...optionalParams);
|
|
28
|
+
}
|
|
29
|
+
verbose(message, ...optionalParams) {
|
|
30
|
+
this._instance.verbose?.(message, ...optionalParams);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/esm/index.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import './augmentation/resource.augmentation.js';
|
|
3
|
+
import './augmentation/collection.augmentation.js';
|
|
4
|
+
import './augmentation/singleton.augmentation.js';
|
|
5
|
+
import './augmentation/storage.augmentation.js';
|
|
3
6
|
export * from './types.js';
|
|
4
|
-
export * from './adapter/
|
|
7
|
+
export * from './adapter/execution-context.js';
|
|
8
|
+
export * from './adapter/operation-context.js';
|
|
9
|
+
export * from './adapter/platform-adapter.js';
|
|
10
|
+
export * from './adapter/request.js';
|
|
11
|
+
export * from './adapter/response.js';
|
|
5
12
|
export * from './adapter/http/express-adapter.js';
|
|
6
13
|
export * from './adapter/http/http-adapter.js';
|
|
7
|
-
export * from './adapter/http/impl/http-
|
|
8
|
-
export * from './adapter/http/impl/http-
|
|
9
|
-
export * from './adapter/http/
|
|
10
|
-
export * from './adapter/http/
|
|
11
|
-
export * from './adapter/interfaces/request-context.interface.js';
|
|
14
|
+
export * from './adapter/http/impl/http-incoming-message.host.js';
|
|
15
|
+
export * from './adapter/http/impl/http-outgoing-message.host.js';
|
|
16
|
+
export * from './adapter/http/http-server-request.js';
|
|
17
|
+
export * from './adapter/http/http-server-response.js';
|
|
12
18
|
export * from './adapter/interfaces/logger.interface.js';
|
|
13
|
-
export * from './adapter/interfaces/request.interface.js';
|
|
14
|
-
export * from './adapter/
|
|
15
|
-
export * from './
|
|
19
|
+
export * from './adapter/interfaces/request-handler.interface.js';
|
|
20
|
+
export * from './adapter/services/logger.js';
|
|
21
|
+
export * from './adapter/http/helpers/multipart-helper.js';
|
package/i18n/en/error.json
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"UNPROCESSABLE_ENTITY": "Unprocessable entity",
|
|
11
11
|
"RESOURCE_NOT_FOUND": "Resource not found: '{{resource}}'",
|
|
12
12
|
"RESOURCE_CONFLICT": "There is already an other {{resource}} resource with same field values ({{fields}})",
|
|
13
|
-
"RESOLVER_FORBIDDEN": "The resource endpoint does not accept '{{operation}}' operations",
|
|
14
|
-
"
|
|
13
|
+
"RESOLVER_FORBIDDEN": "The {{resource}} endpoint does not accept '{{operation}}' operations",
|
|
14
|
+
"UNKNOWN_FIELD": "Unknown field '{{field}}'",
|
|
15
|
+
"UNACCEPTED_SORT_FIELD": "Field '{{field}}' is not available for sort operation",
|
|
16
|
+
"UNACCEPTED_FILTER_FIELD": "Field '{{field}}' is not available for filter operation",
|
|
17
|
+
"UNACCEPTED_FILTER_OPERATION": "'{{operation}}' for field '{{field}}' is not available for filter operation"
|
|
15
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Opra schema package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,18 +27,19 @@
|
|
|
27
27
|
"clean:cover": "rimraf ../../coverage/core"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@opra/common": "^0.
|
|
30
|
+
"@opra/common": "^0.23.0",
|
|
31
31
|
"accepts": "^1.3.8",
|
|
32
|
-
"cookie": "^0.5.0",
|
|
33
|
-
"cookie-signature": "^1.2.1",
|
|
34
32
|
"content-disposition": "^0.5.4",
|
|
35
33
|
"content-type": "^1.0.5",
|
|
34
|
+
"cookie": "^0.5.0",
|
|
35
|
+
"cookie-signature": "^1.2.1",
|
|
36
36
|
"encodeurl": "^1.0.2",
|
|
37
|
-
"fresh": "^0.5.2",
|
|
38
37
|
"formidable": "^3.5.0",
|
|
38
|
+
"fresh": "^0.5.2",
|
|
39
39
|
"mime-types": "^2.1.35",
|
|
40
40
|
"power-tasks": "^1.7.0",
|
|
41
41
|
"putil-varhelpers": "^1.6.5",
|
|
42
|
+
"putil-isplainobject": "^1.1.5",
|
|
42
43
|
"range-parser": "^1.2.1",
|
|
43
44
|
"strict-typed-events": "^2.3.1",
|
|
44
45
|
"type-is": "^1.6.18",
|
|
@@ -55,9 +56,9 @@
|
|
|
55
56
|
"@types/cookie": "^0.5.1",
|
|
56
57
|
"@types/cookie-signature": "^1.1.0",
|
|
57
58
|
"@types/encodeurl": "^1.0.0",
|
|
58
|
-
"@types/fresh": "^0.5.0",
|
|
59
|
-
"@types/formidable": "^3.4.0",
|
|
60
59
|
"@types/express": "^4.17.17",
|
|
60
|
+
"@types/formidable": "^3.4.0",
|
|
61
|
+
"@types/fresh": "^0.5.0",
|
|
61
62
|
"@types/mime-types": "^2.1.1",
|
|
62
63
|
"@types/range-parser": "^1.2.4",
|
|
63
64
|
"@types/type-is": "^1.6.3",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { HttpServerRequest } from './http/http-server-request';
|
|
2
|
+
import type { HttpServerResponse } from './http/http-server-response';
|
|
3
|
+
import type { Protocol } from './platform-adapter';
|
|
4
|
+
export declare namespace ExecutionContext {
|
|
5
|
+
type OnFinishArgs = {
|
|
6
|
+
context: ExecutionContext;
|
|
7
|
+
failed: boolean;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface ExecutionContext {
|
|
11
|
+
readonly protocol: Protocol;
|
|
12
|
+
readonly platform: string;
|
|
13
|
+
errors: Error[];
|
|
14
|
+
executionScope: Record<string | number | symbol, any>;
|
|
15
|
+
switchToHttp(): HttpMessageContext;
|
|
16
|
+
switchToWs(): WsMessageContext;
|
|
17
|
+
switchToRpc(): RpcMessageContext;
|
|
18
|
+
on(event: 'finish', fn: (args: ExecutionContext.OnFinishArgs) => void | Promise<void>): any;
|
|
19
|
+
}
|
|
20
|
+
export interface HttpMessageContext {
|
|
21
|
+
readonly platform: string;
|
|
22
|
+
readonly incoming: HttpServerRequest;
|
|
23
|
+
readonly outgoing: HttpServerResponse;
|
|
24
|
+
switchToContext(): ExecutionContext;
|
|
25
|
+
}
|
|
26
|
+
export interface WsMessageContext {
|
|
27
|
+
switchToContext(): ExecutionContext;
|
|
28
|
+
}
|
|
29
|
+
export interface RpcMessageContext {
|
|
30
|
+
switchToContext(): ExecutionContext;
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
|
+
import type { ApiDocument } from '@opra/common';
|
|
3
|
+
import type { HttpServerResponse } from './/http/http-server-response.js';
|
|
4
|
+
import type { ExecutionContext, HttpMessageContext, RpcMessageContext, WsMessageContext } from './execution-context.js';
|
|
5
|
+
import type { HttpServerRequest } from './http/http-server-request.js';
|
|
6
|
+
import { Protocol } from './platform-adapter.js';
|
|
7
|
+
export declare class ExecutionContextHost extends AsyncEventEmitter implements ExecutionContext {
|
|
8
|
+
readonly api: ApiDocument;
|
|
9
|
+
readonly platform: string;
|
|
10
|
+
readonly protocol: Protocol;
|
|
11
|
+
readonly http?: HttpMessageContext;
|
|
12
|
+
readonly ws?: WsMessageContext;
|
|
13
|
+
readonly rpc?: RpcMessageContext;
|
|
14
|
+
errors: Error[];
|
|
15
|
+
executionScope: Record<string | number | symbol, any>;
|
|
16
|
+
constructor(api: ApiDocument, platform: string, protocol: {
|
|
17
|
+
http?: {
|
|
18
|
+
incoming: HttpServerRequest;
|
|
19
|
+
outgoing: HttpServerResponse;
|
|
20
|
+
};
|
|
21
|
+
ws?: WsMessageContext;
|
|
22
|
+
rpc?: RpcMessageContext;
|
|
23
|
+
});
|
|
24
|
+
switchToHttp(): HttpMessageContext;
|
|
25
|
+
switchToWs(): WsMessageContext;
|
|
26
|
+
switchToRpc(): RpcMessageContext;
|
|
27
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { Application } from 'express';
|
|
2
|
-
import { ApiDocument } from '@opra/common';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import type { ApiDocument } from '@opra/common';
|
|
3
|
+
import type { PlatformAdapter } from '../platform-adapter.js';
|
|
4
|
+
import type { HttpAdapter } from './http-adapter.js';
|
|
5
|
+
export interface ExpressAdapter extends PlatformAdapter {
|
|
6
|
+
readonly app: Application;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* @namespace
|
|
10
|
+
*/
|
|
11
|
+
export declare namespace ExpressAdapter {
|
|
12
|
+
interface Options extends HttpAdapter.Options {
|
|
13
|
+
}
|
|
14
|
+
function create(app: Application, api: ApiDocument, options?: ExpressAdapter.Options): Promise<ExpressAdapter>;
|
|
11
15
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Application } from 'express';
|
|
2
|
+
import { ApiDocument } from '@opra/common';
|
|
3
|
+
import type { ExpressAdapter } from './express-adapter';
|
|
4
|
+
import { HttpAdapterBase } from './http-adapter-base.js';
|
|
5
|
+
export declare class ExpressAdapterHost extends HttpAdapterBase implements ExpressAdapter {
|
|
6
|
+
_platform: string;
|
|
7
|
+
_options: ExpressAdapter.Options;
|
|
8
|
+
_app: Application;
|
|
9
|
+
constructor(app: Application, api: ApiDocument, options?: ExpressAdapter.Options);
|
|
10
|
+
get app(): Application;
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import formidable from 'formidable';
|
|
4
|
+
import type IncomingForm from 'formidable/Formidable.js';
|
|
5
|
+
import { HttpIncomingMessage } from '../impl/http-incoming-message.host.js';
|
|
6
|
+
export type MultipartFile = formidable.File;
|
|
7
|
+
export type MultipartItem = {
|
|
8
|
+
field: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
file?: MultipartFile;
|
|
11
|
+
};
|
|
12
|
+
export declare class MultipartIterator extends EventEmitter {
|
|
13
|
+
protected _cancelled: boolean;
|
|
14
|
+
protected _form: IncomingForm;
|
|
15
|
+
protected _items: MultipartItem[];
|
|
16
|
+
protected _stack: MultipartItem[];
|
|
17
|
+
constructor(incoming: HttpIncomingMessage, options?: formidable.Options);
|
|
18
|
+
get items(): MultipartItem[];
|
|
19
|
+
getNext(): Promise<MultipartItem | undefined>;
|
|
20
|
+
getAll(): Promise<MultipartItem[]>;
|
|
21
|
+
cancel(): void;
|
|
22
|
+
resume(): void;
|
|
23
|
+
pause(): void;
|
|
24
|
+
deleteFiles(): Promise<PromiseSettledResult<any>[]>;
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseArrayParam(v?: string | null): string[] | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ExecutionContext } from '../execution-context.js';
|
|
2
|
+
import { RequestHandler } from '../interfaces/request-handler.interface.js';
|
|
3
|
+
import type { Protocol } from '../platform-adapter';
|
|
4
|
+
import { PlatformAdapterHost } from '../platform-adapter.host.js';
|
|
5
|
+
import { HttpServerRequest } from './http-server-request.js';
|
|
6
|
+
import { HttpServerResponse } from './http-server-response.js';
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @class HttpAdapterBase
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class HttpAdapterBase extends PlatformAdapterHost {
|
|
12
|
+
_protocol: Protocol;
|
|
13
|
+
_requestHandlers: RequestHandler[];
|
|
14
|
+
/**
|
|
15
|
+
* Main http request handler
|
|
16
|
+
* @param incoming
|
|
17
|
+
* @param outgoing
|
|
18
|
+
* @protected
|
|
19
|
+
*/
|
|
20
|
+
protected handleIncoming(incoming: HttpServerRequest, outgoing: HttpServerResponse): Promise<void>;
|
|
21
|
+
processRequest(context: ExecutionContext): Promise<void>;
|
|
22
|
+
protected handleError(context: ExecutionContext): Promise<void>;
|
|
23
|
+
}
|
|
@@ -1,33 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @namespace OpraHttpAdapter
|
|
10
|
-
*/
|
|
11
|
-
export declare namespace OpraHttpAdapter {
|
|
12
|
-
type Options = OpraAdapter.Options & {
|
|
13
|
-
prefix?: string;
|
|
14
|
-
};
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import type { ApiDocument, OpraURLPath } from '@opra/common';
|
|
4
|
+
import type { PlatformAdapter } from '../platform-adapter';
|
|
5
|
+
export interface HttpAdapter extends PlatformAdapter {
|
|
6
|
+
readonly basePath: OpraURLPath;
|
|
7
|
+
readonly server: http.Server;
|
|
15
8
|
}
|
|
16
9
|
/**
|
|
17
|
-
*
|
|
18
|
-
* @class OpraHttpAdapter
|
|
10
|
+
* @namespace HttpAdapter
|
|
19
11
|
*/
|
|
20
|
-
export declare
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* @param outgoing
|
|
26
|
-
* @protected
|
|
27
|
-
*/
|
|
28
|
-
protected handler(incoming: HttpServerRequest, outgoing: HttpServerResponse): Promise<void>;
|
|
29
|
-
protected createRequestTask(request: Request, outgoing: HttpServerResponse): Task;
|
|
30
|
-
protected executeRequest(context: RequestContext): Promise<void>;
|
|
31
|
-
protected handleError(incoming: HttpServerRequest, outgoing: HttpServerResponse, errors: any[]): Promise<void>;
|
|
32
|
-
protected log(logType: keyof ILogger, incoming: HttpServerRequest, message: string, ...optionalParams: any[]): void;
|
|
12
|
+
export declare namespace HttpAdapter {
|
|
13
|
+
type Options = PlatformAdapter.Options & {
|
|
14
|
+
basePath?: string;
|
|
15
|
+
};
|
|
16
|
+
function create(api: ApiDocument, options?: Options): Promise<HttpAdapter>;
|
|
33
17
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import { ApiDocument, OpraURLPath } from '@opra/common';
|
|
4
|
+
import type { HttpAdapter } from './http-adapter';
|
|
5
|
+
import { HttpAdapterBase } from './http-adapter-base.js';
|
|
6
|
+
/**
|
|
7
|
+
* @class HttpAdapterHost
|
|
8
|
+
*/
|
|
9
|
+
export declare class HttpAdapterHost extends HttpAdapterBase implements HttpAdapter {
|
|
10
|
+
_basePath: OpraURLPath;
|
|
11
|
+
_options: HttpAdapter.Options;
|
|
12
|
+
_server: http.Server;
|
|
13
|
+
constructor(api: ApiDocument, options?: HttpAdapter.Options);
|
|
14
|
+
get basePath(): OpraURLPath;
|
|
15
|
+
get server(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
16
|
+
protected _serverListener(incomingMessage: http.IncomingMessage, serverResponse: http.ServerResponse): void;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|