@opra/core 0.4.0 → 0.6.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/adapter.js +103 -123
- package/cjs/adapter/classes/execution-context.host.js +17 -0
- package/cjs/adapter/classes/express-request-wrapper.host.js +37 -0
- package/cjs/adapter/classes/express-response-wrapper.host.js +56 -0
- package/cjs/adapter/classes/http-execution-context.host.js +31 -0
- package/cjs/adapter/{metadata-resource.js → classes/metadata.resource.js} +3 -3
- package/cjs/adapter/express-adapter.js +6 -104
- package/cjs/adapter/http-adapter.js +282 -81
- package/cjs/adapter/request-contexts/batch-request-context.js +12 -0
- package/cjs/adapter/{query-context.js → request-contexts/request-context.js} +9 -13
- package/cjs/adapter/request-contexts/single-request-context.js +15 -0
- package/cjs/index.js +2 -2
- package/cjs/interfaces/i18n-options.interface.js +2 -0
- package/cjs/services/json-collection-service.js +36 -39
- package/cjs/services/json-singleton-service.js +9 -10
- package/cjs/utils/create-i18n.js +2 -2
- package/esm/adapter/adapter.d.ts +13 -44
- package/esm/adapter/adapter.js +89 -109
- package/esm/adapter/classes/execution-context.host.d.ts +10 -0
- package/esm/adapter/classes/execution-context.host.js +13 -0
- package/esm/adapter/classes/express-request-wrapper.host.d.ts +19 -0
- package/esm/adapter/classes/express-request-wrapper.host.js +33 -0
- package/esm/adapter/classes/express-response-wrapper.host.d.ts +22 -0
- package/esm/adapter/classes/express-response-wrapper.host.js +52 -0
- package/esm/adapter/classes/http-execution-context.host.d.ts +13 -0
- package/esm/adapter/classes/http-execution-context.host.js +27 -0
- package/esm/adapter/classes/metadata.resource.d.ts +8 -0
- package/esm/adapter/{metadata-resource.js → classes/metadata.resource.js} +2 -2
- package/esm/adapter/express-adapter.d.ts +1 -1
- package/esm/adapter/express-adapter.js +5 -103
- package/esm/adapter/http-adapter.d.ts +23 -12
- package/esm/adapter/http-adapter.js +248 -47
- package/esm/adapter/request-contexts/batch-request-context.d.ts +7 -0
- package/esm/adapter/request-contexts/batch-request-context.js +8 -0
- package/esm/adapter/request-contexts/request-context.d.ts +22 -0
- package/esm/adapter/{query-context.js → request-contexts/request-context.js} +6 -10
- package/esm/adapter/request-contexts/single-request-context.d.ts +10 -0
- package/esm/adapter/request-contexts/single-request-context.js +11 -0
- package/esm/index.d.ts +2 -2
- package/esm/index.js +2 -2
- package/esm/interfaces/execution-context.interface.d.ts +19 -11
- package/esm/interfaces/i18n-options.interface.d.ts +28 -0
- package/esm/interfaces/i18n-options.interface.js +1 -0
- package/esm/interfaces/resource.interface.d.ts +1 -1
- package/esm/services/json-collection-service.d.ts +3 -4
- package/esm/services/json-collection-service.js +17 -20
- package/esm/services/json-singleton-service.d.ts +3 -3
- package/esm/services/json-singleton-service.js +8 -8
- package/esm/utils/create-i18n.d.ts +3 -3
- package/esm/utils/create-i18n.js +1 -1
- package/package.json +7 -8
- package/cjs/enums/http-headers.enum.js +0 -395
- package/cjs/enums/http-status.enum.js +0 -300
- package/cjs/enums/index.js +0 -5
- package/cjs/helpers/headers-map.js +0 -18
- package/cjs/utils/path-to-tree.js +0 -28
- package/esm/adapter/metadata-resource.d.ts +0 -8
- package/esm/adapter/query-context.d.ts +0 -25
- package/esm/enums/http-headers.enum.d.ts +0 -370
- package/esm/enums/http-headers.enum.js +0 -392
- package/esm/enums/http-status.enum.d.ts +0 -290
- package/esm/enums/http-status.enum.js +0 -297
- package/esm/enums/index.d.ts +0 -2
- package/esm/enums/index.js +0 -2
- package/esm/helpers/headers-map.d.ts +0 -5
- package/esm/helpers/headers-map.js +0 -14
- package/esm/utils/path-to-tree.d.ts +0 -4
- package/esm/utils/path-to-tree.js +0 -24
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
import { BadRequestError, InternalServerError, IssueSeverity, MethodNotAllowedError,
|
|
2
|
-
import { CollectionCreateQuery, CollectionDeleteManyQuery, CollectionDeleteQuery, CollectionGetQuery, CollectionResourceInfo, CollectionSearchQuery, CollectionUpdateManyQuery, CollectionUpdateQuery, ComplexType, ContainerResourceInfo, FieldGetQuery, OpraSchema, SingletonGetQuery, SingletonResourceInfo, UnionType, } from '@opra/schema';
|
|
3
|
-
import { OpraURL } from '@opra/url';
|
|
4
|
-
import { HttpHeaders, HttpStatus } from '../enums/index.js';
|
|
5
|
-
import { HeadersMap } from '../helpers/headers-map.js';
|
|
1
|
+
import { BadRequestError, CollectionCreateQuery, CollectionDeleteManyQuery, CollectionDeleteQuery, CollectionGetQuery, CollectionResourceInfo, CollectionSearchQuery, CollectionUpdateManyQuery, CollectionUpdateQuery, ComplexType, ContainerResourceInfo, FieldGetQuery, HttpHeaders, HttpStatus, InternalServerError, isReadable, IssueSeverity, MethodNotAllowedError, normalizeHeaders, OpraException, OpraSchema, OpraURL, SingletonGetQuery, SingletonResourceInfo, UnionType, wrapException } from '@opra/common';
|
|
6
2
|
import { OpraAdapter } from './adapter.js';
|
|
7
|
-
import {
|
|
3
|
+
import { SingleRequestContext } from './request-contexts/single-request-context.js';
|
|
8
4
|
export class OpraHttpAdapter extends OpraAdapter {
|
|
9
|
-
|
|
10
|
-
const req = executionContext.
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
|
|
5
|
+
async parse(executionContext) {
|
|
6
|
+
const req = executionContext.getRequest();
|
|
7
|
+
const contentType = req.getHeader('content-type');
|
|
8
|
+
if (!contentType || contentType === 'application/json') {
|
|
9
|
+
const body = req.getBody();
|
|
10
|
+
const url = new OpraURL(req.getUrl());
|
|
11
|
+
return this.parseSingleQuery({
|
|
12
|
+
executionContext,
|
|
13
|
+
url,
|
|
14
|
+
method: req.getMethod(),
|
|
15
|
+
headers: req.getHeaders(),
|
|
16
|
+
body
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (typeof contentType === 'string' && contentType.startsWith('multipart/mixed')) {
|
|
20
|
+
// const m = BOUNDARY_PATTERN.exec(contentType);
|
|
21
|
+
// if (!m)
|
|
22
|
+
// throw new BadRequestError({message: 'Content-Type header does not match required format'});
|
|
23
|
+
// const url = new OpraURL(req.getUrl());
|
|
24
|
+
// return await this.parseMultiPart(executionContext, url, req.getHeaders(), req.getStream(), m[1]);
|
|
14
25
|
}
|
|
15
|
-
|
|
16
|
-
return [
|
|
17
|
-
this.prepareRequest(executionContext, url, req.getMethod(), new HeadersMap(req.getHeaders()), req.getBody())
|
|
18
|
-
];
|
|
26
|
+
throw new BadRequestError({ message: 'Unsupported Content-Type' });
|
|
19
27
|
}
|
|
20
|
-
|
|
28
|
+
parseSingleQuery(args) {
|
|
29
|
+
const { executionContext, url, method, headers, body, contentId } = args;
|
|
21
30
|
if (!url.path.size)
|
|
22
31
|
throw new BadRequestError();
|
|
23
32
|
if (method !== 'GET' && url.path.size > 1)
|
|
@@ -27,15 +36,94 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
27
36
|
throw new MethodNotAllowedError({
|
|
28
37
|
message: `Method "${method}" is not allowed by target endpoint`
|
|
29
38
|
});
|
|
30
|
-
return new
|
|
39
|
+
return new SingleRequestContext({
|
|
31
40
|
service: this.document,
|
|
32
41
|
executionContext,
|
|
42
|
+
headers,
|
|
33
43
|
query,
|
|
34
|
-
headers: new HeadersMap(),
|
|
35
44
|
params: url.searchParams,
|
|
45
|
+
contentId,
|
|
36
46
|
continueOnError: query.operation === 'read'
|
|
37
47
|
});
|
|
38
48
|
}
|
|
49
|
+
// async parseMultiPart(
|
|
50
|
+
// executionContext: TExecutionContext,
|
|
51
|
+
// url: OpraURL,
|
|
52
|
+
// headers: IncomingHttpHeaders,
|
|
53
|
+
// input: Readable,
|
|
54
|
+
// boundary: string
|
|
55
|
+
// ): Promise<BatchRequestContext> {
|
|
56
|
+
// return await new Promise((resolve, reject) => {
|
|
57
|
+
// let _resolved = false;
|
|
58
|
+
// const dicer = new Dicer({boundary});
|
|
59
|
+
// const doReject = (e) => {
|
|
60
|
+
// if (_resolved) return;
|
|
61
|
+
// _resolved = true;
|
|
62
|
+
// reject(e);
|
|
63
|
+
// taskQueue.clearQueue();
|
|
64
|
+
// dicer.destroy();
|
|
65
|
+
// }
|
|
66
|
+
// const taskQueue = new TaskQueue({concurrency: 1});
|
|
67
|
+
// taskQueue.on('error', doReject);
|
|
68
|
+
//
|
|
69
|
+
// const queries: SingleRequestContext[] = [];
|
|
70
|
+
// let partCounter = 0;
|
|
71
|
+
// dicer.on('error', doReject);
|
|
72
|
+
// dicer.on('part', part => {
|
|
73
|
+
// const partIndex = partCounter++;
|
|
74
|
+
// let header: any;
|
|
75
|
+
// const chunks: Buffer[] = [];
|
|
76
|
+
// part.on('error', doReject);
|
|
77
|
+
// part.on('header', (_header) => header = normalizeHeaders(_header));
|
|
78
|
+
// part.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
79
|
+
// part.on('end', () => {
|
|
80
|
+
// if (_resolved || !(header || chunks.length))
|
|
81
|
+
// return;
|
|
82
|
+
// const ct = header['content-type'];
|
|
83
|
+
// if (ct === 'application/http') {
|
|
84
|
+
// taskQueue.enqueue(async () => {
|
|
85
|
+
// const data = Buffer.concat(chunks);
|
|
86
|
+
// if (!(data && data.length))
|
|
87
|
+
// return;
|
|
88
|
+
// const r = HttpRequest.parse(data);
|
|
89
|
+
// await callMiddlewares(r, [jsonBodyParser]);
|
|
90
|
+
// const subUrl = new OpraURL(r.url);
|
|
91
|
+
// const contentId = header && header['content-id'];
|
|
92
|
+
// queries.push(this.parseSingleQuery({
|
|
93
|
+
// executionContext,
|
|
94
|
+
// url: subUrl,
|
|
95
|
+
// method: r.method,
|
|
96
|
+
// headers: r.headers,
|
|
97
|
+
// body: r.body,
|
|
98
|
+
// contentId
|
|
99
|
+
// }));
|
|
100
|
+
// });
|
|
101
|
+
// } else doReject(new BadRequestError({
|
|
102
|
+
// message: 'Unaccepted "content-type" header in multipart data',
|
|
103
|
+
// details: {
|
|
104
|
+
// position: `${boundary}[${partIndex}]`
|
|
105
|
+
// }
|
|
106
|
+
// }))
|
|
107
|
+
// });
|
|
108
|
+
// });
|
|
109
|
+
// dicer.on('finish', () => {
|
|
110
|
+
// taskQueue.enqueue(() => {
|
|
111
|
+
// if (_resolved) return;
|
|
112
|
+
// _resolved = true;
|
|
113
|
+
// const batch = new BatchRequestContext({
|
|
114
|
+
// service: this.document,
|
|
115
|
+
// executionContext,
|
|
116
|
+
// headers,
|
|
117
|
+
// queries,
|
|
118
|
+
// params: url.searchParams,
|
|
119
|
+
// continueOnError: false
|
|
120
|
+
// });
|
|
121
|
+
// resolve(batch);
|
|
122
|
+
// });
|
|
123
|
+
// });
|
|
124
|
+
// input.pipe(dicer);
|
|
125
|
+
// });
|
|
126
|
+
// }
|
|
39
127
|
buildQuery(url, method, body) {
|
|
40
128
|
const pathLen = url.path.size;
|
|
41
129
|
let p = url.path.get(0);
|
|
@@ -53,7 +141,12 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
53
141
|
if (resource instanceof SingletonResourceInfo && !p.key) {
|
|
54
142
|
switch (method) {
|
|
55
143
|
case 'GET': {
|
|
56
|
-
|
|
144
|
+
const searchParams = url.searchParams;
|
|
145
|
+
query = new SingletonGetQuery(resource, {
|
|
146
|
+
pick: searchParams.get('$pick'),
|
|
147
|
+
omit: searchParams.get('$omit'),
|
|
148
|
+
include: searchParams.get('$include')
|
|
149
|
+
});
|
|
57
150
|
}
|
|
58
151
|
}
|
|
59
152
|
}
|
|
@@ -154,38 +247,122 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
154
247
|
throw new BadRequestError(e);
|
|
155
248
|
}
|
|
156
249
|
}
|
|
157
|
-
async sendResponse(executionContext,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
250
|
+
async sendResponse(executionContext, requestContext) {
|
|
251
|
+
// if (requestContext instanceof BatchRequestContext)
|
|
252
|
+
// return this.sendBatchResponse(executionContext, requestContext);
|
|
253
|
+
if (requestContext instanceof SingleRequestContext)
|
|
254
|
+
return this.sendSingleResponse(executionContext, requestContext);
|
|
255
|
+
/* istanbul ignore next */
|
|
256
|
+
throw new TypeError('Invalid request context instance');
|
|
257
|
+
}
|
|
258
|
+
// protected async sendBatchResponse(executionContext: TExecutionContext, requestContext: BatchRequestContext) {
|
|
259
|
+
// const resp = executionContext.getResponse();
|
|
260
|
+
// resp.setStatus(HttpStatus.OK);
|
|
261
|
+
// resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
262
|
+
// resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
263
|
+
// resp.setHeader(HttpHeaders.Expires, '-1');
|
|
264
|
+
// if (requestContext.headers) {
|
|
265
|
+
// for (const [k, v] of Object.entries(requestContext.headers)) {
|
|
266
|
+
// if (v)
|
|
267
|
+
// resp.setHeader(k, v);
|
|
268
|
+
// }
|
|
269
|
+
// }
|
|
270
|
+
// const boundary = 'batch_' + uuid();
|
|
271
|
+
// resp.setHeader(HttpHeaders.Content_Type, 'multipart/mixed;boundary=' + boundary);
|
|
272
|
+
// resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
273
|
+
//
|
|
274
|
+
// const bodyBuilder = new HttpMultipartData();
|
|
275
|
+
//
|
|
276
|
+
// const chunks: any[] = [];
|
|
277
|
+
// let msgIdx = 0;
|
|
278
|
+
// for (const ctx of requestContext.queries) {
|
|
279
|
+
// msgIdx++;
|
|
280
|
+
// const out = this.createOutput(ctx);
|
|
281
|
+
//
|
|
282
|
+
//
|
|
283
|
+
// // chunks.push('--' + boundary + CRLF);
|
|
284
|
+
// // let s = 'Content-Type: application/http' + CRLF +
|
|
285
|
+
// // 'Content-Transfer-Encoding: binary' + CRLF +
|
|
286
|
+
// // 'Content-ID:' + (ctx.contentId || msgIdx) + CRLF +
|
|
287
|
+
// // CRLF +
|
|
288
|
+
// // 'HTTP/1.1 ' + out.status + (HttpStatus[out.status] || 'Unknown') + CRLF;
|
|
289
|
+
//
|
|
290
|
+
// let body = out.body;
|
|
291
|
+
// const headers = out.headers || {};
|
|
292
|
+
// if (body) {
|
|
293
|
+
// const contentType = String(headers['content-type'] || '').split(/\s*;\s*/);
|
|
294
|
+
// let charset = '';
|
|
295
|
+
// if (Highland.isStream(body)) {
|
|
296
|
+
// const l = parseInt(String(headers['content-length']), 10);
|
|
297
|
+
// if (isNaN(l))
|
|
298
|
+
// throw new TypeError('"content-length" header required for streamed responses');
|
|
299
|
+
// } else if (typeof body === 'object') {
|
|
300
|
+
// if (typeof body.stream === 'function') { // File and Blob
|
|
301
|
+
// contentType[0] = body.type || 'binary';
|
|
302
|
+
// headers['content-length'] = String(body.size);
|
|
303
|
+
// body = body.stream();
|
|
304
|
+
// } else if (Buffer.isBuffer(body)) {
|
|
305
|
+
// headers['content-length'] = String(body.length);
|
|
306
|
+
// } else {
|
|
307
|
+
// contentType[0] = contentType[0] || 'application/json';
|
|
308
|
+
// charset = 'utf-8';
|
|
309
|
+
// body = Buffer.from(JSON.stringify(body), 'utf-8');
|
|
310
|
+
// headers['content-length'] = String(body.length);
|
|
311
|
+
// }
|
|
312
|
+
// } else {
|
|
313
|
+
// contentType[0] = contentType[0] || 'text/plain';
|
|
314
|
+
// charset = 'utf-8';
|
|
315
|
+
// body = Buffer.from(String(body), 'utf-8');
|
|
316
|
+
// headers['content-length'] = String(body.length);
|
|
317
|
+
// }
|
|
318
|
+
// if (contentType[0]) {
|
|
319
|
+
// if (charset) {
|
|
320
|
+
// const i = contentType.findIndex(x => CHARSET_PATTERN.test(String(x)));
|
|
321
|
+
// if (i > 0) contentType[i] = 'charset=' + charset;
|
|
322
|
+
// else contentType.join('charset=' + charset);
|
|
323
|
+
// }
|
|
324
|
+
// headers['content-type'] = contentType.join(';');
|
|
325
|
+
// }
|
|
326
|
+
// }
|
|
327
|
+
// for (const [k, v] of Object.entries(headers))
|
|
328
|
+
// s += k + ': ' + (Array.isArray(v) ? v.join(';') : v) + CRLF
|
|
329
|
+
//
|
|
330
|
+
// chunks.push(s + CRLF);
|
|
331
|
+
//
|
|
332
|
+
// if (body) {
|
|
333
|
+
// if (typeof body === 'string')
|
|
334
|
+
// chunks.push(body + CRLF + CRLF);
|
|
335
|
+
// else {
|
|
336
|
+
// chunks.push(body);
|
|
337
|
+
// chunks.push(CRLF + CRLF);
|
|
338
|
+
// }
|
|
339
|
+
// }
|
|
340
|
+
// }
|
|
341
|
+
//
|
|
342
|
+
// chunks.push('--' + boundary + '--' + CRLF);
|
|
343
|
+
//
|
|
344
|
+
// resp.setHeader('content-type', 'multipart/mixed;boundary=' + boundary);
|
|
345
|
+
// resp.send(Highland(chunks).flatten());
|
|
346
|
+
// resp.end();
|
|
347
|
+
// }
|
|
348
|
+
async sendSingleResponse(executionContext, requestContext) {
|
|
349
|
+
const out = this.createOutput(requestContext);
|
|
350
|
+
const resp = executionContext.getResponse();
|
|
171
351
|
resp.setStatus(out.status);
|
|
172
|
-
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
173
352
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
174
353
|
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
175
354
|
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
176
|
-
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
177
355
|
if (out.headers) {
|
|
178
356
|
for (const [k, v] of Object.entries(out.headers)) {
|
|
179
|
-
|
|
357
|
+
if (v)
|
|
358
|
+
resp.setHeader(k, v);
|
|
180
359
|
}
|
|
181
360
|
}
|
|
182
|
-
resp.
|
|
361
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
362
|
+
if (out.body)
|
|
363
|
+
resp.send(out.body);
|
|
183
364
|
resp.end();
|
|
184
365
|
}
|
|
185
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
186
|
-
isBatch(executionContext) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
366
|
createOutput(ctx) {
|
|
190
367
|
const { query } = ctx;
|
|
191
368
|
let body;
|
|
@@ -204,24 +381,29 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
204
381
|
if (status < HttpStatus.BAD_REQUEST)
|
|
205
382
|
status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
206
383
|
}
|
|
207
|
-
body = {
|
|
384
|
+
body = this.i18n.deep({
|
|
208
385
|
operation: ctx.query.method,
|
|
209
386
|
errors: errors.map(e => e.issue)
|
|
210
|
-
};
|
|
387
|
+
});
|
|
388
|
+
body = JSON.stringify(body);
|
|
389
|
+
ctx.responseHeaders['content-type'] = 'application/json; charset=utf-8';
|
|
211
390
|
}
|
|
212
391
|
else {
|
|
213
|
-
|
|
392
|
+
if (typeof ctx.response === 'object' && !(isReadable(ctx.response) || Buffer.isBuffer(ctx.response))) {
|
|
393
|
+
body = this.i18n.deep(ctx.response);
|
|
394
|
+
body = JSON.stringify(body);
|
|
395
|
+
ctx.responseHeaders['content-type'] = 'application/json; charset=utf-8';
|
|
396
|
+
}
|
|
214
397
|
status = status || (query.operation === 'create' ? HttpStatus.CREATED : HttpStatus.OK);
|
|
215
398
|
}
|
|
216
|
-
body = this.i18n.deep(body);
|
|
217
399
|
return {
|
|
218
400
|
status,
|
|
219
|
-
headers: ctx.responseHeaders
|
|
401
|
+
headers: normalizeHeaders(ctx.responseHeaders),
|
|
220
402
|
body
|
|
221
403
|
};
|
|
222
404
|
}
|
|
223
405
|
async sendError(executionContext, error) {
|
|
224
|
-
const resp = executionContext.
|
|
406
|
+
const resp = executionContext.getResponse();
|
|
225
407
|
resp.setStatus(error.status || 500);
|
|
226
408
|
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
227
409
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
@@ -236,3 +418,22 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
236
418
|
resp.send(JSON.stringify(body));
|
|
237
419
|
}
|
|
238
420
|
}
|
|
421
|
+
// async function callMiddlewares(req: HttpRequest, middlewares: NextHandleFunction[]): Promise<void> {
|
|
422
|
+
// return new Promise<void>((resolve, reject) => {
|
|
423
|
+
// let i = 0;
|
|
424
|
+
// const next = (err?: any) => {
|
|
425
|
+
// if (err)
|
|
426
|
+
// return reject(err);
|
|
427
|
+
// const fn = middlewares[i++];
|
|
428
|
+
// if (!fn)
|
|
429
|
+
// return resolve();
|
|
430
|
+
// try {
|
|
431
|
+
// fn(req as any, {} as any, next);
|
|
432
|
+
// } catch (e) {
|
|
433
|
+
// reject(e);
|
|
434
|
+
// }
|
|
435
|
+
// }
|
|
436
|
+
// next();
|
|
437
|
+
// });
|
|
438
|
+
//
|
|
439
|
+
// }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RequestContext, RequestContextArgs } from './request-context.js';
|
|
2
|
+
import { SingleRequestContext } from './single-request-context.js';
|
|
3
|
+
export declare type BatchContextArgs = RequestContextArgs & Pick<BatchRequestContext, 'queries'>;
|
|
4
|
+
export declare class BatchRequestContext extends RequestContext {
|
|
5
|
+
readonly queries: SingleRequestContext[];
|
|
6
|
+
constructor(args: BatchContextArgs);
|
|
7
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'http';
|
|
3
|
+
import { HttpStatus, OpraDocument, OpraException, OpraURLSearchParams } from '@opra/common';
|
|
4
|
+
import { ContextType, IExecutionContext, IHttpExecutionContext } from '../../interfaces/execution-context.interface.js';
|
|
5
|
+
export declare type RequestContextArgs = Pick<RequestContext, 'contentId' | 'service' | 'executionContext' | 'params' | 'headers' | 'parentValue' | 'continueOnError'>;
|
|
6
|
+
export declare class RequestContext {
|
|
7
|
+
readonly service: OpraDocument;
|
|
8
|
+
readonly executionContext: IExecutionContext;
|
|
9
|
+
readonly params: OpraURLSearchParams;
|
|
10
|
+
readonly headers: IncomingHttpHeaders;
|
|
11
|
+
readonly contentId?: string;
|
|
12
|
+
readonly parentValue?: any;
|
|
13
|
+
readonly resultPath: string;
|
|
14
|
+
readonly responseHeaders: IncomingHttpHeaders;
|
|
15
|
+
response?: any;
|
|
16
|
+
errors: OpraException[];
|
|
17
|
+
status?: HttpStatus;
|
|
18
|
+
continueOnError?: boolean;
|
|
19
|
+
constructor(args: RequestContextArgs);
|
|
20
|
+
get type(): ContextType;
|
|
21
|
+
switchToHttp(): IHttpExecutionContext;
|
|
22
|
+
}
|
|
@@ -1,28 +1,24 @@
|
|
|
1
|
-
import { OpraURLSearchParams } from '@opra/
|
|
2
|
-
|
|
3
|
-
export class QueryContext {
|
|
1
|
+
import { OpraURLSearchParams } from '@opra/common';
|
|
2
|
+
export class RequestContext {
|
|
4
3
|
service;
|
|
5
4
|
executionContext;
|
|
6
|
-
query;
|
|
7
5
|
params;
|
|
8
6
|
headers;
|
|
7
|
+
contentId;
|
|
9
8
|
parentValue;
|
|
10
9
|
resultPath;
|
|
11
10
|
responseHeaders;
|
|
12
11
|
response;
|
|
13
12
|
errors = [];
|
|
14
13
|
status;
|
|
15
|
-
userContext;
|
|
16
14
|
continueOnError;
|
|
17
15
|
constructor(args) {
|
|
18
|
-
// Object.assign(this, args);
|
|
19
16
|
this.service = args.service;
|
|
20
17
|
this.executionContext = args.executionContext;
|
|
21
|
-
this.query = args.query;
|
|
22
|
-
// this.response = new QueryResponse();
|
|
23
18
|
this.params = this.params || new OpraURLSearchParams();
|
|
24
|
-
this.headers =
|
|
25
|
-
this.
|
|
19
|
+
this.headers = args.headers;
|
|
20
|
+
this.contentId = args.contentId;
|
|
21
|
+
this.responseHeaders = {};
|
|
26
22
|
this.resultPath = this.resultPath || '';
|
|
27
23
|
}
|
|
28
24
|
get type() {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OpraQuery } from '@opra/common';
|
|
2
|
+
import { RequestContext, RequestContextArgs } from './request-context.js';
|
|
3
|
+
export declare type QueryRequestContextArgs = RequestContextArgs & {
|
|
4
|
+
readonly query: OpraQuery;
|
|
5
|
+
};
|
|
6
|
+
export declare class SingleRequestContext extends RequestContext {
|
|
7
|
+
readonly query: OpraQuery;
|
|
8
|
+
constructor(args: QueryRequestContextArgs);
|
|
9
|
+
get userContext(): any;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RequestContext } from './request-context.js';
|
|
2
|
+
export class SingleRequestContext extends RequestContext {
|
|
3
|
+
query;
|
|
4
|
+
constructor(args) {
|
|
5
|
+
super(args);
|
|
6
|
+
this.query = args.query;
|
|
7
|
+
}
|
|
8
|
+
get userContext() {
|
|
9
|
+
return this.executionContext.userContext;
|
|
10
|
+
}
|
|
11
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
export * from './types.js';
|
|
3
|
-
export * from './enums/index.js';
|
|
4
3
|
export * from './interfaces/execution-context.interface.js';
|
|
5
4
|
export * from './interfaces/resource.interface.js';
|
|
6
|
-
export * from './
|
|
5
|
+
export * from './interfaces/i18n-options.interface.js';
|
|
6
|
+
export * from './adapter/request-contexts/single-request-context.js';
|
|
7
7
|
export * from './adapter/adapter.js';
|
|
8
8
|
export * from './adapter/http-adapter.js';
|
|
9
9
|
export * from './adapter/express-adapter.js';
|
package/esm/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
export * from './types.js';
|
|
3
|
-
export * from './enums/index.js';
|
|
4
3
|
export * from './interfaces/execution-context.interface.js';
|
|
5
4
|
export * from './interfaces/resource.interface.js';
|
|
6
|
-
export * from './
|
|
5
|
+
export * from './interfaces/i18n-options.interface.js';
|
|
6
|
+
export * from './adapter/request-contexts/single-request-context.js';
|
|
7
7
|
export * from './adapter/adapter.js';
|
|
8
8
|
export * from './adapter/http-adapter.js';
|
|
9
9
|
export * from './adapter/express-adapter.js';
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http';
|
|
4
|
+
import { Readable, Writable } from 'stream';
|
|
1
5
|
export declare type ContextType = 'http' | 'ws' | 'rpc';
|
|
2
|
-
export declare type PlatformType = 'express';
|
|
3
6
|
export declare namespace IExecutionContext {
|
|
4
7
|
type OnFinishArgs = {
|
|
5
8
|
userContext: any;
|
|
@@ -7,33 +10,38 @@ export declare namespace IExecutionContext {
|
|
|
7
10
|
};
|
|
8
11
|
}
|
|
9
12
|
export interface IExecutionContext {
|
|
13
|
+
userContext: any;
|
|
10
14
|
getType(): ContextType;
|
|
11
|
-
getPlatform():
|
|
15
|
+
getPlatform(): string;
|
|
12
16
|
switchToHttp(): IHttpExecutionContext;
|
|
13
17
|
onFinish(fn: (args: IExecutionContext.OnFinishArgs) => void | Promise<void>): any;
|
|
14
18
|
}
|
|
15
19
|
export interface IHttpExecutionContext extends IExecutionContext {
|
|
16
|
-
getRequest():
|
|
17
|
-
getResponse():
|
|
18
|
-
getRequestWrapper(): IHttpRequestWrapper;
|
|
19
|
-
getResponseWrapper(): IHttpResponseWrapper;
|
|
20
|
+
getRequest(): IHttpRequestWrapper;
|
|
21
|
+
getResponse(): IHttpResponseWrapper;
|
|
20
22
|
}
|
|
21
23
|
export interface IHttpRequestWrapper {
|
|
22
24
|
getInstance(): any;
|
|
23
25
|
getUrl(): string;
|
|
24
26
|
getMethod(): string;
|
|
25
27
|
getHeaderNames(): string[];
|
|
26
|
-
getHeader(name: string): string | undefined;
|
|
27
|
-
getHeaders():
|
|
28
|
+
getHeader(name: string): string | string[] | undefined;
|
|
29
|
+
getHeaders(): IncomingHttpHeaders;
|
|
28
30
|
getBody(): any;
|
|
31
|
+
isCompleted(): boolean;
|
|
32
|
+
getStream(): Readable;
|
|
29
33
|
}
|
|
30
34
|
export interface IHttpResponseWrapper {
|
|
31
35
|
getInstance(): any;
|
|
36
|
+
getHeader(name: string): number | string | string[] | undefined;
|
|
37
|
+
getHeaders(): OutgoingHttpHeaders;
|
|
38
|
+
getHeaderNames(): string[];
|
|
39
|
+
hasHeader(name: string): boolean;
|
|
40
|
+
removeHeader(name: string): void;
|
|
41
|
+
setHeader(name: string, value: number | string | string[]): this;
|
|
32
42
|
getStatus(): number | undefined;
|
|
33
43
|
setStatus(value: number): this;
|
|
34
|
-
|
|
35
|
-
getHeader(name: string): string | undefined;
|
|
36
|
-
setHeader(name: string, value: string): this;
|
|
44
|
+
getStream(): Writable;
|
|
37
45
|
send(body: any): this;
|
|
38
46
|
end(): this;
|
|
39
47
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FallbackLng, LanguageResource } from '@opra/common';
|
|
2
|
+
export interface I18nOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Language to use
|
|
5
|
+
* @default undefined
|
|
6
|
+
*/
|
|
7
|
+
lng?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Language to use if translations in user language are not available.
|
|
10
|
+
* @default 'dev'
|
|
11
|
+
*/
|
|
12
|
+
fallbackLng?: false | FallbackLng;
|
|
13
|
+
/**
|
|
14
|
+
* Default namespace used if not passed to translation function
|
|
15
|
+
* @default 'translation'
|
|
16
|
+
*/
|
|
17
|
+
defaultNS?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Resources to initialize with
|
|
20
|
+
* @default undefined
|
|
21
|
+
*/
|
|
22
|
+
resources?: LanguageResource;
|
|
23
|
+
/**
|
|
24
|
+
* Resource directories to initialize with (if not using loading or not appending using addResourceBundle)
|
|
25
|
+
* @default undefined
|
|
26
|
+
*/
|
|
27
|
+
resourceDirs?: string[];
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Maybe } from 'ts-gems';
|
|
2
|
-
import { CollectionResourceInfo, ComplexType, OpraQuery, OpraSchema } from '@opra/
|
|
3
|
-
import {
|
|
4
|
-
import { QueryContext } from '../adapter/query-context.js';
|
|
2
|
+
import { CollectionResourceInfo, ComplexType, Expression, OpraQuery, OpraSchema } from '@opra/common';
|
|
3
|
+
import { SingleRequestContext } from '../adapter/request-contexts/single-request-context.js';
|
|
5
4
|
import { PartialInput, PartialOutput } from '../types.js';
|
|
6
5
|
export interface JsonCollectionServiceOptions {
|
|
7
6
|
resourceName?: string;
|
|
@@ -20,7 +19,7 @@ export declare class JsonCollectionService<T, TOutput = PartialOutput<T>> {
|
|
|
20
19
|
get primaryKey(): string;
|
|
21
20
|
get resourceName(): string;
|
|
22
21
|
close(): Promise<void>;
|
|
23
|
-
processRequest(ctx:
|
|
22
|
+
processRequest(ctx: SingleRequestContext): Promise<any>;
|
|
24
23
|
get(keyValue: any, options?: JsonCollectionService.GetOptions): Promise<Maybe<TOutput>>;
|
|
25
24
|
count(options?: JsonCollectionService.SearchOptions): Promise<number>;
|
|
26
25
|
search(options?: JsonCollectionService.SearchOptions): Promise<TOutput[]>;
|