@opra/core 0.14.0 → 0.16.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 (105) hide show
  1. package/cjs/adapter/adapter.js +89 -293
  2. package/cjs/adapter/http/express-adapter.js +27 -0
  3. package/cjs/adapter/http/http-adapter.js +467 -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.js +97 -297
  14. package/esm/adapter/http/express-adapter.js +27 -0
  15. package/esm/adapter/http/http-adapter.js +467 -0
  16. package/esm/adapter/http/http-request-context.host.js +28 -0
  17. package/esm/adapter/http/http-request.host.js +14 -0
  18. package/esm/adapter/http/http-response.host.js +14 -0
  19. package/esm/adapter/interfaces/request-context.interface.js +2 -0
  20. package/esm/adapter/interfaces/request.interface.js +2 -0
  21. package/esm/adapter/interfaces/response.interface.js +2 -0
  22. package/esm/adapter/internal/metadata.resource.js +27 -0
  23. package/esm/adapter/request-context.host.js +30 -0
  24. package/esm/adapter/request.host.js +19 -0
  25. package/esm/adapter/response.host.js +20 -0
  26. package/esm/augmentation/resource.augmentation.js +26 -0
  27. package/esm/index.js +13 -11
  28. package/esm/types.js +2 -1
  29. package/i18n/en/error.json +2 -2
  30. package/package.json +11 -8
  31. package/types/adapter/adapter.d.ts +63 -0
  32. package/types/adapter/http/express-adapter.d.ts +11 -0
  33. package/types/adapter/http/http-adapter.d.ts +37 -0
  34. package/types/adapter/http/http-request-context.host.d.ts +16 -0
  35. package/types/adapter/http/http-request.host.d.ts +7 -0
  36. package/types/adapter/http/http-response.host.d.ts +7 -0
  37. package/{esm → types/adapter}/interfaces/logger.interface.d.ts +1 -0
  38. package/types/adapter/interfaces/request-context.interface.d.ts +25 -0
  39. package/types/adapter/interfaces/request.interface.d.ts +13 -0
  40. package/types/adapter/interfaces/response.interface.d.ts +22 -0
  41. package/types/adapter/internal/metadata.resource.d.ts +7 -0
  42. package/types/adapter/request-context.host.d.ts +19 -0
  43. package/types/adapter/request.host.d.ts +26 -0
  44. package/types/adapter/response.host.d.ts +20 -0
  45. package/types/augmentation/resource.augmentation.d.ts +33 -0
  46. package/types/index.d.ts +10 -0
  47. package/cjs/adapter/classes/execution-context.host.js +0 -16
  48. package/cjs/adapter/classes/express-request-wrapper.host.js +0 -36
  49. package/cjs/adapter/classes/express-response-wrapper.host.js +0 -55
  50. package/cjs/adapter/classes/http-execution-context.host.js +0 -28
  51. package/cjs/adapter/classes/metadata.resource.js +0 -22
  52. package/cjs/adapter/express-adapter.js +0 -26
  53. package/cjs/adapter/http-adapter.js +0 -443
  54. package/cjs/adapter/request-contexts/batch-request-context.js +0 -11
  55. package/cjs/adapter/request-contexts/request-context.js +0 -25
  56. package/cjs/adapter/request-contexts/single-request-context.js +0 -14
  57. package/cjs/services/data-service.js +0 -9
  58. package/cjs/services/json-singleton-service.js +0 -96
  59. package/cjs/utils/create-i18n.js +0 -21
  60. package/cjs/utils/get-caller-file.util.js +0 -24
  61. package/esm/adapter/adapter.d.ts +0 -38
  62. package/esm/adapter/classes/execution-context.host.d.ts +0 -10
  63. package/esm/adapter/classes/execution-context.host.js +0 -12
  64. package/esm/adapter/classes/express-request-wrapper.host.d.ts +0 -19
  65. package/esm/adapter/classes/express-request-wrapper.host.js +0 -32
  66. package/esm/adapter/classes/express-response-wrapper.host.d.ts +0 -22
  67. package/esm/adapter/classes/express-response-wrapper.host.js +0 -51
  68. package/esm/adapter/classes/http-execution-context.host.d.ts +0 -13
  69. package/esm/adapter/classes/http-execution-context.host.js +0 -24
  70. package/esm/adapter/classes/metadata.resource.d.ts +0 -8
  71. package/esm/adapter/classes/metadata.resource.js +0 -19
  72. package/esm/adapter/express-adapter.d.ts +0 -11
  73. package/esm/adapter/express-adapter.js +0 -21
  74. package/esm/adapter/http-adapter.d.ts +0 -37
  75. package/esm/adapter/http-adapter.js +0 -439
  76. package/esm/adapter/request-contexts/batch-request-context.d.ts +0 -7
  77. package/esm/adapter/request-contexts/batch-request-context.js +0 -7
  78. package/esm/adapter/request-contexts/request-context.d.ts +0 -22
  79. package/esm/adapter/request-contexts/request-context.js +0 -21
  80. package/esm/adapter/request-contexts/single-request-context.d.ts +0 -10
  81. package/esm/adapter/request-contexts/single-request-context.js +0 -10
  82. package/esm/enums/issue-severity.enum.d.ts +0 -1
  83. package/esm/enums/issue-severity.enum.js +0 -1
  84. package/esm/index.d.ts +0 -11
  85. package/esm/interfaces/execution-context.interface.d.ts +0 -47
  86. package/esm/interfaces/execution-context.interface.js +0 -1
  87. package/esm/interfaces/i18n-options.interface.d.ts +0 -28
  88. package/esm/interfaces/i18n-options.interface.js +0 -1
  89. package/esm/interfaces/logger.interface.js +0 -1
  90. package/esm/interfaces/resource.interface.d.ts +0 -23
  91. package/esm/interfaces/resource.interface.js +0 -1
  92. package/esm/services/data-service.d.ts +0 -2
  93. package/esm/services/data-service.js +0 -5
  94. package/esm/services/json-singleton-service.d.ts +0 -39
  95. package/esm/services/json-singleton-service.js +0 -91
  96. package/esm/utils/create-i18n.d.ts +0 -3
  97. package/esm/utils/create-i18n.js +0 -16
  98. package/esm/utils/get-caller-file.util.d.ts +0 -1
  99. package/esm/utils/get-caller-file.util.js +0 -20
  100. /package/cjs/{interfaces → adapter/interfaces}/logger.interface.js +0 -0
  101. /package/cjs/{enums/issue-severity.enum.js → adapter/interfaces/request-context.interface.js} +0 -0
  102. /package/cjs/{interfaces/execution-context.interface.js → adapter/interfaces/request.interface.js} +0 -0
  103. /package/cjs/{interfaces/i18n-options.interface.js → adapter/interfaces/response.interface.js} +0 -0
  104. /package/{cjs/interfaces/resource.interface.js → esm/adapter/interfaces/logger.interface.js} +0 -0
  105. /package/{esm → types}/types.d.ts +0 -0
@@ -1,322 +1,118 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpraAdapter = void 0;
4
- const power_tasks_1 = require("power-tasks");
4
+ const tslib_1 = require("tslib");
5
+ const path_1 = tslib_1.__importDefault(require("path"));
5
6
  const strict_typed_events_1 = require("strict-typed-events");
6
7
  const common_1 = require("@opra/common");
7
- const create_i18n_js_1 = require("../utils/create-i18n.js");
8
- const metadata_resource_js_1 = require("./classes/metadata.resource.js");
9
- const batch_request_context_js_1 = require("./request-contexts/batch-request-context.js");
10
- const single_request_context_js_1 = require("./request-contexts/single-request-context.js");
11
- const noOp = () => void 0;
12
- class OpraAdapter {
13
- constructor(document) {
14
- this.document = document;
15
- this._internalResources = new common_1.ResponsiveMap();
8
+ const metadata_resource_js_1 = require("./internal/metadata.resource.js");
9
+ /**
10
+ * @class OpraAdapter
11
+ */
12
+ class OpraAdapter extends strict_typed_events_1.AsyncEventEmitter {
13
+ constructor(api) {
14
+ super();
15
+ this.api = api;
16
16
  }
17
- async close() {
18
- const promises = [];
19
- for (const r of this.document.resources.values()) {
20
- if (r.instance) {
21
- const shutDown = r.instance.shutDown;
22
- if (shutDown)
23
- promises.push((async () => shutDown.call(r.instance))());
24
- }
25
- }
26
- await Promise.allSettled(promises);
27
- }
28
- async handler(executionContext) {
29
- let requestContext;
30
- let failed = false;
31
- try {
32
- if (this.userContextResolver)
33
- executionContext.userContext = this.userContextResolver(executionContext);
34
- requestContext = await this.parse(executionContext);
35
- const task = this._requestContextToTask(executionContext, requestContext);
36
- await task.toPromise().catch(noOp);
37
- await this.sendResponse(executionContext, requestContext);
38
- }
39
- catch (e) {
40
- failed = true;
41
- const error = (0, common_1.wrapException)(e);
42
- await this.sendError(executionContext, error);
43
- if (this.logger)
44
- try {
45
- this.logger.error(e);
46
- }
47
- catch {
48
- // noop
49
- }
50
- }
51
- finally {
52
- if (executionContext instanceof strict_typed_events_1.AsyncEventEmitter) {
53
- await executionContext
54
- .emitAsyncSerial('finish', {
55
- context: executionContext,
56
- failed
57
- }).catch();
58
- }
59
- }
60
- }
61
- _requestContextToTask(executionContext, requestContext) {
62
- if (requestContext instanceof batch_request_context_js_1.BatchRequestContext) {
63
- const children = requestContext.queries.map(q => this._requestContextToTask(executionContext, q));
64
- return new power_tasks_1.Task(children, { bail: true });
65
- }
66
- else if (requestContext instanceof single_request_context_js_1.SingleRequestContext) {
67
- const { query } = requestContext;
68
- const task = new power_tasks_1.Task(async () => {
69
- if (query.resource) {
70
- const { resource } = query;
71
- // call pre_xxx method
72
- const fn = resource.metadata['pre_' + query.method];
73
- if (fn && typeof fn === 'function') {
74
- await fn(requestContext);
75
- }
76
- await this._executeResourceQuery(this.document, resource, requestContext);
77
- // todo execute sub property queries
78
- return;
79
- }
80
- throw new common_1.InternalServerError('Not implemented yet');
81
- }, {
82
- id: requestContext.contentId,
83
- exclusive: query.operation !== 'read'
84
- });
85
- task.on('finish', () => {
86
- if (task.error) {
87
- if (task.failedDependencies)
88
- requestContext.errors.push(new common_1.FailedDependencyError());
89
- else
90
- requestContext.errors.push((0, common_1.wrapException)(task.error));
91
- if (this.logger)
92
- try {
93
- this.logger.error(task.error);
94
- }
95
- catch {
96
- // noop
97
- }
98
- return;
99
- }
100
- });
101
- return task;
102
- }
103
- /* istanbul ignore next */
104
- throw new TypeError('Invalid request context instance');
105
- }
106
- async _init(options) {
17
+ /**
18
+ * Initializes the adapter
19
+ * @param options
20
+ * @protected
21
+ */
22
+ async init(options) {
107
23
  this.logger = options?.logger;
108
24
  if (options?.i18n instanceof common_1.I18n)
109
25
  this.i18n = options.i18n;
110
26
  else if (typeof options?.i18n === 'function')
111
27
  this.i18n = await options.i18n();
112
28
  else
113
- this.i18n = await (0, create_i18n_js_1.createI18n)(options?.i18n);
29
+ this.i18n = await this._createI18n(options?.i18n);
114
30
  this.i18n = this.i18n || common_1.I18n.defaultInstance;
115
31
  if (!this.i18n.isInitialized)
116
32
  await this.i18n.init();
117
- this.userContextResolver = options?.userContext;
118
- const metadataResource = new metadata_resource_js_1.MetadataResource();
119
- const metadataResourceInfo = new common_1.SingletonResourceInfo(this.document, '$metadata', this.document.getComplexDataType('object'), {
120
- kind: 'SingletonResource',
121
- type: 'object',
122
- instance: metadataResource,
123
- get: {
124
- handler: metadataResource.get.bind(metadataResource)
125
- }
33
+ if (options?.onRequest)
34
+ this.on('request', options.onRequest);
35
+ this._internalDoc = await common_1.DocumentFactory.createDocument({
36
+ version: common_1.OpraSchema.SpecVersion,
37
+ info: {
38
+ version: common_1.OpraSchema.SpecVersion,
39
+ title: 'Internal resources',
40
+ },
41
+ references: { 'api': this.api },
42
+ resources: [new metadata_resource_js_1.MetadataResource(this.api)]
126
43
  });
127
- this._internalResources.set(metadataResourceInfo.name, metadataResourceInfo);
128
- metadataResource.init(metadataResourceInfo);
129
- for (const r of this.document.resources.values()) {
130
- if (r.instance) {
131
- const init = r.instance.init;
132
- if (init)
133
- await init.call(r.instance, r);
134
- }
44
+ const promises = [];
45
+ for (const r of this.api.resources.values()) {
46
+ const onInit = r.onInit;
47
+ if (onInit)
48
+ promises.push((async () => onInit.call(r.controller, r))());
135
49
  }
50
+ await Promise.all(promises);
136
51
  }
137
- async _executeResourceQuery(document, resource, context) {
138
- if (resource instanceof common_1.CollectionResourceInfo) {
139
- const { query } = context;
140
- if (query instanceof common_1.CollectionSearchQuery) {
141
- const promises = [];
142
- let search;
143
- promises.push(this._executeCollectionResource(document, resource, context)
144
- .then(v => search = v));
145
- if (query.count && resource.metadata.count) {
146
- const ctx = {
147
- query: new common_1.CollectionCountQuery(query.resource, { filter: query.filter }),
148
- resultPath: ''
149
- };
150
- Object.setPrototypeOf(ctx, context);
151
- promises.push(this._executeCollectionResource(document, resource, ctx)
152
- .then(r => {
153
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_Count] = r;
154
- }));
155
- }
156
- await Promise.all(promises);
157
- context.response = search;
158
- return;
159
- }
160
- context.response = await this._executeCollectionResource(document, resource, context);
161
- return;
162
- }
163
- else if (resource instanceof common_1.SingletonResourceInfo) {
164
- context.response = await this._executeSingletonResource(document, resource, context);
165
- return;
52
+ /**
53
+ * Calls shutDown hook for all resources
54
+ */
55
+ async close() {
56
+ const promises = [];
57
+ for (const r of this.api.resources.values()) {
58
+ const onShutdown = r.onShutdown;
59
+ if (onShutdown)
60
+ promises.push((async () => onShutdown.call(r.controller, r))());
166
61
  }
167
- throw new Error(`Executing "${resource.kind}" has not been implemented yet`);
62
+ await Promise.allSettled(promises);
168
63
  }
169
- async _executeCollectionResource(document, resource, context) {
170
- const method = context.query.method;
171
- const handler = resource.getHandler(method);
172
- if (!handler)
173
- throw new common_1.ForbiddenError({
174
- message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { method }, `The resource endpoint does not accept '{{method}}' operations`),
175
- severity: 'error',
176
- code: 'RESOLVER_FORBIDDEN'
177
- });
178
- let result;
179
- switch (method) {
180
- case 'create': {
181
- const query = context.query;
182
- result = await handler(context, query.data, query);
183
- result = Array.isArray(result) ? result[0] : result;
184
- if (result)
185
- context.status = 201;
186
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = resource.dataType.name;
187
- return result;
188
- }
189
- case 'count': {
190
- const query = context.query;
191
- result = await handler(context, query);
192
- return result;
193
- }
194
- case 'get': {
195
- const query = context.query;
196
- result = await handler(context, query.keyValue, query);
197
- result = Array.isArray(result) ? result[0] : result;
198
- if (!result)
199
- throw new common_1.ResourceNotFoundError(resource.name, query.keyValue);
200
- const v = await this._pathWalkThrough(query, query.dataType, result, resource.name);
201
- if (v.value === undefined)
202
- throw new common_1.ResourceNotFoundError(v.path);
203
- if (v.dataType)
204
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = v.dataType.name;
205
- return v.value;
206
- }
207
- case 'search': {
208
- const query = context.query;
209
- result = await handler(context, query);
210
- const items = Array.isArray(result) ? result : (context.response ? [result] : []);
211
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = resource.dataType.name;
212
- return items;
213
- }
214
- case 'update': {
215
- const query = context.query;
216
- result = await handler(context, query.keyValue, query.data, query);
217
- result = Array.isArray(result) ? result[0] : result;
218
- if (!result)
219
- throw new common_1.ResourceNotFoundError(resource.name, query.keyValue);
220
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = resource.dataType.name;
221
- return result;
222
- }
223
- case 'delete':
224
- case 'deleteMany':
225
- case 'updateMany': {
226
- switch (method) {
227
- case 'delete': {
228
- const query = context.query;
229
- result = await handler(context, query.keyValue, query);
230
- break;
231
- }
232
- case 'deleteMany': {
233
- const query = context.query;
234
- result = await handler(context, query);
235
- break;
236
- }
237
- case 'updateMany': {
238
- const query = context.query;
239
- result = await handler(context, query.data, query);
240
- break;
241
- }
242
- }
243
- let affected;
244
- if (typeof result === 'number')
245
- affected = result;
246
- if (typeof result === 'boolean')
247
- affected = result ? 1 : 0;
248
- if (typeof result === 'object')
249
- affected = result.affectedRows || result.affected;
250
- return {
251
- operation: context.query.method,
64
+ async executeRequest(context) {
65
+ await this.emitAsync('request', context);
66
+ const { request, response } = context;
67
+ const { resource, operation } = request;
68
+ if (resource instanceof common_1.Collection || resource instanceof common_1.Singleton) {
69
+ const endpoint = resource.operations[operation];
70
+ if (!endpoint?.handler)
71
+ throw new common_1.ForbiddenError({
72
+ message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { operation }, `The resource endpoint does not accept '{{operation}}' operations`),
73
+ severity: 'error',
74
+ code: 'RESOLVER_FORBIDDEN'
75
+ });
76
+ const value = await endpoint.handler(context);
77
+ // if (value == null)
78
+ if (value != null)
79
+ response.value = value;
80
+ const { crud, many } = request;
81
+ if (crud === 'delete' || (crud === 'update' && many)) {
82
+ let affected = 0;
83
+ if (typeof response.value === 'number')
84
+ affected = response.value;
85
+ if (typeof response.value === 'boolean')
86
+ affected = response.value ? 1 : 0;
87
+ if (typeof response.value === 'object')
88
+ affected = response.value.affectedRows || response.value.affected;
89
+ response.value = {
90
+ operation: request.operation,
252
91
  affected
253
92
  };
254
93
  }
255
- }
256
- }
257
- async _executeSingletonResource(document, resource, context) {
258
- const method = context.query.method;
259
- const resolverInfo = resource.metadata[method];
260
- if (!(resolverInfo && resolverInfo.handler))
261
- throw new common_1.ForbiddenError({
262
- message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { method }, `The resource endpoint does not accept '{{method}}' operations`),
263
- severity: 'error',
264
- code: 'RESOLVER_FORBIDDEN'
265
- });
266
- let result = await resolverInfo.handler(context);
267
- switch (method) {
268
- case 'get': {
269
- const query = context.query;
270
- result = await resolverInfo.handler(context, query);
271
- result = Array.isArray(result) ? result[0] : result;
272
- if (!result)
273
- throw new common_1.ResourceNotFoundError(resource.name);
274
- const v = await this._pathWalkThrough(query, query.dataType, result, resource.name);
275
- if (v.value === undefined)
276
- throw new common_1.ResourceNotFoundError(v.path);
277
- if (v.dataType)
278
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = v.dataType.name;
279
- return v.value;
280
- }
281
- }
282
- if (!result)
283
- return;
284
- result = Array.isArray(result) ? result[0] : result;
285
- let dataType = resource.dataType;
286
- if (context.resultPath) {
287
- const pathArray = context.resultPath.split('.');
288
- for (const field of pathArray) {
289
- const prop = dataType instanceof common_1.ComplexType ? dataType.fields.get(field) : undefined;
290
- dataType = prop && prop.type ? this.document.types.get(prop.type) : undefined;
291
- result = result && typeof result === 'object' && result[field];
94
+ else if (response.value != null) {
95
+ if (!request.many)
96
+ response.value = Array.isArray(response.value) ? response.value[0] : response.value;
97
+ else
98
+ response.value = Array.isArray(response.value) ? response.value : [response.value];
292
99
  }
100
+ if ((request.operation === 'get' || request.operation === 'update') && response.value == null)
101
+ throw new common_1.ResourceNotFoundError(resource.name, request.args.key);
293
102
  }
294
- if (method === 'create')
295
- context.status = 201;
296
- context.responseHeaders[common_1.HttpHeaderCodes.X_Opra_DataType] = resource.dataType.name;
297
- return result;
298
103
  }
299
- async _pathWalkThrough(query, dataType, value, parentPath) {
300
- const { child } = query;
301
- if (!child)
302
- return { value, dataType, path: parentPath };
303
- // Make a case in sensitive lookup
304
- const fieldNameLower = child.fieldName.toLowerCase();
305
- const path = parentPath + (parentPath ? '.' : '') + child.fieldName;
306
- for (const key of Object.keys(value)) {
307
- if (key.toLowerCase() === fieldNameLower) {
308
- let v = value[key];
309
- if (v == null)
310
- return { path };
311
- if (child.child && child.dataType instanceof common_1.ComplexType) {
312
- if (Array.isArray(v))
313
- v = v[0];
314
- return this._pathWalkThrough(child, child.dataType, v, path);
315
- }
316
- return { value: v, dataType: child.dataType, path };
317
- }
318
- }
319
- return { path };
104
+ async _createI18n(options) {
105
+ const opts = {
106
+ ...options,
107
+ };
108
+ delete opts.resourceDirs;
109
+ const instance = common_1.I18n.createInstance(opts);
110
+ await instance.init();
111
+ await instance.loadResourceDir(path_1.default.resolve((0, common_1.getStackFileName)(), '../../../i18n'));
112
+ if (options?.resourceDirs)
113
+ for (const dir of options.resourceDirs)
114
+ await instance.loadResourceDir(dir);
115
+ return instance;
320
116
  }
321
117
  }
322
118
  exports.OpraAdapter = OpraAdapter;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpraExpressAdapter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const body_parser_1 = tslib_1.__importDefault(require("body-parser"));
6
+ const common_1 = require("@opra/common");
7
+ const http_adapter_js_1 = require("./http-adapter.js");
8
+ const noOp = () => void 0;
9
+ class OpraExpressAdapter extends http_adapter_js_1.OpraHttpAdapter {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.platform = 'express';
13
+ }
14
+ static async create(app, document, options) {
15
+ const adapter = new OpraExpressAdapter(document);
16
+ await adapter.init(options);
17
+ const prefix = '/' + (0, common_1.normalizePath)(options?.prefix, true);
18
+ app.use(prefix, body_parser_1.default.json());
19
+ app.use(prefix, (req, res, next) => {
20
+ req.end = noOp;
21
+ req.send = noOp;
22
+ adapter.handler(req, res).catch(e => next(e));
23
+ });
24
+ return adapter;
25
+ }
26
+ }
27
+ exports.OpraExpressAdapter = OpraExpressAdapter;