@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.
Files changed (56) hide show
  1. package/cjs/adapter/adapter.js +103 -122
  2. package/cjs/adapter/classes/execution-context.host.js +17 -0
  3. package/cjs/adapter/classes/express-request-wrapper.host.js +37 -0
  4. package/cjs/adapter/classes/express-response-wrapper.host.js +56 -0
  5. package/cjs/adapter/classes/http-execution-context.host.js +31 -0
  6. package/cjs/adapter/{metadata-resource.js → classes/metadata.resource.js} +3 -3
  7. package/cjs/adapter/express-adapter.js +6 -104
  8. package/cjs/adapter/http-adapter.js +270 -68
  9. package/cjs/adapter/request-contexts/batch-request-context.js +12 -0
  10. package/cjs/adapter/{query-context.js → request-contexts/request-context.js} +8 -12
  11. package/cjs/adapter/request-contexts/single-request-context.js +15 -0
  12. package/cjs/index.js +2 -1
  13. package/cjs/interfaces/i18n-options.interface.js +2 -0
  14. package/cjs/services/json-collection-service.js +36 -39
  15. package/cjs/services/json-singleton-service.js +9 -10
  16. package/cjs/utils/create-i18n.js +2 -2
  17. package/esm/adapter/adapter.d.ts +13 -44
  18. package/esm/adapter/adapter.js +89 -108
  19. package/esm/adapter/classes/execution-context.host.d.ts +10 -0
  20. package/esm/adapter/classes/execution-context.host.js +13 -0
  21. package/esm/adapter/classes/express-request-wrapper.host.d.ts +19 -0
  22. package/esm/adapter/classes/express-request-wrapper.host.js +33 -0
  23. package/esm/adapter/classes/express-response-wrapper.host.d.ts +22 -0
  24. package/esm/adapter/classes/express-response-wrapper.host.js +52 -0
  25. package/esm/adapter/classes/http-execution-context.host.d.ts +13 -0
  26. package/esm/adapter/classes/http-execution-context.host.js +27 -0
  27. package/esm/adapter/classes/metadata.resource.d.ts +8 -0
  28. package/esm/adapter/{metadata-resource.js → classes/metadata.resource.js} +2 -2
  29. package/esm/adapter/express-adapter.d.ts +1 -1
  30. package/esm/adapter/express-adapter.js +5 -103
  31. package/esm/adapter/http-adapter.d.ts +23 -12
  32. package/esm/adapter/http-adapter.js +248 -46
  33. package/esm/adapter/request-contexts/batch-request-context.d.ts +7 -0
  34. package/esm/adapter/request-contexts/batch-request-context.js +8 -0
  35. package/esm/adapter/request-contexts/request-context.d.ts +22 -0
  36. package/esm/adapter/{query-context.js → request-contexts/request-context.js} +6 -10
  37. package/esm/adapter/request-contexts/single-request-context.d.ts +10 -0
  38. package/esm/adapter/request-contexts/single-request-context.js +11 -0
  39. package/esm/index.d.ts +2 -1
  40. package/esm/index.js +2 -1
  41. package/esm/interfaces/execution-context.interface.d.ts +19 -11
  42. package/esm/interfaces/i18n-options.interface.d.ts +28 -0
  43. package/esm/interfaces/i18n-options.interface.js +1 -0
  44. package/esm/interfaces/resource.interface.d.ts +1 -1
  45. package/esm/services/json-collection-service.d.ts +3 -4
  46. package/esm/services/json-collection-service.js +17 -20
  47. package/esm/services/json-singleton-service.d.ts +3 -3
  48. package/esm/services/json-singleton-service.js +8 -8
  49. package/esm/utils/create-i18n.d.ts +3 -3
  50. package/esm/utils/create-i18n.js +1 -1
  51. package/package.json +7 -8
  52. package/cjs/utils/path-to-tree.js +0 -28
  53. package/esm/adapter/metadata-resource.d.ts +0 -8
  54. package/esm/adapter/query-context.d.ts +0 -24
  55. package/esm/utils/path-to-tree.d.ts +0 -4
  56. package/esm/utils/path-to-tree.js +0 -24
@@ -1,22 +1,32 @@
1
- import { HeadersMap, HttpHeaders, HttpStatus } from '@opra/common';
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 { QueryContext } from './query-context.js';
3
+ import { SingleRequestContext } from './request-contexts/single-request-context.js';
7
4
  export class OpraHttpAdapter extends OpraAdapter {
8
- prepareRequests(executionContext) {
9
- const req = executionContext.getRequestWrapper();
10
- // todo implement batch requests
11
- if (this.isBatch(executionContext)) {
12
- throw new Error('not implemented yet');
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
- const url = new OpraURL(req.getUrl());
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
- prepareRequest(executionContext, url, method, headers, body) {
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 QueryContext({
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
- query = new SingletonGetQuery(resource);
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, queryContexts) {
157
- const outputPackets = [];
158
- for (const ctx of queryContexts) {
159
- const v = this.createOutput(ctx);
160
- outputPackets.push(v);
161
- }
162
- if (this.isBatch(executionContext)) {
163
- // this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
164
- return;
165
- }
166
- if (!outputPackets.length)
167
- return this.sendError(executionContext, new NotFoundError());
168
- const out = outputPackets[0];
169
- const resp = executionContext.getResponseWrapper();
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
- resp.setHeader(k, v);
357
+ if (v)
358
+ resp.setHeader(k, v);
179
359
  }
180
360
  }
181
- resp.send(JSON.stringify(out.body));
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
- body = ctx.response;
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.toObject(),
401
+ headers: normalizeHeaders(ctx.responseHeaders),
219
402
  body
220
403
  };
221
404
  }
222
405
  async sendError(executionContext, error) {
223
- const resp = executionContext.getResponseWrapper();
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,8 @@
1
+ import { RequestContext } from './request-context.js';
2
+ export class BatchRequestContext extends RequestContext {
3
+ queries;
4
+ constructor(args) {
5
+ super(args);
6
+ this.queries = args.queries;
7
+ }
8
+ }
@@ -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 { HeadersMap } from '@opra/common';
2
- import { OpraURLSearchParams } from '@opra/url';
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 = new HeadersMap(args.headers);
25
- this.responseHeaders = new HeadersMap();
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 './adapter/query-context.js';
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 './adapter/query-context.js';
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(): PlatformType;
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(): any;
17
- getResponse(): any;
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(): Record<string, any>;
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
- getHeaderNames(name: string): string[];
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,5 +1,5 @@
1
1
  import { Maybe } from 'ts-gems';
2
- import { ResourceInfo } from '@opra/schema';
2
+ import { ResourceInfo } from '@opra/common';
3
3
  import { PartialOutput } from '../types.js';
4
4
  export interface IResource {
5
5
  init?(resource: ResourceInfo): void | Promise<void>;
@@ -1,7 +1,6 @@
1
1
  import { Maybe } from 'ts-gems';
2
- import { CollectionResourceInfo, ComplexType, OpraQuery, OpraSchema } from '@opra/schema';
3
- import { Expression } from '@opra/url';
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: QueryContext): Promise<any>;
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[]>;