@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
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CollectionResourceBase = void 0;
|
|
4
|
-
const common_1 = require("@opra/common");
|
|
5
|
-
class CollectionResourceBase {
|
|
6
|
-
constructor(options) {
|
|
7
|
-
this.defaultLimit = options?.defaultLimit || 100;
|
|
8
|
-
if (options?.operations) {
|
|
9
|
-
const m = Reflect.getMetadata(common_1.METADATA_KEY, Object.getPrototypeOf(this).constructor);
|
|
10
|
-
if (m?.operations)
|
|
11
|
-
Object.keys(m.operations).forEach(k => {
|
|
12
|
-
if (!options.operations?.includes(k)) {
|
|
13
|
-
const operation = m.operations[k];
|
|
14
|
-
this[operation.handlerName] = null;
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
exports.CollectionResourceBase = CollectionResourceBase;
|
package/esm/adapter/adapter.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
3
|
-
import { Collection, DocumentFactory, ForbiddenError, getStackFileName, I18n, OpraSchema, ResourceNotFoundError, Singleton, translate, } from '@opra/common';
|
|
4
|
-
import { MetadataResource } from './internal/metadata.resource.js';
|
|
5
|
-
/**
|
|
6
|
-
* @class OpraAdapter
|
|
7
|
-
*/
|
|
8
|
-
export class OpraAdapter extends AsyncEventEmitter {
|
|
9
|
-
constructor(api) {
|
|
10
|
-
super();
|
|
11
|
-
this.api = api;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Initializes the adapter
|
|
15
|
-
* @param options
|
|
16
|
-
* @protected
|
|
17
|
-
*/
|
|
18
|
-
async init(options) {
|
|
19
|
-
this.logger = options?.logger;
|
|
20
|
-
if (options?.i18n instanceof I18n)
|
|
21
|
-
this.i18n = options.i18n;
|
|
22
|
-
else if (typeof options?.i18n === 'function')
|
|
23
|
-
this.i18n = await options.i18n();
|
|
24
|
-
else
|
|
25
|
-
this.i18n = await this._createI18n(options?.i18n);
|
|
26
|
-
this.i18n = this.i18n || I18n.defaultInstance;
|
|
27
|
-
if (!this.i18n.isInitialized)
|
|
28
|
-
await this.i18n.init();
|
|
29
|
-
if (options?.onRequest)
|
|
30
|
-
this.on('request', options.onRequest);
|
|
31
|
-
this._apiRoot = await DocumentFactory.createDocument({
|
|
32
|
-
version: OpraSchema.SpecVersion,
|
|
33
|
-
info: {
|
|
34
|
-
version: OpraSchema.SpecVersion,
|
|
35
|
-
title: 'Internal resources',
|
|
36
|
-
},
|
|
37
|
-
references: { 'api': this.api },
|
|
38
|
-
resources: [new MetadataResource(this.api)]
|
|
39
|
-
});
|
|
40
|
-
const promises = [];
|
|
41
|
-
for (const r of this.api.resources.values()) {
|
|
42
|
-
const onInit = r.onInit;
|
|
43
|
-
if (onInit)
|
|
44
|
-
promises.push((async () => onInit.call(r.controller, r))());
|
|
45
|
-
}
|
|
46
|
-
await Promise.all(promises);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Calls shutDown hook for all resources
|
|
50
|
-
*/
|
|
51
|
-
async close() {
|
|
52
|
-
const promises = [];
|
|
53
|
-
for (const r of this.api.resources.values()) {
|
|
54
|
-
const onShutdown = r.onShutdown;
|
|
55
|
-
if (onShutdown)
|
|
56
|
-
promises.push((async () => onShutdown.call(r.controller, r))());
|
|
57
|
-
}
|
|
58
|
-
await Promise.allSettled(promises);
|
|
59
|
-
}
|
|
60
|
-
async executeRequest(context) {
|
|
61
|
-
await this.emitAsync('request', context);
|
|
62
|
-
const { request, response } = context;
|
|
63
|
-
const { resource, operation } = request;
|
|
64
|
-
if (resource instanceof Collection || resource instanceof Singleton) {
|
|
65
|
-
const endpoint = resource.operations[operation];
|
|
66
|
-
if (!endpoint?.handler)
|
|
67
|
-
throw new ForbiddenError({
|
|
68
|
-
message: translate('RESOLVER_FORBIDDEN', { operation }, `The resource endpoint does not accept '{{operation}}' operations`),
|
|
69
|
-
severity: 'error',
|
|
70
|
-
code: 'RESOLVER_FORBIDDEN'
|
|
71
|
-
});
|
|
72
|
-
const value = await endpoint.handler(context);
|
|
73
|
-
// if (value == null)
|
|
74
|
-
if (value != null)
|
|
75
|
-
response.value = value;
|
|
76
|
-
const { crud, many } = request;
|
|
77
|
-
if (crud === 'delete' || (crud === 'update' && many)) {
|
|
78
|
-
let affected = 0;
|
|
79
|
-
if (typeof response.value === 'number')
|
|
80
|
-
affected = response.value;
|
|
81
|
-
if (typeof response.value === 'boolean')
|
|
82
|
-
affected = response.value ? 1 : 0;
|
|
83
|
-
if (typeof response.value === 'object')
|
|
84
|
-
affected = response.value.affectedRows || response.value.affected;
|
|
85
|
-
response.value = {
|
|
86
|
-
operation: request.crud,
|
|
87
|
-
affected
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
else if (response.value != null) {
|
|
91
|
-
if (!request.many)
|
|
92
|
-
response.value = Array.isArray(response.value) ? response.value[0] : response.value;
|
|
93
|
-
else
|
|
94
|
-
response.value = Array.isArray(response.value) ? response.value : [response.value];
|
|
95
|
-
}
|
|
96
|
-
if ((request.operation === 'get' || request.operation === 'update') && response.value == null)
|
|
97
|
-
throw new ResourceNotFoundError(resource.name, request.args.key);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async _createI18n(options) {
|
|
101
|
-
const opts = {
|
|
102
|
-
...options,
|
|
103
|
-
};
|
|
104
|
-
delete opts.resourceDirs;
|
|
105
|
-
const instance = I18n.createInstance(opts);
|
|
106
|
-
await instance.init();
|
|
107
|
-
await instance.loadResourceDir(path.resolve(getStackFileName(), '../../../i18n'));
|
|
108
|
-
if (options?.resourceDirs)
|
|
109
|
-
for (const dir of options.resourceDirs)
|
|
110
|
-
await instance.loadResourceDir(dir);
|
|
111
|
-
return instance;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This file contains code blocks from open source NodeJs project
|
|
3
|
-
https://github.com/nodejs/
|
|
4
|
-
*/
|
|
5
|
-
import * as stream from 'stream';
|
|
6
|
-
import { HTTPParser } from '@browsery/http-parser';
|
|
7
|
-
import { isReadable } from '@opra/common';
|
|
8
|
-
import { convertToHeaders, convertToHeadersDistinct } from '../helpers/convert-to-headers.js';
|
|
9
|
-
import { convertToRawHeaders } from '../helpers/convert-to-raw-headers.js';
|
|
10
|
-
export const CRLF = Buffer.from('\r\n');
|
|
11
|
-
export const kHeaders = Symbol('kHeaders');
|
|
12
|
-
export const kHeadersDistinct = Symbol('kHeadersDistinct');
|
|
13
|
-
export const kTrailers = Symbol('kTrailers');
|
|
14
|
-
export const kTrailersDistinct = Symbol('kTrailersDistinct');
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
* @class HttpIncomingMessageHost
|
|
18
|
-
*/
|
|
19
|
-
export class HttpIncomingMessageHost {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.rawHeaders = [];
|
|
22
|
-
this.rawTrailers = [];
|
|
23
|
-
this.complete = false;
|
|
24
|
-
this.joinDuplicateHeaders = false;
|
|
25
|
-
stream.Readable.apply(this);
|
|
26
|
-
}
|
|
27
|
-
get httpVersion() {
|
|
28
|
-
return this.httpVersionMajor
|
|
29
|
-
? this.httpVersionMajor + '.' + this.httpVersionMinor
|
|
30
|
-
: '';
|
|
31
|
-
}
|
|
32
|
-
get headers() {
|
|
33
|
-
if (!this[kHeaders])
|
|
34
|
-
this[kHeaders] = convertToHeaders(this.rawHeaders, {}, this.joinDuplicateHeaders);
|
|
35
|
-
return this[kHeaders];
|
|
36
|
-
}
|
|
37
|
-
set headers(headers) {
|
|
38
|
-
this[kHeaders] = headers;
|
|
39
|
-
}
|
|
40
|
-
get headersDistinct() {
|
|
41
|
-
if (!this[kHeadersDistinct])
|
|
42
|
-
this[kHeadersDistinct] = convertToHeadersDistinct(this.rawHeaders, {});
|
|
43
|
-
return this[kHeadersDistinct];
|
|
44
|
-
}
|
|
45
|
-
get trailers() {
|
|
46
|
-
if (!this[kTrailers])
|
|
47
|
-
this[kTrailers] = convertToHeaders(this.rawTrailers, {}, this.joinDuplicateHeaders);
|
|
48
|
-
return this[kTrailers];
|
|
49
|
-
}
|
|
50
|
-
set trailers(trailers) {
|
|
51
|
-
this[kTrailers] = trailers;
|
|
52
|
-
}
|
|
53
|
-
get trailersDistinct() {
|
|
54
|
-
if (!this[kTrailersDistinct])
|
|
55
|
-
this[kTrailersDistinct] = convertToHeadersDistinct(this.rawTrailers, {});
|
|
56
|
-
return this[kTrailersDistinct];
|
|
57
|
-
}
|
|
58
|
-
_readConfig(init) {
|
|
59
|
-
this.complete = true;
|
|
60
|
-
this.httpVersionMajor = init?.httpVersionMajor || 1;
|
|
61
|
-
this.httpVersionMinor = init?.httpVersionMinor || 0;
|
|
62
|
-
this.method = (init.method || 'GET').toUpperCase();
|
|
63
|
-
this.url = init.url || '';
|
|
64
|
-
this.body = init.body;
|
|
65
|
-
if (init.headers)
|
|
66
|
-
this.rawHeaders = Array.isArray(init.headers) ? init.headers : convertToRawHeaders(init.headers);
|
|
67
|
-
if (init.trailers)
|
|
68
|
-
this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : convertToRawHeaders(init.trailers);
|
|
69
|
-
this.ip = init.ip || '';
|
|
70
|
-
this.ips = init.ips || (this.ip ? [this.ip] : []);
|
|
71
|
-
}
|
|
72
|
-
_readBuffer(buf) {
|
|
73
|
-
const parser = new HTTPParser(HTTPParser.REQUEST);
|
|
74
|
-
let bodyChunks;
|
|
75
|
-
parser[HTTPParser.kOnHeadersComplete] = (info) => {
|
|
76
|
-
this.httpVersionMajor = info.versionMajor;
|
|
77
|
-
this.httpVersionMinor = info.versionMinor;
|
|
78
|
-
this.rawHeaders = info.headers;
|
|
79
|
-
this.method = HTTPParser.methods[info.method];
|
|
80
|
-
this.url = info.url;
|
|
81
|
-
};
|
|
82
|
-
parser[HTTPParser.kOnHeaders] = (trailers) => {
|
|
83
|
-
this.rawTrailers = trailers;
|
|
84
|
-
};
|
|
85
|
-
parser[HTTPParser.kOnBody] = (chunk, offset, length) => {
|
|
86
|
-
bodyChunks = bodyChunks || [];
|
|
87
|
-
bodyChunks.push(chunk.subarray(offset, offset + length));
|
|
88
|
-
};
|
|
89
|
-
parser[HTTPParser.kOnMessageComplete] = () => {
|
|
90
|
-
this.complete = true;
|
|
91
|
-
if (bodyChunks)
|
|
92
|
-
this.body = Buffer.concat(bodyChunks);
|
|
93
|
-
};
|
|
94
|
-
const buffer = Buffer.from(buf);
|
|
95
|
-
let x = parser.execute(buffer, 0, buffer.length);
|
|
96
|
-
if (typeof x === 'object')
|
|
97
|
-
throw x;
|
|
98
|
-
if (!this.complete) {
|
|
99
|
-
x = parser.execute(CRLF);
|
|
100
|
-
if (typeof x === 'object')
|
|
101
|
-
throw x;
|
|
102
|
-
}
|
|
103
|
-
parser.finish();
|
|
104
|
-
}
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
106
|
-
_readStream(readable) {
|
|
107
|
-
throw new Error('_readStream is not implemented yet');
|
|
108
|
-
}
|
|
109
|
-
static create(init) {
|
|
110
|
-
const msg = new HttpIncomingMessageHost();
|
|
111
|
-
if (Buffer.isBuffer(init))
|
|
112
|
-
msg._readBuffer(init);
|
|
113
|
-
else if (isReadable(init)) {
|
|
114
|
-
throw new Error('fromStream is not implemented yet');
|
|
115
|
-
}
|
|
116
|
-
else if (init)
|
|
117
|
-
msg._readConfig(init);
|
|
118
|
-
return msg;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
// Apply mixins
|
|
122
|
-
Object.assign(HttpIncomingMessageHost.prototype, stream.Readable.prototype);
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { BadRequestError, MethodNotAllowedError } from '@opra/common';
|
|
2
|
-
import { RequestHost } from '../../request.host.js';
|
|
3
|
-
export async function parseCollectionRequest(incoming, resource, url) {
|
|
4
|
-
if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
|
|
5
|
-
incoming.headers['content-type'] !== 'application/json')
|
|
6
|
-
throw new BadRequestError({ message: 'Unsupported Content-Type' });
|
|
7
|
-
url.searchParams.define({
|
|
8
|
-
'$search': { codec: 'string' },
|
|
9
|
-
'$pick': { codec: 'string', array: 'strict' },
|
|
10
|
-
'$omit': { codec: 'string', array: 'strict' },
|
|
11
|
-
'$include': { codec: 'string', array: 'strict' },
|
|
12
|
-
'$sort': { codec: 'string', array: 'strict' },
|
|
13
|
-
'$filter': { codec: 'filter' },
|
|
14
|
-
'$limit': { codec: 'number' },
|
|
15
|
-
'$skip': { codec: 'number' },
|
|
16
|
-
'$distinct': { codec: 'boolean' },
|
|
17
|
-
'$count': { codec: 'boolean' },
|
|
18
|
-
});
|
|
19
|
-
url.parse(incoming.url || '');
|
|
20
|
-
const contentId = incoming.headers['content-id'];
|
|
21
|
-
const p = url.path.get(0);
|
|
22
|
-
const params = url.searchParams;
|
|
23
|
-
switch (incoming.method) {
|
|
24
|
-
case 'POST': {
|
|
25
|
-
if (!p.key) {
|
|
26
|
-
const pick = params.get('$pick');
|
|
27
|
-
const omit = params.get('$omit');
|
|
28
|
-
const include = params.get('$include');
|
|
29
|
-
return new RequestHost({
|
|
30
|
-
http: incoming,
|
|
31
|
-
kind: 'CollectionCreateRequest',
|
|
32
|
-
contentId,
|
|
33
|
-
resource,
|
|
34
|
-
operation: 'create',
|
|
35
|
-
crud: 'create',
|
|
36
|
-
many: false,
|
|
37
|
-
args: {
|
|
38
|
-
data: incoming.body,
|
|
39
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
40
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
41
|
-
include: include && resource.normalizeFieldPath(include)
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
case 'DELETE': {
|
|
48
|
-
if (p.key) {
|
|
49
|
-
return new RequestHost({
|
|
50
|
-
http: incoming,
|
|
51
|
-
kind: 'CollectionDeleteRequest',
|
|
52
|
-
contentId,
|
|
53
|
-
resource,
|
|
54
|
-
operation: 'delete',
|
|
55
|
-
crud: 'delete',
|
|
56
|
-
many: false,
|
|
57
|
-
args: {
|
|
58
|
-
key: resource.parseKeyValue(p.key)
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
63
|
-
return new RequestHost({
|
|
64
|
-
http: incoming,
|
|
65
|
-
kind: 'CollectionDeleteManyRequest',
|
|
66
|
-
contentId,
|
|
67
|
-
resource,
|
|
68
|
-
operation: 'deleteMany',
|
|
69
|
-
crud: 'delete',
|
|
70
|
-
many: true,
|
|
71
|
-
args: {
|
|
72
|
-
filter
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
case 'GET': {
|
|
77
|
-
const pick = params.get('$pick');
|
|
78
|
-
const omit = params.get('$omit');
|
|
79
|
-
const include = params.get('$include');
|
|
80
|
-
if (p.key) {
|
|
81
|
-
return new RequestHost({
|
|
82
|
-
http: incoming,
|
|
83
|
-
kind: 'CollectionGetRequest',
|
|
84
|
-
contentId,
|
|
85
|
-
resource,
|
|
86
|
-
operation: 'get',
|
|
87
|
-
crud: 'read',
|
|
88
|
-
many: false,
|
|
89
|
-
args: {
|
|
90
|
-
key: resource.parseKeyValue(p.key),
|
|
91
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
92
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
93
|
-
include: include && resource.normalizeFieldPath(include)
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
98
|
-
const sort = params.get('$sort');
|
|
99
|
-
return new RequestHost({
|
|
100
|
-
http: incoming,
|
|
101
|
-
kind: 'CollectionFindManyRequest',
|
|
102
|
-
contentId,
|
|
103
|
-
resource,
|
|
104
|
-
operation: 'findMany',
|
|
105
|
-
crud: 'read',
|
|
106
|
-
many: true,
|
|
107
|
-
args: {
|
|
108
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
109
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
110
|
-
include: include && resource.normalizeFieldPath(include),
|
|
111
|
-
sort: sort && resource.normalizeSortFields(sort),
|
|
112
|
-
filter,
|
|
113
|
-
limit: params.get('$limit'),
|
|
114
|
-
skip: params.get('$skip'),
|
|
115
|
-
distinct: params.get('$distinct'),
|
|
116
|
-
count: params.get('$count'),
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
case 'PATCH': {
|
|
121
|
-
if (p.key) {
|
|
122
|
-
const pick = params.get('$pick');
|
|
123
|
-
const omit = params.get('$omit');
|
|
124
|
-
const include = params.get('$include');
|
|
125
|
-
return new RequestHost({
|
|
126
|
-
http: incoming,
|
|
127
|
-
kind: 'CollectionUpdateRequest',
|
|
128
|
-
contentId,
|
|
129
|
-
resource,
|
|
130
|
-
operation: 'update',
|
|
131
|
-
crud: 'update',
|
|
132
|
-
many: false,
|
|
133
|
-
args: {
|
|
134
|
-
key: resource.parseKeyValue(p.key),
|
|
135
|
-
data: incoming.body,
|
|
136
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
137
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
138
|
-
include: include && resource.normalizeFieldPath(include),
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
143
|
-
return new RequestHost({
|
|
144
|
-
http: incoming,
|
|
145
|
-
kind: 'CollectionUpdateManyRequest',
|
|
146
|
-
contentId,
|
|
147
|
-
resource,
|
|
148
|
-
operation: 'updateMany',
|
|
149
|
-
crud: 'update',
|
|
150
|
-
many: true,
|
|
151
|
-
args: {
|
|
152
|
-
data: incoming.body,
|
|
153
|
-
filter,
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
throw new MethodNotAllowedError({
|
|
159
|
-
message: `Collection resource does not accept http "${incoming.method}" method`
|
|
160
|
-
});
|
|
161
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { BadRequestError, Collection, OpraURL, Singleton } from '@opra/common';
|
|
2
|
-
import { parseCollectionRequest } from './parse-collection-request.js';
|
|
3
|
-
import { parseSingletonRequest } from './parse-singleton-request.js';
|
|
4
|
-
export async function parseRequest(api, incoming) {
|
|
5
|
-
const url = new OpraURL(incoming.url);
|
|
6
|
-
if (!url.path.size) {
|
|
7
|
-
// Batch
|
|
8
|
-
if (incoming.headers['content-type'] === 'multipart/mixed') {
|
|
9
|
-
// todo
|
|
10
|
-
}
|
|
11
|
-
throw new BadRequestError();
|
|
12
|
-
}
|
|
13
|
-
const p = url.path.get(0);
|
|
14
|
-
const resource = api.getResource(p.resource);
|
|
15
|
-
if (resource instanceof Collection)
|
|
16
|
-
return await parseCollectionRequest(incoming, resource, url);
|
|
17
|
-
if (resource instanceof Singleton)
|
|
18
|
-
return await parseSingletonRequest(incoming, resource, url);
|
|
19
|
-
throw new BadRequestError();
|
|
20
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { BadRequestError, MethodNotAllowedError } from '@opra/common';
|
|
2
|
-
import { RequestHost } from '../../request.host.js';
|
|
3
|
-
export async function parseSingletonRequest(incoming, resource, url) {
|
|
4
|
-
if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
|
|
5
|
-
incoming.headers['content-type'] !== 'application/json')
|
|
6
|
-
throw new BadRequestError({ message: 'Unsupported Content-Type' });
|
|
7
|
-
url.searchParams.define({
|
|
8
|
-
'$pick': { codec: 'string', array: 'strict' },
|
|
9
|
-
'$omit': { codec: 'string', array: 'strict' },
|
|
10
|
-
'$include': { codec: 'string', array: 'strict' }
|
|
11
|
-
});
|
|
12
|
-
url.parse(incoming.url || '');
|
|
13
|
-
const contentId = incoming.headers['content-id'];
|
|
14
|
-
const params = url.searchParams;
|
|
15
|
-
switch (incoming.method) {
|
|
16
|
-
case 'POST': {
|
|
17
|
-
const pick = params.get('$pick');
|
|
18
|
-
const omit = params.get('$omit');
|
|
19
|
-
const include = params.get('$include');
|
|
20
|
-
return new RequestHost({
|
|
21
|
-
http: incoming,
|
|
22
|
-
kind: 'SingletonCreateRequest',
|
|
23
|
-
contentId,
|
|
24
|
-
resource,
|
|
25
|
-
operation: 'create',
|
|
26
|
-
crud: 'create',
|
|
27
|
-
many: false,
|
|
28
|
-
args: {
|
|
29
|
-
data: incoming.body,
|
|
30
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
31
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
32
|
-
include: include && resource.normalizeFieldPath(include),
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
case 'DELETE': {
|
|
37
|
-
return new RequestHost({
|
|
38
|
-
http: incoming,
|
|
39
|
-
kind: 'SingletonDeleteRequest',
|
|
40
|
-
contentId,
|
|
41
|
-
resource,
|
|
42
|
-
operation: 'delete',
|
|
43
|
-
crud: 'delete',
|
|
44
|
-
many: false,
|
|
45
|
-
args: {}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
case 'GET': {
|
|
49
|
-
const pick = params.get('$pick');
|
|
50
|
-
const omit = params.get('$omit');
|
|
51
|
-
const include = params.get('$include');
|
|
52
|
-
return new RequestHost({
|
|
53
|
-
http: incoming,
|
|
54
|
-
kind: 'SingletonGetRequest',
|
|
55
|
-
contentId,
|
|
56
|
-
resource,
|
|
57
|
-
operation: 'get',
|
|
58
|
-
crud: 'read',
|
|
59
|
-
many: false,
|
|
60
|
-
args: {
|
|
61
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
62
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
63
|
-
include: include && resource.normalizeFieldPath(include),
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
case 'PATCH': {
|
|
68
|
-
const pick = params.get('$pick');
|
|
69
|
-
const omit = params.get('$omit');
|
|
70
|
-
const include = params.get('$include');
|
|
71
|
-
return new RequestHost({
|
|
72
|
-
http: incoming,
|
|
73
|
-
kind: 'SingletonUpdateRequest',
|
|
74
|
-
contentId,
|
|
75
|
-
resource,
|
|
76
|
-
operation: 'update',
|
|
77
|
-
crud: 'update',
|
|
78
|
-
many: false,
|
|
79
|
-
args: {
|
|
80
|
-
data: incoming.body,
|
|
81
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
82
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
83
|
-
include: include && resource.normalizeFieldPath(include),
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
default:
|
|
88
|
-
throw new MethodNotAllowedError({
|
|
89
|
-
message: `Singleton resource does not accept http "${incoming.method}" method`
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { ApiDocument, cloneObject, Singleton } from '@opra/common';
|
|
3
|
-
export let MetadataResource = class MetadataResource {
|
|
4
|
-
constructor(document) {
|
|
5
|
-
this.document = document;
|
|
6
|
-
this._schema = document.exportSchema();
|
|
7
|
-
}
|
|
8
|
-
get() {
|
|
9
|
-
return cloneObject(this.document.exportSchema(), true);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
__decorate([
|
|
13
|
-
Singleton.Get(),
|
|
14
|
-
__metadata("design:type", Function),
|
|
15
|
-
__metadata("design:paramtypes", []),
|
|
16
|
-
__metadata("design:returntype", void 0)
|
|
17
|
-
], MetadataResource.prototype, "get", null);
|
|
18
|
-
MetadataResource = __decorate([
|
|
19
|
-
Singleton(Object, {
|
|
20
|
-
name: '$metadata',
|
|
21
|
-
}),
|
|
22
|
-
__metadata("design:paramtypes", [ApiDocument])
|
|
23
|
-
], MetadataResource);
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
|
-
export class RequestContextHost extends AsyncEventEmitter {
|
|
3
|
-
constructor(protocol, platform, api, _request, _response) {
|
|
4
|
-
super();
|
|
5
|
-
this.protocol = protocol;
|
|
6
|
-
this.platform = platform;
|
|
7
|
-
this.api = api;
|
|
8
|
-
this._request = _request;
|
|
9
|
-
this._response = _response;
|
|
10
|
-
if (this.protocol === 'http') {
|
|
11
|
-
this._http = {
|
|
12
|
-
platform,
|
|
13
|
-
request: this._request.switchToHttp(),
|
|
14
|
-
response: this._response.switchToHttp(),
|
|
15
|
-
switchToContext: () => this
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
get request() {
|
|
20
|
-
return this._request;
|
|
21
|
-
}
|
|
22
|
-
get response() {
|
|
23
|
-
return this._response;
|
|
24
|
-
}
|
|
25
|
-
switchToHttp() {
|
|
26
|
-
if (this._http)
|
|
27
|
-
return this._http;
|
|
28
|
-
throw new TypeError('Not executing in an "Http" context');
|
|
29
|
-
}
|
|
30
|
-
switchToWs() {
|
|
31
|
-
if (this._ws)
|
|
32
|
-
return this._ws;
|
|
33
|
-
throw new TypeError('Not executing in an "WebSocket" context');
|
|
34
|
-
}
|
|
35
|
-
switchToRpc() {
|
|
36
|
-
if (this._rpc)
|
|
37
|
-
return this._rpc;
|
|
38
|
-
throw new TypeError('Not executing in an "RPC" context');
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { METADATA_KEY } from '@opra/common';
|
|
2
|
-
export class CollectionResourceBase {
|
|
3
|
-
constructor(options) {
|
|
4
|
-
this.defaultLimit = options?.defaultLimit || 100;
|
|
5
|
-
if (options?.operations) {
|
|
6
|
-
const m = Reflect.getMetadata(METADATA_KEY, Object.getPrototypeOf(this).constructor);
|
|
7
|
-
if (m?.operations)
|
|
8
|
-
Object.keys(m.operations).forEach(k => {
|
|
9
|
-
if (!options.operations?.includes(k)) {
|
|
10
|
-
const operation = m.operations[k];
|
|
11
|
-
this[operation.handlerName] = null;
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { Collection, OpraURL } from '@opra/common';
|
|
2
|
-
import { Request } from '../../interfaces/request.interface.js';
|
|
3
|
-
import { HttpServerRequest } from '../impl/http-server-request.js';
|
|
4
|
-
export declare function parseCollectionRequest(incoming: HttpServerRequest, resource: Collection, url: OpraURL): Promise<Request>;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { ApiDocument } from '@opra/common';
|
|
2
|
-
import { Request } from '../../interfaces/request.interface.js';
|
|
3
|
-
import { HttpServerRequest } from '../impl/http-server-request.js';
|
|
4
|
-
export declare function parseRequest(api: ApiDocument, incoming: HttpServerRequest): Promise<Request>;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { OpraURL, Singleton } from '@opra/common';
|
|
2
|
-
import { Request } from '../../interfaces/request.interface.js';
|
|
3
|
-
import { HttpServerRequest } from '../impl/http-server-request.js';
|
|
4
|
-
export declare function parseSingletonRequest(incoming: HttpServerRequest, resource: Singleton, url: OpraURL): Promise<Request>;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { ApiDocument } from '@opra/common';
|
|
2
|
-
import { HttpServerRequest } from '../http/impl/http-server-request.js';
|
|
3
|
-
import { HttpServerResponse } from '../http/impl/http-server-response.js';
|
|
4
|
-
import { Request } from './request.interface.js';
|
|
5
|
-
import { Response } from './response.interface.js';
|
|
6
|
-
export declare namespace RequestContext {
|
|
7
|
-
type Protocol = 'http' | 'ws' | 'rpc';
|
|
8
|
-
}
|
|
9
|
-
export interface RequestContext {
|
|
10
|
-
readonly protocol: RequestContext.Protocol;
|
|
11
|
-
readonly platform: string;
|
|
12
|
-
readonly api: ApiDocument;
|
|
13
|
-
readonly request: Request;
|
|
14
|
-
readonly response: Response;
|
|
15
|
-
user?: any;
|
|
16
|
-
switchToHttp(): HttpMessageContext;
|
|
17
|
-
switchToWs(): WsMessageContext;
|
|
18
|
-
switchToRpc(): RpcMessageContext;
|
|
19
|
-
}
|
|
20
|
-
export interface HttpMessageContext {
|
|
21
|
-
readonly platform: string;
|
|
22
|
-
readonly request: HttpServerRequest;
|
|
23
|
-
readonly response: HttpServerResponse;
|
|
24
|
-
switchToContext(): RequestContext;
|
|
25
|
-
}
|
|
26
|
-
export interface WsMessageContext {
|
|
27
|
-
switchToContext(): RequestContext;
|
|
28
|
-
}
|
|
29
|
-
export interface RpcMessageContext {
|
|
30
|
-
switchToContext(): RequestContext;
|
|
31
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { OpraSchema, Resource } from '@opra/common';
|
|
2
|
-
import { HttpServerRequest } from '../http/impl/http-server-request.js';
|
|
3
|
-
export interface Request {
|
|
4
|
-
readonly contentId: string;
|
|
5
|
-
readonly kind: string;
|
|
6
|
-
readonly resource: Resource;
|
|
7
|
-
readonly resourceKind: OpraSchema.Resource.Kind;
|
|
8
|
-
readonly operation: string;
|
|
9
|
-
readonly crud: 'create' | 'read' | 'update' | 'delete';
|
|
10
|
-
readonly many: boolean;
|
|
11
|
-
readonly args: any;
|
|
12
|
-
switchToHttp(): HttpServerRequest;
|
|
13
|
-
switchToWs(): never;
|
|
14
|
-
switchToRpc(): never;
|
|
15
|
-
}
|