@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.
Files changed (68) hide show
  1. package/cjs/adapter/adapter.js +103 -123
  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 +282 -81
  9. package/cjs/adapter/request-contexts/batch-request-context.js +12 -0
  10. package/cjs/adapter/{query-context.js → request-contexts/request-context.js} +9 -13
  11. package/cjs/adapter/request-contexts/single-request-context.js +15 -0
  12. package/cjs/index.js +2 -2
  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 -109
  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 -47
  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 -2
  40. package/esm/index.js +2 -2
  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/enums/http-headers.enum.js +0 -395
  53. package/cjs/enums/http-status.enum.js +0 -300
  54. package/cjs/enums/index.js +0 -5
  55. package/cjs/helpers/headers-map.js +0 -18
  56. package/cjs/utils/path-to-tree.js +0 -28
  57. package/esm/adapter/metadata-resource.d.ts +0 -8
  58. package/esm/adapter/query-context.d.ts +0 -25
  59. package/esm/enums/http-headers.enum.d.ts +0 -370
  60. package/esm/enums/http-headers.enum.js +0 -392
  61. package/esm/enums/http-status.enum.d.ts +0 -290
  62. package/esm/enums/http-status.enum.js +0 -297
  63. package/esm/enums/index.d.ts +0 -2
  64. package/esm/enums/index.js +0 -2
  65. package/esm/helpers/headers-map.d.ts +0 -5
  66. package/esm/helpers/headers-map.js +0 -14
  67. package/esm/utils/path-to-tree.d.ts +0 -4
  68. package/esm/utils/path-to-tree.js +0 -24
@@ -1,23 +1,32 @@
1
- import { BadRequestError, InternalServerError, IssueSeverity, MethodNotAllowedError, NotFoundError, OpraException, wrapException } from '@opra/exception';
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 { QueryContext } from './query-context.js';
3
+ import { SingleRequestContext } from './request-contexts/single-request-context.js';
8
4
  export class OpraHttpAdapter extends OpraAdapter {
9
- prepareRequests(executionContext) {
10
- const req = executionContext.getRequestWrapper();
11
- // todo implement batch requests
12
- if (this.isBatch(executionContext)) {
13
- 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]);
14
25
  }
15
- const url = new OpraURL(req.getUrl());
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
- prepareRequest(executionContext, url, method, headers, body) {
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 QueryContext({
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
- 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
+ });
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, queryContexts) {
158
- const outputPackets = [];
159
- for (const ctx of queryContexts) {
160
- const v = this.createOutput(ctx);
161
- outputPackets.push(v);
162
- }
163
- if (this.isBatch(executionContext)) {
164
- // this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
165
- return;
166
- }
167
- if (!outputPackets.length)
168
- return this.sendError(executionContext, new NotFoundError());
169
- const out = outputPackets[0];
170
- 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();
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
- resp.setHeader(k, v);
357
+ if (v)
358
+ resp.setHeader(k, v);
180
359
  }
181
360
  }
182
- resp.send(JSON.stringify(out.body));
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
- 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
+ }
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.toObject(),
401
+ headers: normalizeHeaders(ctx.responseHeaders),
220
402
  body
221
403
  };
222
404
  }
223
405
  async sendError(executionContext, error) {
224
- const resp = executionContext.getResponseWrapper();
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,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 { OpraURLSearchParams } from '@opra/url';
2
- import { HeadersMap } from '../helpers/headers-map.js';
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
@@ -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 './adapter/query-context.js';
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 './adapter/query-context.js';
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(): 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[]>;