@opra/core 0.25.5 → 0.26.1

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 (63) hide show
  1. package/cjs/augmentation/container.augmentation.js +2 -0
  2. package/cjs/http/adapters/express-adapter.host.js +34 -0
  3. package/cjs/http/{express-adapter.js → adapters/express-adapter.js} +1 -3
  4. package/cjs/http/{http-adapter.host.js → adapters/node-http-adapter.host.js} +30 -22
  5. package/cjs/http/adapters/node-http-adapter.js +14 -0
  6. package/cjs/http/helpers/json-body-loader.js +29 -0
  7. package/cjs/http/http-adapter-host.js +678 -0
  8. package/cjs/index.js +4 -3
  9. package/cjs/platform-adapter.host.js +74 -45
  10. package/cjs/{endpoint-context.js → request-context.js} +5 -5
  11. package/cjs/request.host.js +3 -0
  12. package/esm/augmentation/container.augmentation.js +1 -0
  13. package/esm/http/adapters/express-adapter.host.js +30 -0
  14. package/esm/http/{express-adapter.js → adapters/express-adapter.js} +1 -3
  15. package/esm/http/{http-adapter.host.js → adapters/node-http-adapter.host.js} +28 -20
  16. package/esm/http/adapters/node-http-adapter.js +11 -0
  17. package/esm/http/helpers/json-body-loader.js +24 -0
  18. package/esm/http/http-adapter-host.js +673 -0
  19. package/esm/index.js +4 -3
  20. package/esm/platform-adapter.host.js +75 -46
  21. package/esm/{endpoint-context.js → request-context.js} +4 -4
  22. package/esm/request.host.js +3 -0
  23. package/i18n/en/error.json +1 -2
  24. package/package.json +14 -14
  25. package/types/augmentation/collection.augmentation.d.ts +19 -16
  26. package/types/augmentation/container.augmentation.d.ts +13 -0
  27. package/types/augmentation/resource.augmentation.d.ts +2 -2
  28. package/types/augmentation/singleton.augmentation.d.ts +13 -9
  29. package/types/augmentation/storage.augmentation.d.ts +11 -14
  30. package/types/http/{express-adapter.d.ts → adapters/express-adapter.d.ts} +3 -3
  31. package/types/http/adapters/express-adapter.host.d.ts +12 -0
  32. package/types/http/{http-adapter.d.ts → adapters/node-http-adapter.d.ts} +5 -5
  33. package/types/http/adapters/node-http-adapter.host.d.ts +19 -0
  34. package/types/http/helpers/json-body-loader.d.ts +5 -0
  35. package/types/http/http-adapter-host.d.ts +34 -0
  36. package/types/index.d.ts +4 -3
  37. package/types/interfaces/request-handler.interface.d.ts +1 -1
  38. package/types/platform-adapter.d.ts +2 -2
  39. package/types/platform-adapter.host.d.ts +18 -14
  40. package/types/{endpoint-context.d.ts → request-context.d.ts} +3 -3
  41. package/types/request.d.ts +7 -2
  42. package/types/request.host.d.ts +5 -2
  43. package/cjs/http/express-adapter.host.js +0 -24
  44. package/cjs/http/http-adapter-base.js +0 -138
  45. package/cjs/http/http-adapter.js +0 -16
  46. package/cjs/http/request-handlers/entity-request-handler.js +0 -429
  47. package/cjs/http/request-handlers/parse-batch-request.js +0 -169
  48. package/cjs/http/request-handlers/request-handler-base.js +0 -37
  49. package/cjs/http/request-handlers/storage-request-handler.js +0 -139
  50. package/esm/http/express-adapter.host.js +0 -20
  51. package/esm/http/http-adapter-base.js +0 -134
  52. package/esm/http/http-adapter.js +0 -13
  53. package/esm/http/request-handlers/entity-request-handler.js +0 -424
  54. package/esm/http/request-handlers/parse-batch-request.js +0 -169
  55. package/esm/http/request-handlers/request-handler-base.js +0 -33
  56. package/esm/http/request-handlers/storage-request-handler.js +0 -134
  57. package/types/http/express-adapter.host.d.ts +0 -11
  58. package/types/http/http-adapter-base.d.ts +0 -23
  59. package/types/http/http-adapter.host.d.ts +0 -18
  60. package/types/http/request-handlers/entity-request-handler.d.ts +0 -24
  61. package/types/http/request-handlers/parse-batch-request.d.ts +0 -0
  62. package/types/http/request-handlers/request-handler-base.d.ts +0 -16
  63. package/types/http/request-handlers/storage-request-handler.d.ts +0 -23
@@ -1,424 +0,0 @@
1
- import bodyParser from 'body-parser';
2
- import { toBoolean, toInt } from 'putil-varhelpers';
3
- import * as valgen from 'valgen';
4
- import { BadRequestError, Collection, HttpHeaderCodes, HttpStatusCodes, InternalServerError, MethodNotAllowedError, OpraException, ResourceNotFoundError, Singleton, translate, } from '@opra/common';
5
- import { EndpointContext } from '../../endpoint-context.js';
6
- import { RequestHost } from '../../request.host.js';
7
- import { ResponseHost } from '../../response.host.js';
8
- import { parseArrayParam } from '../helpers/query-parsers.js';
9
- import { RequestHandlerBase } from './request-handler-base.js';
10
- /**
11
- * @class EntityRequestHandler
12
- */
13
- export class EntityRequestHandler extends RequestHandlerBase {
14
- constructor(adapter) {
15
- super(adapter);
16
- this.adapter = adapter;
17
- this.bodyLoaders = new WeakMap();
18
- }
19
- async processRequest(executionContext) {
20
- const { incoming, outgoing } = executionContext.switchToHttp();
21
- // Parse incoming message and create Request object
22
- const request = await this.parseRequest(incoming);
23
- if (!request)
24
- return;
25
- const response = new ResponseHost({ http: outgoing });
26
- const context = EndpointContext.from(executionContext, request, response);
27
- await this.callEndpoint(context);
28
- if (response.errors.length) {
29
- context.errors.push(...response.errors);
30
- return;
31
- }
32
- try {
33
- await this.sendResponse(context);
34
- }
35
- catch (e) {
36
- if (e instanceof OpraException)
37
- throw e;
38
- if (e instanceof valgen.ValidationError) {
39
- throw new InternalServerError({
40
- message: translate('error:RESPONSE_VALIDATION,', 'Response validation failed'),
41
- code: 'RESPONSE_VALIDATION',
42
- details: e.issues
43
- }, e);
44
- }
45
- throw new InternalServerError(e);
46
- }
47
- }
48
- async parseRequest(incoming) {
49
- const p = incoming.parsedUrl.path[0];
50
- const resource = this.adapter.api.getResource(p.resource, true);
51
- if (!resource)
52
- throw new BadRequestError({
53
- message: translate('error:SOURCE_NOT_FOUND,', 'Resource not found'),
54
- code: 'SOURCE_NOT_FOUND',
55
- details: {
56
- path: incoming.parsedUrl.address
57
- }
58
- });
59
- try {
60
- if (resource instanceof Collection)
61
- return await this.parseCollectionRequest(resource, incoming);
62
- if (resource instanceof Singleton)
63
- return await this.parseSingletonRequest(resource, incoming);
64
- }
65
- catch (e) {
66
- if (e instanceof OpraException)
67
- throw e;
68
- if (e instanceof valgen.ValidationError) {
69
- throw new BadRequestError({
70
- message: translate('error:REQUEST_VALIDATION,', 'Request validation failed'),
71
- code: 'REQUEST_VALIDATION',
72
- details: e.issues
73
- }, e);
74
- }
75
- throw new BadRequestError(e);
76
- }
77
- }
78
- async callEndpoint(context) {
79
- const request = context.request;
80
- const { response } = context;
81
- const resource = request.resource;
82
- // Call endpoint handler method
83
- let value;
84
- try {
85
- value = await request.controller[request.endpoint].call(request.controller, context);
86
- if (value == null)
87
- value = response.value;
88
- const { endpoint } = request;
89
- if (endpoint === 'delete' || endpoint === 'deleteMany' || endpoint === 'updateMany') {
90
- let affected = 0;
91
- if (typeof value === 'number')
92
- affected = value;
93
- if (typeof value === 'boolean')
94
- affected = value ? 1 : 0;
95
- if (typeof value === 'object')
96
- affected = value.affected || value.affectedRows ||
97
- (endpoint === 'updateMany' ? value.updated : value.deleted);
98
- response.value = affected;
99
- }
100
- else {
101
- // "get" and "update" endpoints must return the entity instance, otherwise it means resource not found
102
- if (value == null && (request.endpoint === 'get' || request.endpoint === 'update'))
103
- throw new ResourceNotFoundError(resource.name, request.key);
104
- // "findMany" endpoint should return array of entity instances
105
- if (request.endpoint === 'findMany')
106
- value = value == null ? [] : Array.isArray(value) ? value : [value];
107
- else
108
- value = value == null ? {} : Array.isArray(value) ? value[0] : value;
109
- response.value = value;
110
- }
111
- }
112
- catch (error) {
113
- response.errors.push(error);
114
- }
115
- }
116
- async sendResponse(context) {
117
- const { request, response } = context;
118
- const resource = request.resource;
119
- const outgoing = response.switchToHttp();
120
- let responseObject;
121
- if (request.endpoint === 'delete' || request.endpoint === 'deleteMany') {
122
- responseObject = {
123
- resource: resource.name,
124
- operation: 'delete',
125
- affected: response.value
126
- };
127
- }
128
- else if (request.endpoint === 'updateMany') {
129
- responseObject = {
130
- resource: resource.name,
131
- operation: 'update',
132
- affected: response.value
133
- };
134
- }
135
- else {
136
- if (!response.value)
137
- throw new InternalServerError(`"${request.endpoint}" endpoint should return value`);
138
- const encode = resource.getEncoder(request.endpoint);
139
- const data = encode(response.value, { coerce: true });
140
- if (request.endpoint === 'create')
141
- outgoing.statusCode = 201;
142
- responseObject = {
143
- resource: resource.name,
144
- endpoint: request.endpoint,
145
- data
146
- };
147
- if (request.endpoint === 'create' || request.endpoint === 'update')
148
- responseObject.affected = 1;
149
- if (request.endpoint === 'findMany' && response.count != null && response.count >= 0)
150
- responseObject.totalCount = response.count;
151
- }
152
- outgoing.statusCode = outgoing.statusCode || HttpStatusCodes.OK;
153
- const body = this.adapter._i18n.deep(responseObject);
154
- outgoing.setHeader(HttpHeaderCodes.Content_Type, 'application/opra+json; charset=utf-8');
155
- outgoing.send(JSON.stringify(body));
156
- outgoing.end();
157
- }
158
- async parseCollectionRequest(resource, incoming) {
159
- if ((incoming.method === 'POST' || incoming.method === 'PATCH') && !incoming.is('json'))
160
- throw new BadRequestError({ message: 'Unsupported Content-Type' });
161
- const contentId = incoming.headers['content-id'];
162
- const p = incoming.parsedUrl.path[0];
163
- const params = incoming.parsedUrl.searchParams;
164
- switch (incoming.method) {
165
- case 'POST': {
166
- if (p.key == null) {
167
- const endpointMeta = await this.assertEndpoint(resource, 'create');
168
- const jsonReader = this.getBodyLoader(endpointMeta);
169
- const decode = resource.getDecoder('create');
170
- let data = await jsonReader(incoming);
171
- data = decode(data, { coerce: true });
172
- const pick = parseArrayParam(params.get('$pick'));
173
- const omit = parseArrayParam(params.get('$omit'));
174
- const include = parseArrayParam(params.get('$include'));
175
- return new RequestHost({
176
- controller: endpointMeta.controller,
177
- http: incoming,
178
- contentId,
179
- resource,
180
- endpoint: 'create',
181
- data,
182
- params: {
183
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
184
- pick: pick && resource.normalizeFieldPath(pick),
185
- omit: omit && resource.normalizeFieldPath(omit),
186
- include: include && resource.normalizeFieldPath(include)
187
- }
188
- });
189
- }
190
- break;
191
- }
192
- case 'DELETE': {
193
- if (p.key != null) {
194
- const endpointMeta = await this.assertEndpoint(resource, 'delete');
195
- return new RequestHost({
196
- controller: endpointMeta.controller,
197
- http: incoming,
198
- contentId,
199
- resource,
200
- endpoint: 'delete',
201
- key: resource.parseKeyValue(p.key),
202
- params: this.parseParameters(incoming.parsedUrl, endpointMeta)
203
- });
204
- }
205
- const endpointMeta = await this.assertEndpoint(resource, 'deleteMany');
206
- const filter = resource.normalizeFilter(params.get('$filter'));
207
- return new RequestHost({
208
- controller: endpointMeta.controller,
209
- http: incoming,
210
- contentId,
211
- resource,
212
- endpoint: 'deleteMany',
213
- params: {
214
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
215
- filter
216
- }
217
- });
218
- }
219
- case 'GET': {
220
- const pick = parseArrayParam(params.get('$pick'));
221
- const omit = parseArrayParam(params.get('$omit'));
222
- const include = parseArrayParam(params.get('$include'));
223
- if (p.key != null) {
224
- const endpointMeta = await this.assertEndpoint(resource, 'get');
225
- return new RequestHost({
226
- controller: endpointMeta.controller,
227
- http: incoming,
228
- contentId,
229
- resource,
230
- endpoint: 'get',
231
- key: resource.parseKeyValue(p.key),
232
- params: {
233
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
234
- pick: pick && resource.normalizeFieldPath(pick),
235
- omit: omit && resource.normalizeFieldPath(omit),
236
- include: include && resource.normalizeFieldPath(include)
237
- }
238
- });
239
- }
240
- const endpointMeta = await this.assertEndpoint(resource, 'findMany');
241
- const filter = resource.normalizeFilter(params.get('$filter'));
242
- const sort = parseArrayParam(params.get('$sort'));
243
- return new RequestHost({
244
- controller: endpointMeta.controller,
245
- http: incoming,
246
- contentId,
247
- resource,
248
- endpoint: 'findMany',
249
- params: {
250
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
251
- pick: pick && resource.normalizeFieldPath(pick),
252
- omit: omit && resource.normalizeFieldPath(omit),
253
- include: include && resource.normalizeFieldPath(include),
254
- sort: sort && resource.normalizeSortFields(sort),
255
- filter,
256
- limit: toInt(params.get('$limit')),
257
- skip: toInt(params.get('$skip')),
258
- distinct: toBoolean(params.get('$distinct')),
259
- count: toBoolean(params.get('$count')),
260
- }
261
- });
262
- }
263
- case 'PATCH': {
264
- if (p.key != null) {
265
- const endpointMeta = await this.assertEndpoint(resource, 'update');
266
- const jsonReader = this.getBodyLoader(endpointMeta);
267
- const decode = resource.getDecoder('update');
268
- let data = await jsonReader(incoming);
269
- data = decode(data, { coerce: true });
270
- const pick = parseArrayParam(params.get('$pick'));
271
- const omit = parseArrayParam(params.get('$omit'));
272
- const include = parseArrayParam(params.get('$include'));
273
- return new RequestHost({
274
- controller: endpointMeta.controller,
275
- http: incoming,
276
- contentId,
277
- resource,
278
- endpoint: 'update',
279
- key: resource.parseKeyValue(p.key),
280
- data,
281
- params: {
282
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
283
- pick: pick && resource.normalizeFieldPath(pick),
284
- omit: omit && resource.normalizeFieldPath(omit),
285
- include: include && resource.normalizeFieldPath(include),
286
- }
287
- });
288
- }
289
- const endpointMeta = await this.assertEndpoint(resource, 'updateMany');
290
- const jsonReader = this.getBodyLoader(endpointMeta);
291
- const decode = resource.getDecoder('updateMany');
292
- let data = await jsonReader(incoming);
293
- data = decode(data, { coerce: true });
294
- const filter = resource.normalizeFilter(params.get('$filter'));
295
- return new RequestHost({
296
- controller: endpointMeta.controller,
297
- http: incoming,
298
- contentId,
299
- resource,
300
- endpoint: 'updateMany',
301
- data,
302
- params: {
303
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
304
- filter,
305
- }
306
- });
307
- }
308
- }
309
- throw new MethodNotAllowedError({
310
- message: `Collection resource do not accept http "${incoming.method}" method`
311
- });
312
- }
313
- async parseSingletonRequest(resource, incoming) {
314
- if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
315
- incoming.headers['content-type'] !== 'application/json')
316
- throw new BadRequestError({ message: 'Unsupported Content-Type' });
317
- const contentId = incoming.headers['content-id'];
318
- const params = incoming.parsedUrl.searchParams;
319
- switch (incoming.method) {
320
- case 'POST': {
321
- const endpointMeta = await this.assertEndpoint(resource, 'create');
322
- const jsonReader = this.getBodyLoader(endpointMeta);
323
- const decode = resource.getDecoder('create');
324
- let data = await jsonReader(incoming);
325
- data = decode(data, { coerce: true });
326
- const pick = parseArrayParam(params.get('$pick'));
327
- const omit = parseArrayParam(params.get('$omit'));
328
- const include = parseArrayParam(params.get('$include'));
329
- return new RequestHost({
330
- controller: endpointMeta.controller,
331
- http: incoming,
332
- contentId,
333
- resource,
334
- endpoint: 'create',
335
- data,
336
- params: {
337
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
338
- pick: pick && resource.normalizeFieldPath(pick),
339
- omit: omit && resource.normalizeFieldPath(omit),
340
- include: include && resource.normalizeFieldPath(include)
341
- }
342
- });
343
- }
344
- case 'DELETE': {
345
- const endpointMeta = await this.assertEndpoint(resource, 'delete');
346
- return new RequestHost({
347
- controller: endpointMeta.controller,
348
- http: incoming,
349
- contentId,
350
- resource,
351
- endpoint: 'delete',
352
- params: this.parseParameters(incoming.parsedUrl, endpointMeta)
353
- });
354
- }
355
- case 'GET': {
356
- const endpointMeta = await this.assertEndpoint(resource, 'get');
357
- const pick = parseArrayParam(params.get('$pick'));
358
- const omit = parseArrayParam(params.get('$omit'));
359
- const include = parseArrayParam(params.get('$include'));
360
- return new RequestHost({
361
- controller: endpointMeta.controller,
362
- http: incoming,
363
- contentId,
364
- resource,
365
- endpoint: 'get',
366
- params: {
367
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
368
- pick: pick && resource.normalizeFieldPath(pick),
369
- omit: omit && resource.normalizeFieldPath(omit),
370
- include: include && resource.normalizeFieldPath(include)
371
- }
372
- });
373
- }
374
- case 'PATCH': {
375
- const endpointMeta = await this.assertEndpoint(resource, 'update');
376
- const jsonReader = this.getBodyLoader(endpointMeta);
377
- const decode = resource.getDecoder('update');
378
- let data = await jsonReader(incoming);
379
- data = decode(data, { coerce: true });
380
- const pick = parseArrayParam(params.get('$pick'));
381
- const omit = parseArrayParam(params.get('$omit'));
382
- const include = parseArrayParam(params.get('$include'));
383
- return new RequestHost({
384
- controller: endpointMeta.controller,
385
- http: incoming,
386
- contentId,
387
- resource,
388
- endpoint: 'update',
389
- data,
390
- params: {
391
- ...this.parseParameters(incoming.parsedUrl, endpointMeta),
392
- pick: pick && resource.normalizeFieldPath(pick),
393
- omit: omit && resource.normalizeFieldPath(omit),
394
- include: include && resource.normalizeFieldPath(include),
395
- }
396
- });
397
- }
398
- }
399
- throw new MethodNotAllowedError({
400
- message: `Singleton resource do not accept http "${incoming.method}" method`
401
- });
402
- }
403
- getBodyLoader(endpoint) {
404
- let bodyLoader = this.bodyLoaders.get(endpoint);
405
- if (!bodyLoader) {
406
- const parser = bodyParser.json({
407
- limit: endpoint.input?.maxContentSize,
408
- type: 'json'
409
- });
410
- bodyLoader = (incoming) => {
411
- return new Promise((resolve, reject) => {
412
- const next = (error) => {
413
- if (error)
414
- return reject(error);
415
- resolve(incoming.body);
416
- };
417
- parser(incoming, {}, next);
418
- });
419
- };
420
- this.bodyLoaders.set(endpoint, bodyLoader);
421
- }
422
- return bodyLoader;
423
- }
424
- }
@@ -1,169 +0,0 @@
1
- "use strict";
2
- // async parseMultiPart(
3
- // context: TExecutionContext,
4
- // url: OpraURL,
5
- // headers: IncomingHttpHeaders,
6
- // input: Readable,
7
- // boundary: string
8
- // ): Promise<BatchRequestContext> {
9
- // return await new Promise((resolve, reject) => {
10
- // let _resolved = false;
11
- // const dicer = new Dicer({boundary});
12
- // const doReject = (e) => {
13
- // if (_resolved) return;
14
- // _resolved = true;
15
- // reject(e);
16
- // taskQueue.clearQueue();
17
- // dicer.destroy();
18
- // }
19
- // const taskQueue = new TaskQueue({concurrency: 1});
20
- // taskQueue.on('error', doReject);
21
- //
22
- // const queries: SingleRequestContext[] = [];
23
- // let partCounter = 0;
24
- // dicer.on('error', doReject);
25
- // dicer.on('part', part => {
26
- // const partIndex = partCounter++;
27
- // let header: any;
28
- // const chunks: Buffer[] = [];
29
- // part.on('error', doReject);
30
- // part.on('header', (_header) => header = normalizeHeaders(_header));
31
- // part.on('data', (chunk: Buffer) => chunks.push(chunk));
32
- // part.on('end', () => {
33
- // if (_resolved || !(header || chunks.length))
34
- // return;
35
- // const ct = header['content-type'];
36
- // if (ct === 'application/http') {
37
- // taskQueue.enqueue(async () => {
38
- // const data = Buffer.concat(chunks);
39
- // if (!(data && data.length))
40
- // return;
41
- // const r = HttpRequest.parse(data);
42
- // await callMiddlewares(r, [jsonBodyParser]);
43
- // const subUrl = new OpraURL(r.url);
44
- // const contentId = header && header['content-id'];
45
- // queries.push(this.parseSingleQuery({
46
- // context,
47
- // url: subUrl,
48
- // method: r.method,
49
- // headers: r.headers,
50
- // body: r.body,
51
- // contentId
52
- // }));
53
- // });
54
- // } else doReject(new BadRequestError({
55
- // message: 'Unaccepted "content-type" header in multipart data',
56
- // details: {
57
- // position: `${boundary}[${partIndex}]`
58
- // }
59
- // }))
60
- // });
61
- // });
62
- // dicer.on('finish', () => {
63
- // taskQueue.enqueue(() => {
64
- // if (_resolved) return;
65
- // _resolved = true;
66
- // const batch = new BatchRequestContext({
67
- // service: this.document,
68
- // context,
69
- // headers,
70
- // queries,
71
- // params: url.searchParams,
72
- // continueOnError: false
73
- // });
74
- // resolve(batch);
75
- // });
76
- // });
77
- // input.pipe(dicer);
78
- // });
79
- // }
80
- // protected async sendBatchResponse(context: TExecutionContext, requestContext: BatchRequestContext) {
81
- // const resp = context.getResponse();
82
- // resp.setStatus(HttpStatus.OK);
83
- // resp.setHeader(HttpHeaderCodes.Cache_Control, 'no-cache');
84
- // resp.setHeader(HttpHeaderCodes.Pragma, 'no-cache');
85
- // resp.setHeader(HttpHeaderCodes.Expires, '-1');
86
- // if (requestContext.headers) {
87
- // for (const [k, v] of Object.entries(requestContext.headers)) {
88
- // if (v)
89
- // resp.setHeader(k, v);
90
- // }
91
- // }
92
- // const boundary = 'batch_' + uuid();
93
- // resp.setHeader(HttpHeaderCodes.Content_Type, 'multipart/mixed;boundary=' + boundary);
94
- // resp.setHeader(HttpHeaderCodes.X_Opra_Version, OpraSchema.Version);
95
- //
96
- // const bodyBuilder = new HttpMultipartData();
97
- //
98
- // const chunks: any[] = [];
99
- // let msgIdx = 0;
100
- // for (const ctx of requestContext.queries) {
101
- // msgIdx++;
102
- // const out = this.createOutput(ctx);
103
- //
104
- //
105
- // // chunks.push('--' + boundary + CRLF);
106
- // // let s = 'Content-Type: application/http' + CRLF +
107
- // // 'Content-Transfer-Encoding: binary' + CRLF +
108
- // // 'Content-ID:' + (ctx.contentId || msgIdx) + CRLF +
109
- // // CRLF +
110
- // // 'HTTP/1.1 ' + out.status + (HttpStatus[out.status] || 'Unknown') + CRLF;
111
- //
112
- // let body = out.body;
113
- // const headers = out.headers || {};
114
- // if (body) {
115
- // const contentType = String(headers['content-type'] || '').split(/\s*;\s*/);
116
- // let charset = '';
117
- // if (Highland.isStream(body)) {
118
- // const l = parseInt(String(headers['content-length']), 10);
119
- // if (isNaN(l))
120
- // throw new TypeError('"content-length" header required for streamed responses');
121
- // } else if (typeof body === 'object') {
122
- // if (typeof body.stream === 'function') { // File and Blob
123
- // contentType[0] = body.type || 'binary';
124
- // headers['content-length'] = String(body.size);
125
- // body = body.stream();
126
- // } else if (Buffer.isBuffer(body)) {
127
- // headers['content-length'] = String(body.length);
128
- // } else {
129
- // contentType[0] = contentType[0] || 'application/json';
130
- // charset = 'utf-8';
131
- // body = Buffer.from(JSON.stringify(body), 'utf-8');
132
- // headers['content-length'] = String(body.length);
133
- // }
134
- // } else {
135
- // contentType[0] = contentType[0] || 'text/plain';
136
- // charset = 'utf-8';
137
- // body = Buffer.from(String(body), 'utf-8');
138
- // headers['content-length'] = String(body.length);
139
- // }
140
- // if (contentType[0]) {
141
- // if (charset) {
142
- // const i = contentType.findIndex(x => CHARSET_PATTERN.test(String(x)));
143
- // if (i > 0) contentType[i] = 'charset=' + charset;
144
- // else contentType.join('charset=' + charset);
145
- // }
146
- // headers['content-type'] = contentType.join(';');
147
- // }
148
- // }
149
- // for (const [k, v] of Object.entries(headers))
150
- // s += k + ': ' + (Array.isArray(v) ? v.join(';') : v) + CRLF
151
- //
152
- // chunks.push(s + CRLF);
153
- //
154
- // if (body) {
155
- // if (typeof body === 'string')
156
- // chunks.push(body + CRLF + CRLF);
157
- // else {
158
- // chunks.push(body);
159
- // chunks.push(CRLF + CRLF);
160
- // }
161
- // }
162
- // }
163
- //
164
- // chunks.push('--' + boundary + '--' + CRLF);
165
- //
166
- // resp.setHeader('content-type', 'multipart/mixed;boundary=' + boundary);
167
- // resp.send(Highland(chunks).flatten());
168
- // resp.end();
169
- // }
@@ -1,33 +0,0 @@
1
- import { ForbiddenError, translate } from '@opra/common';
2
- /**
3
- * @class RequestHandlerBase
4
- */
5
- export class RequestHandlerBase {
6
- constructor(adapter) {
7
- this.adapter = adapter;
8
- }
9
- async assertEndpoint(resource, endpoint) {
10
- const controller = await this.adapter.getController(resource);
11
- const endpointMeta = (typeof controller?.[endpoint] === 'function') && resource.operations[endpoint];
12
- if (endpointMeta)
13
- return {
14
- ...endpointMeta,
15
- controller
16
- };
17
- throw new ForbiddenError({
18
- message: translate('RESOLVER_FORBIDDEN', { resource: resource.name, endpoint }, `'{{resource}}' endpoint does not accept '{{endpoint}}' operations`),
19
- severity: 'error',
20
- code: 'RESOLVER_FORBIDDEN'
21
- });
22
- }
23
- parseParameters(parsedUrl, metadata) {
24
- if (!metadata.parameters)
25
- return;
26
- const searchParams = parsedUrl.searchParams;
27
- const out = {};
28
- for (const [k] of Object.entries(metadata.parameters)) {
29
- out[k] = searchParams.get(k);
30
- }
31
- return out;
32
- }
33
- }