@opra/core 0.14.0 → 0.15.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 (98) hide show
  1. package/cjs/adapter/adapter.js +88 -294
  2. package/cjs/adapter/http/express-adapter.js +27 -0
  3. package/cjs/adapter/http/http-adapter.js +466 -0
  4. package/cjs/adapter/http/http-request-context.host.js +28 -0
  5. package/cjs/adapter/http/http-request.host.js +14 -0
  6. package/cjs/adapter/http/http-response.host.js +14 -0
  7. package/cjs/adapter/internal/metadata.resource.js +27 -0
  8. package/cjs/adapter/request-context.host.js +30 -0
  9. package/cjs/adapter/request.host.js +19 -0
  10. package/cjs/adapter/response.host.js +20 -0
  11. package/cjs/augmentation/resource.augmentation.js +26 -0
  12. package/cjs/index.js +7 -8
  13. package/esm/adapter/adapter.d.ts +52 -28
  14. package/esm/adapter/adapter.js +88 -295
  15. package/esm/adapter/http/express-adapter.d.ts +11 -0
  16. package/esm/adapter/http/express-adapter.js +22 -0
  17. package/esm/adapter/http/http-adapter.d.ts +37 -0
  18. package/esm/adapter/http/http-adapter.js +462 -0
  19. package/esm/adapter/http/http-request-context.host.d.ts +16 -0
  20. package/esm/adapter/http/http-request-context.host.js +24 -0
  21. package/esm/adapter/http/http-request.host.d.ts +7 -0
  22. package/esm/adapter/http/http-request.host.js +10 -0
  23. package/esm/adapter/http/http-response.host.d.ts +7 -0
  24. package/esm/adapter/http/http-response.host.js +10 -0
  25. package/esm/{interfaces → adapter/interfaces}/logger.interface.d.ts +1 -0
  26. package/esm/adapter/interfaces/request-context.interface.d.ts +25 -0
  27. package/esm/adapter/interfaces/request.interface.d.ts +13 -0
  28. package/esm/adapter/interfaces/response.interface.d.ts +22 -0
  29. package/esm/adapter/internal/metadata.resource.d.ts +7 -0
  30. package/esm/adapter/internal/metadata.resource.js +24 -0
  31. package/esm/adapter/request-context.host.d.ts +19 -0
  32. package/esm/adapter/request-context.host.js +26 -0
  33. package/esm/adapter/request.host.d.ts +26 -0
  34. package/esm/adapter/request.host.js +15 -0
  35. package/esm/adapter/response.host.d.ts +20 -0
  36. package/esm/adapter/response.host.js +16 -0
  37. package/esm/augmentation/resource.augmentation.d.ts +33 -0
  38. package/esm/augmentation/resource.augmentation.js +24 -0
  39. package/esm/index.d.ts +7 -8
  40. package/esm/index.js +7 -8
  41. package/i18n/en/error.json +1 -1
  42. package/package.json +9 -7
  43. package/cjs/adapter/classes/execution-context.host.js +0 -16
  44. package/cjs/adapter/classes/express-request-wrapper.host.js +0 -36
  45. package/cjs/adapter/classes/express-response-wrapper.host.js +0 -55
  46. package/cjs/adapter/classes/http-execution-context.host.js +0 -28
  47. package/cjs/adapter/classes/metadata.resource.js +0 -22
  48. package/cjs/adapter/express-adapter.js +0 -26
  49. package/cjs/adapter/http-adapter.js +0 -443
  50. package/cjs/adapter/request-contexts/batch-request-context.js +0 -11
  51. package/cjs/adapter/request-contexts/request-context.js +0 -25
  52. package/cjs/adapter/request-contexts/single-request-context.js +0 -14
  53. package/cjs/interfaces/resource.interface.js +0 -2
  54. package/cjs/services/data-service.js +0 -9
  55. package/cjs/services/json-singleton-service.js +0 -96
  56. package/cjs/utils/create-i18n.js +0 -21
  57. package/cjs/utils/get-caller-file.util.js +0 -24
  58. package/esm/adapter/classes/execution-context.host.d.ts +0 -10
  59. package/esm/adapter/classes/execution-context.host.js +0 -12
  60. package/esm/adapter/classes/express-request-wrapper.host.d.ts +0 -19
  61. package/esm/adapter/classes/express-request-wrapper.host.js +0 -32
  62. package/esm/adapter/classes/express-response-wrapper.host.d.ts +0 -22
  63. package/esm/adapter/classes/express-response-wrapper.host.js +0 -51
  64. package/esm/adapter/classes/http-execution-context.host.d.ts +0 -13
  65. package/esm/adapter/classes/http-execution-context.host.js +0 -24
  66. package/esm/adapter/classes/metadata.resource.d.ts +0 -8
  67. package/esm/adapter/classes/metadata.resource.js +0 -19
  68. package/esm/adapter/express-adapter.d.ts +0 -11
  69. package/esm/adapter/express-adapter.js +0 -21
  70. package/esm/adapter/http-adapter.d.ts +0 -37
  71. package/esm/adapter/http-adapter.js +0 -439
  72. package/esm/adapter/request-contexts/batch-request-context.d.ts +0 -7
  73. package/esm/adapter/request-contexts/batch-request-context.js +0 -7
  74. package/esm/adapter/request-contexts/request-context.d.ts +0 -22
  75. package/esm/adapter/request-contexts/request-context.js +0 -21
  76. package/esm/adapter/request-contexts/single-request-context.d.ts +0 -10
  77. package/esm/adapter/request-contexts/single-request-context.js +0 -10
  78. package/esm/enums/issue-severity.enum.d.ts +0 -1
  79. package/esm/interfaces/execution-context.interface.d.ts +0 -47
  80. package/esm/interfaces/i18n-options.interface.d.ts +0 -28
  81. package/esm/interfaces/resource.interface.d.ts +0 -23
  82. package/esm/interfaces/resource.interface.js +0 -1
  83. package/esm/services/data-service.d.ts +0 -2
  84. package/esm/services/data-service.js +0 -5
  85. package/esm/services/json-singleton-service.d.ts +0 -39
  86. package/esm/services/json-singleton-service.js +0 -91
  87. package/esm/utils/create-i18n.d.ts +0 -3
  88. package/esm/utils/create-i18n.js +0 -16
  89. package/esm/utils/get-caller-file.util.d.ts +0 -1
  90. package/esm/utils/get-caller-file.util.js +0 -20
  91. /package/cjs/{interfaces → adapter/interfaces}/logger.interface.js +0 -0
  92. /package/cjs/{enums/issue-severity.enum.js → adapter/interfaces/request-context.interface.js} +0 -0
  93. /package/cjs/{interfaces/execution-context.interface.js → adapter/interfaces/request.interface.js} +0 -0
  94. /package/cjs/{interfaces/i18n-options.interface.js → adapter/interfaces/response.interface.js} +0 -0
  95. /package/esm/{interfaces → adapter/interfaces}/logger.interface.js +0 -0
  96. /package/esm/{enums/issue-severity.enum.js → adapter/interfaces/request-context.interface.js} +0 -0
  97. /package/esm/{interfaces/execution-context.interface.js → adapter/interfaces/request.interface.js} +0 -0
  98. /package/esm/{interfaces/i18n-options.interface.js → adapter/interfaces/response.interface.js} +0 -0
@@ -0,0 +1,466 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpraHttpAdapter = void 0;
4
+ const power_tasks_1 = require("power-tasks");
5
+ const common_1 = require("@opra/common");
6
+ const adapter_js_1 = require("../adapter.js");
7
+ const http_request_host_js_1 = require("./http-request.host.js");
8
+ const http_request_context_host_js_1 = require("./http-request-context.host.js");
9
+ const http_response_host_js_1 = require("./http-response.host.js");
10
+ /**
11
+ *
12
+ * @class OpraHttpAdapter
13
+ */
14
+ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
15
+ /**
16
+ * Main http request handler
17
+ * @param incoming
18
+ * @param outgoing
19
+ * @protected
20
+ */
21
+ async handler(incoming, outgoing) {
22
+ try {
23
+ // Batch
24
+ if (incoming.is('multipart/mixed')) {
25
+ throw new common_1.BadRequestError({ message: 'Not implemented yet' });
26
+ }
27
+ if (!(incoming.method === 'POST' || incoming.method === 'PATCH') || incoming.is('json')) {
28
+ const request = await this.parseRequest(incoming);
29
+ const response = new http_response_host_js_1.HttpResponseHost({}, outgoing);
30
+ const context = new http_request_context_host_js_1.HttpRequestContextHost(this.platform, this.api, request, response);
31
+ const task = new power_tasks_1.Task(async () => {
32
+ try {
33
+ await this.executeRequest(context);
34
+ if (request.operation === 'search' && request.args.count && response.count != null) {
35
+ response.switchToHttp().header(common_1.HttpHeaderCodes.X_Opra_Total_Matches, String(response.count));
36
+ }
37
+ }
38
+ catch (error) {
39
+ return this.errorHandler(incoming, outgoing, [error]);
40
+ }
41
+ await this.sendResponse(context);
42
+ }, {
43
+ id: incoming.get('content-id'),
44
+ exclusive: request.crud !== 'read'
45
+ });
46
+ await task.toPromise().catch(e => {
47
+ this.logger?.error?.(e);
48
+ outgoing.sendStatus(500);
49
+ });
50
+ return;
51
+ }
52
+ throw new common_1.BadRequestError({ message: 'Unsupported Content-Type' });
53
+ }
54
+ catch (error) {
55
+ await this.errorHandler(incoming, outgoing, [error]);
56
+ }
57
+ }
58
+ async errorHandler(incoming, outgoing, errors) {
59
+ errors.forEach(e => {
60
+ this.log((e instanceof common_1.OpraException) ? 'error' : 'fatal', incoming, e); // todo. implement a better logger
61
+ });
62
+ errors = errors.map(common_1.wrapException);
63
+ let status = outgoing.statusCode || 0;
64
+ // Sort errors from fatal to info
65
+ errors.sort((a, b) => {
66
+ const i = common_1.IssueSeverity.Keys.indexOf(a.issue.severity) - common_1.IssueSeverity.Keys.indexOf(b.issue.severity);
67
+ if (i === 0)
68
+ return b.status - a.status;
69
+ return i;
70
+ });
71
+ if (!status || status < common_1.HttpStatusCodes.BAD_REQUEST) {
72
+ status = errors[0].status;
73
+ if (status < common_1.HttpStatusCodes.BAD_REQUEST)
74
+ status = common_1.HttpStatusCodes.INTERNAL_SERVER_ERROR;
75
+ }
76
+ const body = this.i18n.deep({
77
+ errors: errors.map(e => e.issue)
78
+ });
79
+ outgoing.set(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
80
+ outgoing.set(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
81
+ outgoing.set(common_1.HttpHeaderCodes.Pragma, 'no-cache');
82
+ outgoing.set(common_1.HttpHeaderCodes.Expires, '-1');
83
+ outgoing.set(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
84
+ outgoing.status(status);
85
+ outgoing.send(JSON.stringify(body));
86
+ outgoing.end();
87
+ }
88
+ log(logType, incoming, message, ...optionalParams) {
89
+ const logFn = logType === 'fatal'
90
+ ? this.logger?.fatal || this.logger?.error
91
+ : this.logger?.[logType];
92
+ if (!logFn)
93
+ return;
94
+ logFn.apply(this.logger, [String(message), ...optionalParams]);
95
+ }
96
+ async afterExecuteRequest(context) {
97
+ await super.afterExecuteRequest(context);
98
+ const { request } = context;
99
+ const response = context.response;
100
+ const { crud } = request;
101
+ const httpResponse = response.switchToHttp();
102
+ if (request.resource instanceof common_1.Singleton || request.resource instanceof common_1.Collection) {
103
+ httpResponse.set(common_1.HttpHeaderCodes.X_Opra_Data_Type, request.resource.type.name);
104
+ httpResponse.set(common_1.HttpHeaderCodes.X_Opra_Operation, request.operation);
105
+ }
106
+ if (crud === 'create') {
107
+ if (!response.value)
108
+ throw new common_1.InternalServerError();
109
+ // todo validate
110
+ httpResponse.status(201);
111
+ }
112
+ }
113
+ /**
114
+ *
115
+ * @param incoming
116
+ * @protected
117
+ */
118
+ async parseRequest(incoming) {
119
+ try {
120
+ const url = new common_1.OpraURL();
121
+ url.searchParams.define({
122
+ '$pick': { codec: 'string', array: true },
123
+ '$omit': { codec: 'string', array: true },
124
+ '$include': { codec: 'string', array: true },
125
+ '$sort': { codec: 'string', array: true },
126
+ '$filter': { codec: 'filter' },
127
+ '$limit': { codec: 'number' },
128
+ '$skip': { codec: 'number' },
129
+ '$distinct': { codec: 'boolean' },
130
+ '$count': { codec: 'boolean' },
131
+ });
132
+ url.parse(incoming.url);
133
+ // const {context, url, method, headers, body, contentId} = args;
134
+ if (!url.path.size)
135
+ throw new common_1.BadRequestError();
136
+ const method = incoming.method;
137
+ if (method !== 'GET' && url.path.size > 1)
138
+ throw new common_1.BadRequestError();
139
+ // const pathLen = url.path.size;
140
+ // let pathIndex = 0;
141
+ const params = url.searchParams;
142
+ const p = url.path.get(0);
143
+ const resource = this._internalDoc.getResource(p.resource);
144
+ // let container: IResourceContainer | undefined;
145
+ // while (resource && resource instanceof ContainerResourceInfo) {
146
+ // container = resource;
147
+ // p = url.path.get(++pathIndex);
148
+ // resource = container.getResource(p.resource);
149
+ // }
150
+ // const headers = incoming.headers;
151
+ /*
152
+ * Collection
153
+ */
154
+ if (resource instanceof common_1.Collection) {
155
+ switch (method) {
156
+ case 'POST': {
157
+ if (!p.key) {
158
+ return new http_request_host_js_1.HttpRequestHost({
159
+ kind: 'CollectionCreateRequest',
160
+ resource,
161
+ operation: 'create',
162
+ crud: 'create',
163
+ many: false,
164
+ args: {
165
+ data: incoming.body,
166
+ pick: resource.normalizeFieldNames(params.get('$pick')),
167
+ omit: resource.normalizeFieldNames(params.get('$omit')),
168
+ include: resource.normalizeFieldNames(params.get('$include'))
169
+ }
170
+ }, incoming);
171
+ }
172
+ break;
173
+ }
174
+ case 'DELETE': {
175
+ if (p.key) {
176
+ return new http_request_host_js_1.HttpRequestHost({
177
+ kind: 'CollectionDeleteRequest',
178
+ resource,
179
+ operation: 'delete',
180
+ crud: 'delete',
181
+ many: false,
182
+ args: {
183
+ key: resource.parseKeyValue(p.key)
184
+ }
185
+ }, incoming);
186
+ }
187
+ return new http_request_host_js_1.HttpRequestHost({
188
+ kind: 'CollectionDeleteManyRequest',
189
+ resource,
190
+ operation: 'deleteMany',
191
+ crud: 'delete',
192
+ many: true,
193
+ args: {
194
+ filter: resource.normalizeFilterFields(params.get('$filter'))
195
+ }
196
+ }, incoming);
197
+ }
198
+ case 'GET': {
199
+ if (p.key) {
200
+ return new http_request_host_js_1.HttpRequestHost({
201
+ kind: 'CollectionGetRequest',
202
+ resource,
203
+ operation: 'get',
204
+ crud: 'read',
205
+ many: false,
206
+ args: {
207
+ key: resource.parseKeyValue(p.key),
208
+ pick: resource.normalizeFieldNames(params.get('$pick')),
209
+ omit: resource.normalizeFieldNames(params.get('$omit')),
210
+ include: resource.normalizeFieldNames(params.get('$include'))
211
+ }
212
+ }, incoming);
213
+ }
214
+ return new http_request_host_js_1.HttpRequestHost({
215
+ kind: 'CollectionSearchRequest',
216
+ resource,
217
+ operation: 'search',
218
+ crud: 'read',
219
+ many: true,
220
+ args: {
221
+ sort: resource.normalizeSortFields(params.get('$sort')),
222
+ pick: resource.normalizeFieldNames(params.get('$pick')),
223
+ omit: resource.normalizeFieldNames(params.get('$omit')),
224
+ include: resource.normalizeFieldNames(params.get('$include')),
225
+ filter: resource.normalizeFilterFields(params.get('$filter')),
226
+ limit: params.get('$limit'),
227
+ skip: params.get('$skip'),
228
+ distinct: params.get('$distinct'),
229
+ count: params.get('$count'),
230
+ }
231
+ }, incoming);
232
+ }
233
+ case 'PATCH': {
234
+ if (p.key) {
235
+ return new http_request_host_js_1.HttpRequestHost({
236
+ kind: 'CollectionUpdateRequest',
237
+ resource,
238
+ operation: 'update',
239
+ crud: 'update',
240
+ many: false,
241
+ args: {
242
+ key: resource.parseKeyValue(p.key),
243
+ data: incoming.body,
244
+ pick: resource.normalizeFieldNames(params.get('$pick')),
245
+ omit: resource.normalizeFieldNames(params.get('$omit')),
246
+ include: resource.normalizeFieldNames(params.get('$include'))
247
+ }
248
+ }, incoming);
249
+ }
250
+ return new http_request_host_js_1.HttpRequestHost({
251
+ kind: 'CollectionUpdateManyRequest',
252
+ resource,
253
+ operation: 'updateMany',
254
+ crud: 'update',
255
+ many: true,
256
+ args: {
257
+ data: incoming.body,
258
+ filter: resource.normalizeFilterFields(params.get('$filter'))
259
+ }
260
+ }, incoming);
261
+ }
262
+ }
263
+ }
264
+ else
265
+ /*
266
+ * Singleton
267
+ */
268
+ if (resource instanceof common_1.Singleton && !p.key) {
269
+ switch (method) {
270
+ case 'POST': {
271
+ return new http_request_host_js_1.HttpRequestHost({
272
+ kind: 'SingletonCreateRequest',
273
+ resource,
274
+ operation: 'create',
275
+ crud: 'create',
276
+ many: false,
277
+ args: {
278
+ data: incoming.body,
279
+ pick: resource.normalizeFieldNames(params.get('$pick')),
280
+ omit: resource.normalizeFieldNames(params.get('$omit')),
281
+ include: resource.normalizeFieldNames(params.get('$include'))
282
+ }
283
+ }, incoming);
284
+ }
285
+ case 'DELETE': {
286
+ return new http_request_host_js_1.HttpRequestHost({
287
+ kind: 'SingletonDeleteRequest',
288
+ resource,
289
+ operation: 'delete',
290
+ crud: 'delete',
291
+ many: false,
292
+ args: {}
293
+ }, incoming);
294
+ }
295
+ case 'GET': {
296
+ return new http_request_host_js_1.HttpRequestHost({
297
+ kind: 'SingletonGetRequest',
298
+ resource,
299
+ operation: 'get',
300
+ crud: 'read',
301
+ many: false,
302
+ args: {
303
+ pick: resource.normalizeFieldNames(params.get('$pick')),
304
+ omit: resource.normalizeFieldNames(params.get('$omit')),
305
+ include: resource.normalizeFieldNames(params.get('$include'))
306
+ }
307
+ }, incoming);
308
+ }
309
+ case 'PATCH': {
310
+ return new http_request_host_js_1.HttpRequestHost({
311
+ kind: 'SingletonUpdateRequest',
312
+ resource,
313
+ operation: 'update',
314
+ crud: 'update',
315
+ many: false,
316
+ args: {
317
+ data: incoming.body,
318
+ pick: resource.normalizeFieldNames(params.get('$pick')),
319
+ omit: resource.normalizeFieldNames(params.get('$omit')),
320
+ include: resource.normalizeFieldNames(params.get('$include'))
321
+ }
322
+ }, incoming);
323
+ }
324
+ }
325
+ }
326
+ else
327
+ throw new common_1.InternalServerError();
328
+ // if (query instanceof SingletonGetQuery || query instanceof CollectionGetQuery || query instanceof ElementReadQuery) {
329
+ // // Move through properties
330
+ // let parentType: DataType;
331
+ // const curPath: string[] = [];
332
+ // let parent: SingletonGetQuery | CollectionGetQuery | ElementReadQuery = query;
333
+ // while (++pathIndex < pathLen) {
334
+ // p = url.path.get(pathIndex);
335
+ // parentType = parent.type;
336
+ // if (parent.type instanceof UnionType) {
337
+ // if (parent.type.name === 'any')
338
+ // parentType = this.document.getComplexType('object');
339
+ // else
340
+ // throw new TypeError(`"${resource.name}.${curPath.join()}" is a UnionType and needs type casting.`);
341
+ // }
342
+ // if (!(parentType instanceof ComplexType))
343
+ // throw new TypeError(`"${resource.name}.${curPath.join()}" is not a ComplexType and has no fields.`);
344
+ // curPath.push(p.resource);
345
+ // parent.child = new ElementReadQuery(parent, p.resource, {castingType: parentType});
346
+ // parent = parent.child;
347
+ // }
348
+ // }
349
+ throw new common_1.MethodNotAllowedError({
350
+ message: `Method "${method}" is not allowed by target endpoint`
351
+ });
352
+ }
353
+ catch (e) {
354
+ if (e instanceof common_1.OpraException)
355
+ throw e;
356
+ throw new common_1.BadRequestError(e);
357
+ }
358
+ }
359
+ // async parseMultiPart(
360
+ // context: TExecutionContext,
361
+ // url: OpraURL,
362
+ // headers: IncomingHttpHeaders,
363
+ // input: Readable,
364
+ // boundary: string
365
+ // ): Promise<BatchRequestContext> {
366
+ // return await new Promise((resolve, reject) => {
367
+ // let _resolved = false;
368
+ // const dicer = new Dicer({boundary});
369
+ // const doReject = (e) => {
370
+ // if (_resolved) return;
371
+ // _resolved = true;
372
+ // reject(e);
373
+ // taskQueue.clearQueue();
374
+ // dicer.destroy();
375
+ // }
376
+ // const taskQueue = new TaskQueue({concurrency: 1});
377
+ // taskQueue.on('error', doReject);
378
+ //
379
+ // const queries: SingleRequestContext[] = [];
380
+ // let partCounter = 0;
381
+ // dicer.on('error', doReject);
382
+ // dicer.on('part', part => {
383
+ // const partIndex = partCounter++;
384
+ // let header: any;
385
+ // const chunks: Buffer[] = [];
386
+ // part.on('error', doReject);
387
+ // part.on('header', (_header) => header = normalizeHeaders(_header));
388
+ // part.on('data', (chunk: Buffer) => chunks.push(chunk));
389
+ // part.on('end', () => {
390
+ // if (_resolved || !(header || chunks.length))
391
+ // return;
392
+ // const ct = header['content-type'];
393
+ // if (ct === 'application/http') {
394
+ // taskQueue.enqueue(async () => {
395
+ // const data = Buffer.concat(chunks);
396
+ // if (!(data && data.length))
397
+ // return;
398
+ // const r = HttpRequest.parse(data);
399
+ // await callMiddlewares(r, [jsonBodyParser]);
400
+ // const subUrl = new OpraURL(r.url);
401
+ // const contentId = header && header['content-id'];
402
+ // queries.push(this.parseSingleQuery({
403
+ // context,
404
+ // url: subUrl,
405
+ // method: r.method,
406
+ // headers: r.headers,
407
+ // body: r.body,
408
+ // contentId
409
+ // }));
410
+ // });
411
+ // } else doReject(new BadRequestError({
412
+ // message: 'Unaccepted "content-type" header in multipart data',
413
+ // details: {
414
+ // position: `${boundary}[${partIndex}]`
415
+ // }
416
+ // }))
417
+ // });
418
+ // });
419
+ // dicer.on('finish', () => {
420
+ // taskQueue.enqueue(() => {
421
+ // if (_resolved) return;
422
+ // _resolved = true;
423
+ // const batch = new BatchRequestContext({
424
+ // service: this.document,
425
+ // context,
426
+ // headers,
427
+ // queries,
428
+ // params: url.searchParams,
429
+ // continueOnError: false
430
+ // });
431
+ // resolve(batch);
432
+ // });
433
+ // });
434
+ // input.pipe(dicer);
435
+ // });
436
+ // }
437
+ async sendResponse(context) {
438
+ const { request, response } = context;
439
+ const outgoing = response.switchToHttp();
440
+ const errors = response.errors?.map(e => (0, common_1.wrapException)(e));
441
+ if (errors && errors.length) {
442
+ await this.errorHandler(request.switchToHttp(), outgoing, errors);
443
+ return;
444
+ }
445
+ outgoing.set(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
446
+ outgoing.set(common_1.HttpHeaderCodes.Pragma, 'no-cache');
447
+ outgoing.set(common_1.HttpHeaderCodes.Expires, '-1');
448
+ outgoing.set(common_1.HttpHeaderCodes.X_Opra_Version, common_1.OpraSchema.SpecVersion);
449
+ outgoing.status(outgoing.statusCode || common_1.HttpStatusCodes.OK);
450
+ if (response.value) {
451
+ if (typeof response.value === 'object') {
452
+ if ((0, common_1.isReadable)(response.value) || Buffer.isBuffer(response.value))
453
+ outgoing.send(response.value);
454
+ else {
455
+ const body = this.i18n.deep(response.value);
456
+ outgoing.set(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
457
+ outgoing.send(JSON.stringify(body));
458
+ }
459
+ }
460
+ else
461
+ outgoing.send(JSON.stringify(response.value));
462
+ }
463
+ outgoing.end();
464
+ }
465
+ }
466
+ exports.OpraHttpAdapter = OpraHttpAdapter;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpRequestContextHost = void 0;
4
+ const request_context_host_js_1 = require("../request-context.host.js");
5
+ class HttpRequestContextHost extends request_context_host_js_1.RequestContextHost {
6
+ constructor(platform, api, _request, _response) {
7
+ super('http', platform, api, _request, _response);
8
+ this.platform = platform;
9
+ this.api = api;
10
+ this._request = _request;
11
+ this._response = _response;
12
+ }
13
+ switchToHttp() {
14
+ const obj = {
15
+ request: this._request.switchToHttp(),
16
+ response: this._response.switchToHttp()
17
+ };
18
+ Object.setPrototypeOf(obj, this);
19
+ return obj;
20
+ }
21
+ switchToWs() {
22
+ throw new TypeError('Not executing in an "WebSocket" protocol');
23
+ }
24
+ switchToRpc() {
25
+ throw new TypeError('Not executing in an "RPC" protocol');
26
+ }
27
+ }
28
+ exports.HttpRequestContextHost = HttpRequestContextHost;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpRequestHost = void 0;
4
+ const request_host_js_1 = require("../request.host.js");
5
+ class HttpRequestHost extends request_host_js_1.RequestHost {
6
+ constructor(init, _incoming) {
7
+ super(init);
8
+ this._incoming = _incoming;
9
+ }
10
+ switchToHttp() {
11
+ return this._incoming;
12
+ }
13
+ }
14
+ exports.HttpRequestHost = HttpRequestHost;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpResponseHost = void 0;
4
+ const response_host_js_1 = require("../response.host.js");
5
+ class HttpResponseHost extends response_host_js_1.ResponseHost {
6
+ constructor(init, _outgoing) {
7
+ super(init);
8
+ this._outgoing = _outgoing;
9
+ }
10
+ switchToHttp() {
11
+ return this._outgoing;
12
+ }
13
+ }
14
+ exports.HttpResponseHost = HttpResponseHost;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MetadataResource = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@opra/common");
6
+ let MetadataResource = class MetadataResource {
7
+ constructor(document) {
8
+ this.document = document;
9
+ this._schema = document.exportSchema();
10
+ }
11
+ get() {
12
+ return (0, common_1.cloneObject)(this.document.exportSchema(), true);
13
+ }
14
+ };
15
+ tslib_1.__decorate([
16
+ common_1.Singleton.GetOperation(),
17
+ tslib_1.__metadata("design:type", Function),
18
+ tslib_1.__metadata("design:paramtypes", []),
19
+ tslib_1.__metadata("design:returntype", void 0)
20
+ ], MetadataResource.prototype, "get", null);
21
+ MetadataResource = tslib_1.__decorate([
22
+ (0, common_1.Singleton)(Object, {
23
+ name: '$metadata',
24
+ }),
25
+ tslib_1.__metadata("design:paramtypes", [common_1.ApiDocument])
26
+ ], MetadataResource);
27
+ exports.MetadataResource = MetadataResource;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RequestContextHost = void 0;
4
+ const strict_typed_events_1 = require("strict-typed-events");
5
+ class RequestContextHost extends strict_typed_events_1.AsyncEventEmitter {
6
+ constructor(protocol, platform, api, _request, _response) {
7
+ super();
8
+ this.protocol = protocol;
9
+ this.platform = platform;
10
+ this.api = api;
11
+ this._request = _request;
12
+ this._response = _response;
13
+ }
14
+ get request() {
15
+ return this._request;
16
+ }
17
+ get response() {
18
+ return this._response;
19
+ }
20
+ switchToHttp() {
21
+ throw new TypeError('Not executing in an "Http" protocol');
22
+ }
23
+ switchToWs() {
24
+ throw new TypeError('Not executing in an "WebSocket" protocol');
25
+ }
26
+ switchToRpc() {
27
+ throw new TypeError('Not executing in an "RPC" protocol');
28
+ }
29
+ }
30
+ exports.RequestContextHost = RequestContextHost;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RequestHost = void 0;
4
+ class RequestHost {
5
+ constructor(init) {
6
+ Object.assign(this, init);
7
+ this.resourceKind = this.resource.kind;
8
+ }
9
+ switchToHttp() {
10
+ throw new TypeError('Not executing in an "Http" protocol');
11
+ }
12
+ switchToWs() {
13
+ throw new TypeError('Not executing in an "WebSocket" protocol');
14
+ }
15
+ switchToRpc() {
16
+ throw new TypeError('Not executing in an "RPC" protocol');
17
+ }
18
+ }
19
+ exports.RequestHost = RequestHost;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseHost = void 0;
4
+ class ResponseHost {
5
+ constructor(init) {
6
+ if (init)
7
+ Object.assign(this, init);
8
+ this.errors = this.errors || [];
9
+ }
10
+ switchToHttp() {
11
+ throw new TypeError('Not executing in an "Http" protocol');
12
+ }
13
+ switchToWs() {
14
+ throw new TypeError('Not executing in an "WebSocket" protocol');
15
+ }
16
+ switchToRpc() {
17
+ throw new TypeError('Not executing in an "RPC" protocol');
18
+ }
19
+ }
20
+ exports.ResponseHost = ResponseHost;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const common_1 = require("@opra/common");
4
+ // @ts-ignore
5
+ const oldConstruct = common_1.Resource.prototype._construct;
6
+ // @ts-ignore
7
+ common_1.Resource.prototype._construct = function (init) {
8
+ oldConstruct.call(this, init);
9
+ const _this = this;
10
+ _this.onInit = init.onInit;
11
+ _this.onShutdown = init.onShutdown;
12
+ };
13
+ common_1.Collection.OnInit = common_1.Singleton.OnInit = function () {
14
+ return (target, propertyKey) => {
15
+ const resourceMetadata = (Reflect.getOwnMetadata(common_1.METADATA_KEY, target.constructor) || {});
16
+ resourceMetadata.onInit = target[propertyKey];
17
+ Reflect.defineMetadata(common_1.METADATA_KEY, target.constructor, resourceMetadata);
18
+ };
19
+ };
20
+ common_1.Collection.OnShutdown = common_1.Singleton.OnShutdown = function () {
21
+ return (target, propertyKey) => {
22
+ const resourceMetadata = (Reflect.getOwnMetadata(common_1.METADATA_KEY, target.constructor) || {});
23
+ resourceMetadata.onShutdown = target[propertyKey];
24
+ Reflect.defineMetadata(common_1.METADATA_KEY, target.constructor, resourceMetadata);
25
+ };
26
+ };
package/cjs/index.js CHANGED
@@ -2,13 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  require("reflect-metadata");
5
+ require("./augmentation/resource.augmentation.js");
5
6
  tslib_1.__exportStar(require("./types.js"), exports);
6
- tslib_1.__exportStar(require("./interfaces/execution-context.interface.js"), exports);
7
- tslib_1.__exportStar(require("./interfaces/resource.interface.js"), exports);
8
- tslib_1.__exportStar(require("./interfaces/i18n-options.interface.js"), exports);
9
- tslib_1.__exportStar(require("./adapter/request-contexts/single-request-context.js"), exports);
10
7
  tslib_1.__exportStar(require("./adapter/adapter.js"), exports);
11
- tslib_1.__exportStar(require("./adapter/http-adapter.js"), exports);
12
- tslib_1.__exportStar(require("./adapter/express-adapter.js"), exports);
13
- tslib_1.__exportStar(require("./services/data-service.js"), exports);
14
- tslib_1.__exportStar(require("./services/json-singleton-service.js"), exports);
8
+ tslib_1.__exportStar(require("./adapter/http/express-adapter.js"), exports);
9
+ tslib_1.__exportStar(require("./adapter/http/http-adapter.js"), exports);
10
+ tslib_1.__exportStar(require("./adapter/interfaces/request-context.interface.js"), exports);
11
+ tslib_1.__exportStar(require("./adapter/interfaces/logger.interface.js"), exports);
12
+ tslib_1.__exportStar(require("./adapter/interfaces/request.interface.js"), exports);
13
+ tslib_1.__exportStar(require("./adapter/interfaces/response.interface.js"), exports);