@opra/core 0.5.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 -122
- 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 +270 -68
- package/cjs/adapter/request-contexts/batch-request-context.js +12 -0
- package/cjs/adapter/{query-context.js → request-contexts/request-context.js} +8 -12
- package/cjs/adapter/request-contexts/single-request-context.js +15 -0
- package/cjs/index.js +2 -1
- 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 -108
- 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 -46
- 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 -1
- package/esm/index.js +2 -1
- 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/utils/path-to-tree.js +0 -28
- package/esm/adapter/metadata-resource.d.ts +0 -8
- package/esm/adapter/query-context.d.ts +0 -24
- package/esm/utils/path-to-tree.d.ts +0 -4
- package/esm/utils/path-to-tree.js +0 -24
|
@@ -1,22 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BadRequestError, InternalServerError, IssueSeverity, MethodNotAllowedError, NotFoundError, OpraException, wrapException } from '@opra/exception';
|
|
3
|
-
import { CollectionCreateQuery, CollectionDeleteManyQuery, CollectionDeleteQuery, CollectionGetQuery, CollectionResourceInfo, CollectionSearchQuery, CollectionUpdateManyQuery, CollectionUpdateQuery, ComplexType, ContainerResourceInfo, FieldGetQuery, OpraSchema, SingletonGetQuery, SingletonResourceInfo, UnionType, } from '@opra/schema';
|
|
4
|
-
import { OpraURL } from '@opra/url';
|
|
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';
|
|
5
2
|
import { OpraAdapter } from './adapter.js';
|
|
6
|
-
import {
|
|
3
|
+
import { SingleRequestContext } from './request-contexts/single-request-context.js';
|
|
7
4
|
export class OpraHttpAdapter extends OpraAdapter {
|
|
8
|
-
|
|
9
|
-
const req = executionContext.
|
|
10
|
-
|
|
11
|
-
if (
|
|
12
|
-
|
|
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]);
|
|
13
25
|
}
|
|
14
|
-
|
|
15
|
-
return [
|
|
16
|
-
this.prepareRequest(executionContext, url, req.getMethod(), new HeadersMap(req.getHeaders()), req.getBody())
|
|
17
|
-
];
|
|
26
|
+
throw new BadRequestError({ message: 'Unsupported Content-Type' });
|
|
18
27
|
}
|
|
19
|
-
|
|
28
|
+
parseSingleQuery(args) {
|
|
29
|
+
const { executionContext, url, method, headers, body, contentId } = args;
|
|
20
30
|
if (!url.path.size)
|
|
21
31
|
throw new BadRequestError();
|
|
22
32
|
if (method !== 'GET' && url.path.size > 1)
|
|
@@ -26,15 +36,94 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
26
36
|
throw new MethodNotAllowedError({
|
|
27
37
|
message: `Method "${method}" is not allowed by target endpoint`
|
|
28
38
|
});
|
|
29
|
-
return new
|
|
39
|
+
return new SingleRequestContext({
|
|
30
40
|
service: this.document,
|
|
31
41
|
executionContext,
|
|
42
|
+
headers,
|
|
32
43
|
query,
|
|
33
|
-
headers: new HeadersMap(),
|
|
34
44
|
params: url.searchParams,
|
|
45
|
+
contentId,
|
|
35
46
|
continueOnError: query.operation === 'read'
|
|
36
47
|
});
|
|
37
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
|
+
// }
|
|
38
127
|
buildQuery(url, method, body) {
|
|
39
128
|
const pathLen = url.path.size;
|
|
40
129
|
let p = url.path.get(0);
|
|
@@ -52,7 +141,12 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
52
141
|
if (resource instanceof SingletonResourceInfo && !p.key) {
|
|
53
142
|
switch (method) {
|
|
54
143
|
case 'GET': {
|
|
55
|
-
|
|
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
|
+
});
|
|
56
150
|
}
|
|
57
151
|
}
|
|
58
152
|
}
|
|
@@ -153,38 +247,122 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
153
247
|
throw new BadRequestError(e);
|
|
154
248
|
}
|
|
155
249
|
}
|
|
156
|
-
async sendResponse(executionContext,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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();
|
|
170
351
|
resp.setStatus(out.status);
|
|
171
|
-
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
172
352
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
173
353
|
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
174
354
|
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
175
|
-
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
176
355
|
if (out.headers) {
|
|
177
356
|
for (const [k, v] of Object.entries(out.headers)) {
|
|
178
|
-
|
|
357
|
+
if (v)
|
|
358
|
+
resp.setHeader(k, v);
|
|
179
359
|
}
|
|
180
360
|
}
|
|
181
|
-
resp.
|
|
361
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
362
|
+
if (out.body)
|
|
363
|
+
resp.send(out.body);
|
|
182
364
|
resp.end();
|
|
183
365
|
}
|
|
184
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
185
|
-
isBatch(executionContext) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
366
|
createOutput(ctx) {
|
|
189
367
|
const { query } = ctx;
|
|
190
368
|
let body;
|
|
@@ -203,24 +381,29 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
203
381
|
if (status < HttpStatus.BAD_REQUEST)
|
|
204
382
|
status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
205
383
|
}
|
|
206
|
-
body = {
|
|
384
|
+
body = this.i18n.deep({
|
|
207
385
|
operation: ctx.query.method,
|
|
208
386
|
errors: errors.map(e => e.issue)
|
|
209
|
-
};
|
|
387
|
+
});
|
|
388
|
+
body = JSON.stringify(body);
|
|
389
|
+
ctx.responseHeaders['content-type'] = 'application/json; charset=utf-8';
|
|
210
390
|
}
|
|
211
391
|
else {
|
|
212
|
-
|
|
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
|
+
}
|
|
213
397
|
status = status || (query.operation === 'create' ? HttpStatus.CREATED : HttpStatus.OK);
|
|
214
398
|
}
|
|
215
|
-
body = this.i18n.deep(body);
|
|
216
399
|
return {
|
|
217
400
|
status,
|
|
218
|
-
headers: ctx.responseHeaders
|
|
401
|
+
headers: normalizeHeaders(ctx.responseHeaders),
|
|
219
402
|
body
|
|
220
403
|
};
|
|
221
404
|
}
|
|
222
405
|
async sendError(executionContext, error) {
|
|
223
|
-
const resp = executionContext.
|
|
406
|
+
const resp = executionContext.getResponse();
|
|
224
407
|
resp.setStatus(error.status || 500);
|
|
225
408
|
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
226
409
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
@@ -235,3 +418,22 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
235
418
|
resp.send(JSON.stringify(body));
|
|
236
419
|
}
|
|
237
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 {
|
|
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
|
@@ -2,7 +2,8 @@ import "reflect-metadata";
|
|
|
2
2
|
export * from './types.js';
|
|
3
3
|
export * from './interfaces/execution-context.interface.js';
|
|
4
4
|
export * from './interfaces/resource.interface.js';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './interfaces/i18n-options.interface.js';
|
|
6
|
+
export * from './adapter/request-contexts/single-request-context.js';
|
|
6
7
|
export * from './adapter/adapter.js';
|
|
7
8
|
export * from './adapter/http-adapter.js';
|
|
8
9
|
export * from './adapter/express-adapter.js';
|
package/esm/index.js
CHANGED
|
@@ -2,7 +2,8 @@ import "reflect-metadata";
|
|
|
2
2
|
export * from './types.js';
|
|
3
3
|
export * from './interfaces/execution-context.interface.js';
|
|
4
4
|
export * from './interfaces/resource.interface.js';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './interfaces/i18n-options.interface.js';
|
|
6
|
+
export * from './adapter/request-contexts/single-request-context.js';
|
|
6
7
|
export * from './adapter/adapter.js';
|
|
7
8
|
export * from './adapter/http-adapter.js';
|
|
8
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[]>;
|