@opra/http 1.4.3 → 1.5.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.
@@ -48,7 +48,9 @@ class HttpContext extends core_1.ExecutionContext {
48
48
  return this._multipartReader;
49
49
  const { mediaType } = this;
50
50
  if (mediaType?.contentType) {
51
- const arr = Array.isArray(mediaType.contentType) ? mediaType.contentType : [mediaType.contentType];
51
+ const arr = Array.isArray(mediaType.contentType)
52
+ ? mediaType.contentType
53
+ : [mediaType.contentType];
52
54
  const contentType = arr.find(ct => type_is_1.default.is(ct, ['multipart']));
53
55
  if (!contentType)
54
56
  throw new common_1.NotAcceptableError('This endpoint does not accept multipart requests');
@@ -76,10 +78,13 @@ class HttpContext extends core_1.ExecutionContext {
76
78
  this._body = [...parts];
77
79
  return this._body;
78
80
  }
79
- this._body = await this.request.readBody({ limit: operation?.requestBody?.maxContentSize });
81
+ this._body = await this.request.readBody({
82
+ limit: operation?.requestBody?.maxContentSize,
83
+ });
80
84
  if (this._body != null) {
81
85
  // Convert Buffer to string if media is text
82
- if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text'])) {
86
+ if (Buffer.isBuffer(this._body) &&
87
+ request.is(['json', 'xml', 'txt', 'text'])) {
83
88
  this._body = this._body.toString('utf-8');
84
89
  }
85
90
  // Transform text to Object if media is JSON
@@ -127,12 +127,17 @@ class HttpHandler {
127
127
  const getDecoder = (prm) => {
128
128
  let decode = this[core_1.kAssetCache].get(prm, 'decode');
129
129
  if (!decode) {
130
- decode = prm.type?.generateCodec('decode', { ignoreReadonlyFields: true }) || valgen_1.vg.isAny();
130
+ decode =
131
+ prm.type?.generateCodec('decode', { ignoreReadonlyFields: true }) ||
132
+ valgen_1.vg.isAny();
131
133
  this[core_1.kAssetCache].set(prm, 'decode', decode);
132
134
  }
133
135
  return decode;
134
136
  };
135
- const paramsLeft = new Set([...operation.parameters, ...operation.owner.parameters]);
137
+ const paramsLeft = new Set([
138
+ ...operation.parameters,
139
+ ...operation.owner.parameters,
140
+ ]);
136
141
  /** parse cookie parameters */
137
142
  if (request.cookies) {
138
143
  for (key of Object.keys(request.cookies)) {
@@ -146,7 +151,11 @@ class HttpHandler {
146
151
  if (cntPrm)
147
152
  paramsLeft.delete(cntPrm);
148
153
  const decode = getDecoder(prm);
149
- const v = decode(request.cookies[key], { coerce: true, label: key, onFail });
154
+ const v = decode(request.cookies[key], {
155
+ coerce: true,
156
+ label: key,
157
+ onFail,
158
+ });
150
159
  const prmName = typeof prm.name === 'string' ? prm.name : key;
151
160
  if (v !== undefined)
152
161
  context.cookies[prmName] = v;
@@ -165,7 +174,11 @@ class HttpHandler {
165
174
  if (cntPrm)
166
175
  paramsLeft.delete(cntPrm);
167
176
  const decode = getDecoder(prm);
168
- const v = decode(request.headers[key], { coerce: true, label: key, onFail });
177
+ const v = decode(request.headers[key], {
178
+ coerce: true,
179
+ label: key,
180
+ onFail,
181
+ });
169
182
  const prmName = typeof prm.name === 'string' ? prm.name : key;
170
183
  if (v !== undefined)
171
184
  context.headers[prmName] = v;
@@ -184,7 +197,11 @@ class HttpHandler {
184
197
  if (cntPrm)
185
198
  paramsLeft.delete(cntPrm);
186
199
  const decode = getDecoder(prm);
187
- const v = decode(request.params[key], { coerce: true, label: key, onFail });
200
+ const v = decode(request.params[key], {
201
+ coerce: true,
202
+ label: key,
203
+ onFail,
204
+ });
188
205
  if (v !== undefined)
189
206
  context.pathParams[key] = v;
190
207
  }
@@ -206,7 +223,9 @@ class HttpHandler {
206
223
  let values = searchParams?.getAll(key);
207
224
  const prmName = typeof prm.name === 'string' ? prm.name : key;
208
225
  if (values?.length && prm.isArray) {
209
- values = values.map(v => (0, fast_tokenizer_1.splitString)(v, { delimiters: prm.arraySeparator, quotes: true })).flat();
226
+ values = values
227
+ .map(v => (0, fast_tokenizer_1.splitString)(v, { delimiters: prm.arraySeparator, quotes: true }))
228
+ .flat();
210
229
  values = values.map(v => decode(v, { coerce: true, label: key, onFail }));
211
230
  if (values.length)
212
231
  context.queryParams[prmName] = values;
@@ -255,7 +274,9 @@ class HttpHandler {
255
274
  type_is_1.default.is(contentType, Array.isArray(mc.contentType) ? mc.contentType : [mc.contentType]));
256
275
  }
257
276
  if (!mediaType) {
258
- const contentTypes = operation.requestBody.content.map(mc => mc.contentType).flat();
277
+ const contentTypes = operation.requestBody.content
278
+ .map(mc => mc.contentType)
279
+ .flat();
259
280
  throw new common_1.BadRequestError(`Request body should be one of required content types (${contentTypes.join(', ')})`);
260
281
  }
261
282
  (0, ts_gems_1.asMutable)(context).mediaType = mediaType;
@@ -297,24 +318,25 @@ class HttpHandler {
297
318
  let operationResultEncoder = this[core_1.kAssetCache].get(operationResultType, 'encode');
298
319
  if (!operationResultEncoder) {
299
320
  operationResultEncoder = operationResultType.generateCodec('encode', {
321
+ scope: this.adapter.document.scopes,
300
322
  ignoreWriteonlyFields: true,
301
- ignoreHiddenFields: true,
302
323
  });
303
324
  this[core_1.kAssetCache].set(operationResultType, 'encode', operationResultEncoder);
304
325
  }
305
326
  /** Validate response */
306
327
  if (operationResponse?.type) {
307
- if (!(body == null && statusCode === common_1.HttpStatusCode.NO_CONTENT)) {
328
+ if (!(body == null &&
329
+ statusCode === common_1.HttpStatusCode.NO_CONTENT)) {
308
330
  /** Generate encoder */
309
331
  const projection = responseArgs.projection || '*';
310
332
  const assetKey = (0, super_fast_md5_1.md5)(String(projection));
311
333
  let encode = this[core_1.kAssetCache].get(operationResponse, 'encode:' + assetKey);
312
334
  if (!encode) {
313
335
  encode = operationResponse.type.generateCodec('encode', {
336
+ scope: this.adapter.document.scopes,
314
337
  partial: operationResponse.partial,
315
338
  projection,
316
339
  ignoreWriteonlyFields: true,
317
- ignoreHiddenFields: true,
318
340
  onFail: issue => `Response body validation failed: ` + issue.message,
319
341
  });
320
342
  if (operationResponse) {
@@ -345,8 +367,11 @@ class HttpHandler {
345
367
  }
346
368
  if (body instanceof common_1.OperationResult &&
347
369
  operationResponse.type &&
348
- operationResponse.type !== document.node.getDataType(common_1.OperationResult)) {
349
- body.type = operationResponse.type.name ? operationResponse.type.name : '#embedded';
370
+ operationResponse.type !==
371
+ document.node.getDataType(common_1.OperationResult)) {
372
+ body.type = operationResponse.type.name
373
+ ? operationResponse.type.name
374
+ : '#embedded';
350
375
  }
351
376
  }
352
377
  }
@@ -436,7 +461,8 @@ class HttpHandler {
436
461
  const bodyObject = new common_1.OperationResult({
437
462
  errors: errors.map(x => {
438
463
  const o = x.toJSON();
439
- if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
464
+ if (!(process.env.NODE_ENV === 'dev' ||
465
+ process.env.NODE_ENV === 'development'))
440
466
  delete o.stack;
441
467
  return o; // i18n.deep(o);
442
468
  }),
@@ -483,9 +509,13 @@ class HttpHandler {
483
509
  _determineResponseArgs(context, body) {
484
510
  const { response, operation } = context;
485
511
  const hasBody = body != null;
486
- const statusCode = !hasBody && response.statusCode === common_1.HttpStatusCode.OK ? common_1.HttpStatusCode.NO_CONTENT : response.statusCode;
512
+ const statusCode = !hasBody && response.statusCode === common_1.HttpStatusCode.OK
513
+ ? common_1.HttpStatusCode.NO_CONTENT
514
+ : response.statusCode;
487
515
  /** Parse content-type header */
488
- const parsedContentType = hasBody && response.hasHeader('content-type') ? (0, content_type_1.parse)(response) : undefined;
516
+ const parsedContentType = hasBody && response.hasHeader('content-type')
517
+ ? (0, content_type_1.parse)(response)
518
+ : undefined;
489
519
  let contentType = parsedContentType?.type;
490
520
  /** Estimate content type if not defined */
491
521
  if (hasBody && !contentType) {
@@ -563,7 +593,8 @@ class HttpHandler {
563
593
  payload: body,
564
594
  });
565
595
  }
566
- if ((composition === 'Entity.Create' || composition === 'Entity.Update') &&
596
+ if ((composition === 'Entity.Create' ||
597
+ composition === 'Entity.Update') &&
567
598
  composition &&
568
599
  body.affected == null) {
569
600
  body.affected = 1;
@@ -592,7 +623,8 @@ class HttpHandler {
592
623
  break;
593
624
  }
594
625
  }
595
- if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type) {
626
+ if (responseArgs.contentType &&
627
+ responseArgs.contentType !== parsedContentType?.type) {
596
628
  response.setHeader('content-type', responseArgs.contentType);
597
629
  }
598
630
  if (responseArgs.contentType &&
@@ -611,7 +643,8 @@ class HttpHandler {
611
643
  wrappedErrors.push(new common_1.InternalServerError());
612
644
  // Sort errors from fatal to info
613
645
  wrappedErrors.sort((a, b) => {
614
- const i = common_1.IssueSeverity.Keys.indexOf(a.severity) - common_1.IssueSeverity.Keys.indexOf(b.severity);
646
+ const i = common_1.IssueSeverity.Keys.indexOf(a.severity) -
647
+ common_1.IssueSeverity.Keys.indexOf(b.severity);
615
648
  if (i === 0)
616
649
  return b.status - a.status;
617
650
  return i;
@@ -102,14 +102,20 @@ class MultipartReader extends events_1.EventEmitter {
102
102
  if (!field)
103
103
  throw new common_1.BadRequestError(`Unknown multipart field (${item.field})`);
104
104
  if (item.kind === 'field') {
105
- const decode = field.generateCodec('decode', { ignoreReadonlyFields: true, projection: '*' });
105
+ const decode = field.generateCodec('decode', {
106
+ ignoreReadonlyFields: true,
107
+ projection: '*',
108
+ });
106
109
  item.value = decode(item.value, {
107
- onFail: issue => `Multipart field (${item.field}) validation failed: ` + issue.message,
110
+ onFail: issue => `Multipart field (${item.field}) validation failed: ` +
111
+ issue.message,
108
112
  });
109
113
  }
110
114
  else if (item.kind === 'file') {
111
115
  if (field.contentType) {
112
- const arr = Array.isArray(field.contentType) ? field.contentType : [field.contentType];
116
+ const arr = Array.isArray(field.contentType)
117
+ ? field.contentType
118
+ : [field.contentType];
113
119
  if (!(item.mimeType && arr.find(ct => type_is_1.default.is(item.mimeType, [ct])))) {
114
120
  throw new common_1.BadRequestError(`Multipart field (${item.field}) do not accept this content type`);
115
121
  }
@@ -117,7 +123,9 @@ class MultipartReader extends events_1.EventEmitter {
117
123
  }
118
124
  }
119
125
  /** if all items received we check for required items */
120
- if (this._finished && this.mediaType && this.mediaType.multipartFields?.length > 0) {
126
+ if (this._finished &&
127
+ this.mediaType &&
128
+ this.mediaType.multipartFields?.length > 0) {
121
129
  const fieldsLeft = new Set(this.mediaType.multipartFields);
122
130
  for (const x of this._items) {
123
131
  const field = this.mediaType.findMultipartField(x.field);
@@ -129,7 +137,9 @@ class MultipartReader extends events_1.EventEmitter {
129
137
  if (!field.required)
130
138
  continue;
131
139
  try {
132
- (0, valgen_1.isNotNullish)(null, { onFail: () => `Multi part field "${String(field.fieldName)}" is required` });
140
+ (0, valgen_1.isNotNullish)(null, {
141
+ onFail: () => `Multi part field "${String(field.fieldName)}" is required`,
142
+ });
133
143
  }
134
144
  catch (e) {
135
145
  if (!issues) {
@@ -192,5 +202,6 @@ class MultipartReader extends events_1.EventEmitter {
192
202
  exports.MultipartReader = MultipartReader;
193
203
  function generateFileName() {
194
204
  const buf = Buffer.alloc(10);
195
- return new Date().toISOString().substring(0, 10).replace(/-/g, '') + (0, node_crypto_1.randomFillSync)(buf).toString('hex');
205
+ return (new Date().toISOString().substring(0, 10).replace(/-/g, '') +
206
+ (0, node_crypto_1.randomFillSync)(buf).toString('hex'));
196
207
  }
@@ -37,10 +37,14 @@ class NodeIncomingMessageHost extends stream_1.Duplex {
37
37
  this.body = Buffer.from(JSON.stringify(init.body), 'utf-8');
38
38
  }
39
39
  if (init.headers) {
40
- this.rawHeaders = Array.isArray(init.headers) ? init.headers : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.headers);
40
+ this.rawHeaders = Array.isArray(init.headers)
41
+ ? init.headers
42
+ : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.headers);
41
43
  }
42
44
  if (init.trailers) {
43
- this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.trailers);
45
+ this.rawTrailers = Array.isArray(init.trailers)
46
+ ? init.trailers
47
+ : (0, convert_to_raw_headers_js_1.convertToRawHeaders)(init.trailers);
44
48
  }
45
49
  this.ip = init.ip || '';
46
50
  this.ips = init.ips || (this.ip ? [this.ip] : []);
@@ -53,7 +57,9 @@ class NodeIncomingMessageHost extends stream_1.Duplex {
53
57
  }
54
58
  }
55
59
  get httpVersion() {
56
- return this.httpVersionMajor ? this.httpVersionMajor + '.' + this.httpVersionMinor : '';
60
+ return this.httpVersionMajor
61
+ ? this.httpVersionMajor + '.' + this.httpVersionMinor
62
+ : '';
57
63
  }
58
64
  get headers() {
59
65
  if (!this[exports.kHeaders])
@@ -27,7 +27,9 @@ class NodeOutgoingMessageHost extends stream_1.Duplex {
27
27
  this.sendDate = !!init?.sendDate;
28
28
  this.strictContentLength = !!init?.strictContentLength;
29
29
  if (init.headers)
30
- this.setHeaders(Array.isArray(init.headers) ? new Map([init.headers]) : init.headers);
30
+ this.setHeaders(Array.isArray(init.headers)
31
+ ? new Map([init.headers])
32
+ : init.headers);
31
33
  this.body = init.body;
32
34
  }
33
35
  }
@@ -67,7 +69,9 @@ class NodeOutgoingMessageHost extends stream_1.Duplex {
67
69
  }
68
70
  addTrailers(headers) {
69
71
  if (headers && typeof headers === 'object') {
70
- const entries = typeof headers.entries === 'function' ? headers.entries() : Object.entries(headers);
72
+ const entries = typeof headers.entries === 'function'
73
+ ? headers.entries()
74
+ : Object.entries(headers);
71
75
  let trailers = this[exports.kOutTrailers];
72
76
  if (trailers == null)
73
77
  this[exports.kOutTrailers] = trailers = { __proto__: null };
@@ -98,7 +102,9 @@ class NodeOutgoingMessageHost extends stream_1.Duplex {
98
102
  if (this.headersSent)
99
103
  throw new Error(`Cannot set headers after they are sent to the client`);
100
104
  if (headers && typeof headers === 'object' && !Array.isArray(headers)) {
101
- const entries = typeof headers.entries === 'function' ? headers.entries() : Object.entries(headers);
105
+ const entries = typeof headers.entries === 'function'
106
+ ? headers.entries()
107
+ : Object.entries(headers);
102
108
  for (const entry of entries) {
103
109
  this.setHeader(entry[0], entry[1]);
104
110
  }
@@ -17,7 +17,8 @@ var NodeIncomingMessage;
17
17
  * @param iterable
18
18
  */
19
19
  function from(iterable) {
20
- if (typeof iterable === 'object' && !((0, objects_1.isIterable)(iterable) || (0, objects_1.isAsyncIterable)(iterable))) {
20
+ if (typeof iterable === 'object' &&
21
+ !((0, objects_1.isIterable)(iterable) || (0, objects_1.isAsyncIterable)(iterable))) {
21
22
  return new node_incoming_message_host_js_1.NodeIncomingMessageHost(iterable);
22
23
  }
23
24
  const msg = new node_incoming_message_host_js_1.NodeIncomingMessageHost();
@@ -6,7 +6,10 @@ exports.isNodeOutgoingMessage = isNodeOutgoingMessage;
6
6
  exports.isHttpOutgoing = isHttpOutgoing;
7
7
  const common_1 = require("@opra/common");
8
8
  function isNodeIncomingMessage(v) {
9
- return v && typeof v.method === 'string' && Array.isArray(v.rawHeaders) && (0, common_1.isReadable)(v);
9
+ return (v &&
10
+ typeof v.method === 'string' &&
11
+ Array.isArray(v.rawHeaders) &&
12
+ (0, common_1.isReadable)(v));
10
13
  }
11
14
  function isHttpIncoming(v) {
12
15
  return (isNodeIncomingMessage(v) &&
@@ -18,5 +21,7 @@ function isNodeOutgoingMessage(v) {
18
21
  return v && typeof v.getHeaders === 'function' && (0, common_1.isStream)(v);
19
22
  }
20
23
  function isHttpOutgoing(v) {
21
- return isNodeOutgoingMessage(v) && typeof v.clearCookie === 'function' && typeof v.cookie === 'function';
24
+ return (isNodeOutgoingMessage(v) &&
25
+ typeof v.clearCookie === 'function' &&
26
+ typeof v.cookie === 'function');
22
27
  }
@@ -62,13 +62,16 @@ class BodyReader extends events_1.EventEmitter {
62
62
  * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
63
63
  */
64
64
  const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
65
- if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength))) {
65
+ if (this.req.headers['transfer-encoding'] === undefined &&
66
+ !(contentLength && !isNaN(contentLength))) {
66
67
  return this.onEnd();
67
68
  }
68
69
  // check the length and limit options.
69
70
  // note: we intentionally leave the stream paused,
70
71
  // so users should handle the stream themselves.
71
- if (this.limit != null && contentLength != null && contentLength > this.limit) {
72
+ if (this.limit != null &&
73
+ contentLength != null &&
74
+ contentLength > this.limit) {
72
75
  return this.onEnd(new common_1.OpraHttpError({
73
76
  message: 'Content Too Large',
74
77
  code: 'HTTP.CONTENT_TOO_LARGE',
@@ -171,7 +174,9 @@ class BodyReader extends events_1.EventEmitter {
171
174
  }
172
175
  static encoderPipeline(req) {
173
176
  const contentEncoding = req.headers['content-encoding'] || 'identity';
174
- const contentEncodings = (Array.isArray(contentEncoding) ? contentEncoding : contentEncoding.split(/\s*,\s*/))
177
+ const contentEncodings = (Array.isArray(contentEncoding)
178
+ ? contentEncoding
179
+ : contentEncoding.split(/\s*,\s*/))
175
180
  .map(s => s.toLowerCase())
176
181
  .reverse();
177
182
  return contentEncodings.reduce((prev, encoding) => {
@@ -13,7 +13,9 @@ function convertToRawHeaders(src) {
13
13
  return a;
14
14
  }
15
15
  if (flag === match_known_fields_js_1.COMMA_DELIMITED_FIELD || flag === match_known_fields_js_1.SEMICOLON_DELIMITED_FIELD) {
16
- v = Array.isArray(v) ? v.join(flag === match_known_fields_js_1.COMMA_DELIMITED_FIELD ? ', ' : '; ') : String(v);
16
+ v = Array.isArray(v)
17
+ ? v.join(flag === match_known_fields_js_1.COMMA_DELIMITED_FIELD ? ', ' : '; ')
18
+ : String(v);
17
19
  }
18
20
  else
19
21
  v = Array.isArray(v) ? String(v[0]) : String(v);
@@ -1,6 +1,6 @@
1
1
  import * as nodePath from 'node:path';
2
- import { HttpApi, NotFoundError } from '@opra/common';
3
- import { Router } from 'express';
2
+ import { HttpApi, NotFoundError, } from '@opra/common';
3
+ import { Router, } from 'express';
4
4
  import { HttpAdapter } from './http-adapter.js';
5
5
  import { HttpContext } from './http-context.js';
6
6
  import { HttpIncoming } from './interfaces/http-incoming.interface.js';
@@ -44,7 +44,9 @@ export class HttpContext extends ExecutionContext {
44
44
  return this._multipartReader;
45
45
  const { mediaType } = this;
46
46
  if (mediaType?.contentType) {
47
- const arr = Array.isArray(mediaType.contentType) ? mediaType.contentType : [mediaType.contentType];
47
+ const arr = Array.isArray(mediaType.contentType)
48
+ ? mediaType.contentType
49
+ : [mediaType.contentType];
48
50
  const contentType = arr.find(ct => typeIs.is(ct, ['multipart']));
49
51
  if (!contentType)
50
52
  throw new NotAcceptableError('This endpoint does not accept multipart requests');
@@ -72,10 +74,13 @@ export class HttpContext extends ExecutionContext {
72
74
  this._body = [...parts];
73
75
  return this._body;
74
76
  }
75
- this._body = await this.request.readBody({ limit: operation?.requestBody?.maxContentSize });
77
+ this._body = await this.request.readBody({
78
+ limit: operation?.requestBody?.maxContentSize,
79
+ });
76
80
  if (this._body != null) {
77
81
  // Convert Buffer to string if media is text
78
- if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text'])) {
82
+ if (Buffer.isBuffer(this._body) &&
83
+ request.is(['json', 'xml', 'txt', 'text'])) {
79
84
  this._body = this._body.toString('utf-8');
80
85
  }
81
86
  // Transform text to Object if media is JSON
@@ -6,7 +6,7 @@ import { parse as parseContentType } from 'content-type';
6
6
  import { splitString } from 'fast-tokenizer';
7
7
  import { md5 } from 'super-fast-md5';
8
8
  import { asMutable } from 'ts-gems';
9
- import { toArray, ValidationError, vg } from 'valgen';
9
+ import { toArray, ValidationError, vg, } from 'valgen';
10
10
  import { wrapException } from './utils/wrap-exception.js';
11
11
  /**
12
12
  * @class HttpHandler
@@ -123,12 +123,17 @@ export class HttpHandler {
123
123
  const getDecoder = (prm) => {
124
124
  let decode = this[kAssetCache].get(prm, 'decode');
125
125
  if (!decode) {
126
- decode = prm.type?.generateCodec('decode', { ignoreReadonlyFields: true }) || vg.isAny();
126
+ decode =
127
+ prm.type?.generateCodec('decode', { ignoreReadonlyFields: true }) ||
128
+ vg.isAny();
127
129
  this[kAssetCache].set(prm, 'decode', decode);
128
130
  }
129
131
  return decode;
130
132
  };
131
- const paramsLeft = new Set([...operation.parameters, ...operation.owner.parameters]);
133
+ const paramsLeft = new Set([
134
+ ...operation.parameters,
135
+ ...operation.owner.parameters,
136
+ ]);
132
137
  /** parse cookie parameters */
133
138
  if (request.cookies) {
134
139
  for (key of Object.keys(request.cookies)) {
@@ -142,7 +147,11 @@ export class HttpHandler {
142
147
  if (cntPrm)
143
148
  paramsLeft.delete(cntPrm);
144
149
  const decode = getDecoder(prm);
145
- const v = decode(request.cookies[key], { coerce: true, label: key, onFail });
150
+ const v = decode(request.cookies[key], {
151
+ coerce: true,
152
+ label: key,
153
+ onFail,
154
+ });
146
155
  const prmName = typeof prm.name === 'string' ? prm.name : key;
147
156
  if (v !== undefined)
148
157
  context.cookies[prmName] = v;
@@ -161,7 +170,11 @@ export class HttpHandler {
161
170
  if (cntPrm)
162
171
  paramsLeft.delete(cntPrm);
163
172
  const decode = getDecoder(prm);
164
- const v = decode(request.headers[key], { coerce: true, label: key, onFail });
173
+ const v = decode(request.headers[key], {
174
+ coerce: true,
175
+ label: key,
176
+ onFail,
177
+ });
165
178
  const prmName = typeof prm.name === 'string' ? prm.name : key;
166
179
  if (v !== undefined)
167
180
  context.headers[prmName] = v;
@@ -180,7 +193,11 @@ export class HttpHandler {
180
193
  if (cntPrm)
181
194
  paramsLeft.delete(cntPrm);
182
195
  const decode = getDecoder(prm);
183
- const v = decode(request.params[key], { coerce: true, label: key, onFail });
196
+ const v = decode(request.params[key], {
197
+ coerce: true,
198
+ label: key,
199
+ onFail,
200
+ });
184
201
  if (v !== undefined)
185
202
  context.pathParams[key] = v;
186
203
  }
@@ -202,7 +219,9 @@ export class HttpHandler {
202
219
  let values = searchParams?.getAll(key);
203
220
  const prmName = typeof prm.name === 'string' ? prm.name : key;
204
221
  if (values?.length && prm.isArray) {
205
- values = values.map(v => splitString(v, { delimiters: prm.arraySeparator, quotes: true })).flat();
222
+ values = values
223
+ .map(v => splitString(v, { delimiters: prm.arraySeparator, quotes: true }))
224
+ .flat();
206
225
  values = values.map(v => decode(v, { coerce: true, label: key, onFail }));
207
226
  if (values.length)
208
227
  context.queryParams[prmName] = values;
@@ -251,7 +270,9 @@ export class HttpHandler {
251
270
  typeIs.is(contentType, Array.isArray(mc.contentType) ? mc.contentType : [mc.contentType]));
252
271
  }
253
272
  if (!mediaType) {
254
- const contentTypes = operation.requestBody.content.map(mc => mc.contentType).flat();
273
+ const contentTypes = operation.requestBody.content
274
+ .map(mc => mc.contentType)
275
+ .flat();
255
276
  throw new BadRequestError(`Request body should be one of required content types (${contentTypes.join(', ')})`);
256
277
  }
257
278
  asMutable(context).mediaType = mediaType;
@@ -293,24 +314,25 @@ export class HttpHandler {
293
314
  let operationResultEncoder = this[kAssetCache].get(operationResultType, 'encode');
294
315
  if (!operationResultEncoder) {
295
316
  operationResultEncoder = operationResultType.generateCodec('encode', {
317
+ scope: this.adapter.document.scopes,
296
318
  ignoreWriteonlyFields: true,
297
- ignoreHiddenFields: true,
298
319
  });
299
320
  this[kAssetCache].set(operationResultType, 'encode', operationResultEncoder);
300
321
  }
301
322
  /** Validate response */
302
323
  if (operationResponse?.type) {
303
- if (!(body == null && statusCode === HttpStatusCode.NO_CONTENT)) {
324
+ if (!(body == null &&
325
+ statusCode === HttpStatusCode.NO_CONTENT)) {
304
326
  /** Generate encoder */
305
327
  const projection = responseArgs.projection || '*';
306
328
  const assetKey = md5(String(projection));
307
329
  let encode = this[kAssetCache].get(operationResponse, 'encode:' + assetKey);
308
330
  if (!encode) {
309
331
  encode = operationResponse.type.generateCodec('encode', {
332
+ scope: this.adapter.document.scopes,
310
333
  partial: operationResponse.partial,
311
334
  projection,
312
335
  ignoreWriteonlyFields: true,
313
- ignoreHiddenFields: true,
314
336
  onFail: issue => `Response body validation failed: ` + issue.message,
315
337
  });
316
338
  if (operationResponse) {
@@ -341,8 +363,11 @@ export class HttpHandler {
341
363
  }
342
364
  if (body instanceof OperationResult &&
343
365
  operationResponse.type &&
344
- operationResponse.type !== document.node.getDataType(OperationResult)) {
345
- body.type = operationResponse.type.name ? operationResponse.type.name : '#embedded';
366
+ operationResponse.type !==
367
+ document.node.getDataType(OperationResult)) {
368
+ body.type = operationResponse.type.name
369
+ ? operationResponse.type.name
370
+ : '#embedded';
346
371
  }
347
372
  }
348
373
  }
@@ -432,7 +457,8 @@ export class HttpHandler {
432
457
  const bodyObject = new OperationResult({
433
458
  errors: errors.map(x => {
434
459
  const o = x.toJSON();
435
- if (!(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'))
460
+ if (!(process.env.NODE_ENV === 'dev' ||
461
+ process.env.NODE_ENV === 'development'))
436
462
  delete o.stack;
437
463
  return o; // i18n.deep(o);
438
464
  }),
@@ -479,9 +505,13 @@ export class HttpHandler {
479
505
  _determineResponseArgs(context, body) {
480
506
  const { response, operation } = context;
481
507
  const hasBody = body != null;
482
- const statusCode = !hasBody && response.statusCode === HttpStatusCode.OK ? HttpStatusCode.NO_CONTENT : response.statusCode;
508
+ const statusCode = !hasBody && response.statusCode === HttpStatusCode.OK
509
+ ? HttpStatusCode.NO_CONTENT
510
+ : response.statusCode;
483
511
  /** Parse content-type header */
484
- const parsedContentType = hasBody && response.hasHeader('content-type') ? parseContentType(response) : undefined;
512
+ const parsedContentType = hasBody && response.hasHeader('content-type')
513
+ ? parseContentType(response)
514
+ : undefined;
485
515
  let contentType = parsedContentType?.type;
486
516
  /** Estimate content type if not defined */
487
517
  if (hasBody && !contentType) {
@@ -559,7 +589,8 @@ export class HttpHandler {
559
589
  payload: body,
560
590
  });
561
591
  }
562
- if ((composition === 'Entity.Create' || composition === 'Entity.Update') &&
592
+ if ((composition === 'Entity.Create' ||
593
+ composition === 'Entity.Update') &&
563
594
  composition &&
564
595
  body.affected == null) {
565
596
  body.affected = 1;
@@ -588,7 +619,8 @@ export class HttpHandler {
588
619
  break;
589
620
  }
590
621
  }
591
- if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type) {
622
+ if (responseArgs.contentType &&
623
+ responseArgs.contentType !== parsedContentType?.type) {
592
624
  response.setHeader('content-type', responseArgs.contentType);
593
625
  }
594
626
  if (responseArgs.contentType &&
@@ -607,7 +639,8 @@ export class HttpHandler {
607
639
  wrappedErrors.push(new InternalServerError());
608
640
  // Sort errors from fatal to info
609
641
  wrappedErrors.sort((a, b) => {
610
- const i = IssueSeverity.Keys.indexOf(a.severity) - IssueSeverity.Keys.indexOf(b.severity);
642
+ const i = IssueSeverity.Keys.indexOf(a.severity) -
643
+ IssueSeverity.Keys.indexOf(b.severity);
611
644
  if (i === 0)
612
645
  return b.status - a.status;
613
646
  return i;
@@ -98,14 +98,20 @@ export class MultipartReader extends EventEmitter {
98
98
  if (!field)
99
99
  throw new BadRequestError(`Unknown multipart field (${item.field})`);
100
100
  if (item.kind === 'field') {
101
- const decode = field.generateCodec('decode', { ignoreReadonlyFields: true, projection: '*' });
101
+ const decode = field.generateCodec('decode', {
102
+ ignoreReadonlyFields: true,
103
+ projection: '*',
104
+ });
102
105
  item.value = decode(item.value, {
103
- onFail: issue => `Multipart field (${item.field}) validation failed: ` + issue.message,
106
+ onFail: issue => `Multipart field (${item.field}) validation failed: ` +
107
+ issue.message,
104
108
  });
105
109
  }
106
110
  else if (item.kind === 'file') {
107
111
  if (field.contentType) {
108
- const arr = Array.isArray(field.contentType) ? field.contentType : [field.contentType];
112
+ const arr = Array.isArray(field.contentType)
113
+ ? field.contentType
114
+ : [field.contentType];
109
115
  if (!(item.mimeType && arr.find(ct => typeIs.is(item.mimeType, [ct])))) {
110
116
  throw new BadRequestError(`Multipart field (${item.field}) do not accept this content type`);
111
117
  }
@@ -113,7 +119,9 @@ export class MultipartReader extends EventEmitter {
113
119
  }
114
120
  }
115
121
  /** if all items received we check for required items */
116
- if (this._finished && this.mediaType && this.mediaType.multipartFields?.length > 0) {
122
+ if (this._finished &&
123
+ this.mediaType &&
124
+ this.mediaType.multipartFields?.length > 0) {
117
125
  const fieldsLeft = new Set(this.mediaType.multipartFields);
118
126
  for (const x of this._items) {
119
127
  const field = this.mediaType.findMultipartField(x.field);
@@ -125,7 +133,9 @@ export class MultipartReader extends EventEmitter {
125
133
  if (!field.required)
126
134
  continue;
127
135
  try {
128
- isNotNullish(null, { onFail: () => `Multi part field "${String(field.fieldName)}" is required` });
136
+ isNotNullish(null, {
137
+ onFail: () => `Multi part field "${String(field.fieldName)}" is required`,
138
+ });
129
139
  }
130
140
  catch (e) {
131
141
  if (!issues) {
@@ -187,5 +197,6 @@ export class MultipartReader extends EventEmitter {
187
197
  }
188
198
  function generateFileName() {
189
199
  const buf = Buffer.alloc(10);
190
- return new Date().toISOString().substring(0, 10).replace(/-/g, '') + randomFillSync(buf).toString('hex');
200
+ return (new Date().toISOString().substring(0, 10).replace(/-/g, '') +
201
+ randomFillSync(buf).toString('hex'));
191
202
  }
@@ -1,6 +1,6 @@
1
1
  import { isAsyncIterable, isIterable } from '@jsopen/objects';
2
2
  import { Duplex, Readable } from 'stream';
3
- import { convertToHeaders, convertToHeadersDistinct } from '../utils/convert-to-headers.js';
3
+ import { convertToHeaders, convertToHeadersDistinct, } from '../utils/convert-to-headers.js';
4
4
  import { convertToRawHeaders } from '../utils/convert-to-raw-headers.js';
5
5
  export const CRLF = Buffer.from('\r\n');
6
6
  export const kHeaders = Symbol.for('kHeaders');
@@ -34,10 +34,14 @@ export class NodeIncomingMessageHost extends Duplex {
34
34
  this.body = Buffer.from(JSON.stringify(init.body), 'utf-8');
35
35
  }
36
36
  if (init.headers) {
37
- this.rawHeaders = Array.isArray(init.headers) ? init.headers : convertToRawHeaders(init.headers);
37
+ this.rawHeaders = Array.isArray(init.headers)
38
+ ? init.headers
39
+ : convertToRawHeaders(init.headers);
38
40
  }
39
41
  if (init.trailers) {
40
- this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : convertToRawHeaders(init.trailers);
42
+ this.rawTrailers = Array.isArray(init.trailers)
43
+ ? init.trailers
44
+ : convertToRawHeaders(init.trailers);
41
45
  }
42
46
  this.ip = init.ip || '';
43
47
  this.ips = init.ips || (this.ip ? [this.ip] : []);
@@ -50,7 +54,9 @@ export class NodeIncomingMessageHost extends Duplex {
50
54
  }
51
55
  }
52
56
  get httpVersion() {
53
- return this.httpVersionMajor ? this.httpVersionMajor + '.' + this.httpVersionMinor : '';
57
+ return this.httpVersionMajor
58
+ ? this.httpVersionMajor + '.' + this.httpVersionMinor
59
+ : '';
54
60
  }
55
61
  get headers() {
56
62
  if (!this[kHeaders])
@@ -3,7 +3,7 @@
3
3
  https://github.com/nodejs/
4
4
  */
5
5
  import { Duplex } from 'stream';
6
- import { validateHeaderName, validateHeaderValue, validateString } from '../utils/common.js';
6
+ import { validateHeaderName, validateHeaderValue, validateString, } from '../utils/common.js';
7
7
  export const kOutHeaders = Symbol.for('kOutHeaders');
8
8
  export const kOutTrailers = Symbol.for('kOutTrailers');
9
9
  // noinspection JSUnusedLocalSymbols
@@ -24,7 +24,9 @@ export class NodeOutgoingMessageHost extends Duplex {
24
24
  this.sendDate = !!init?.sendDate;
25
25
  this.strictContentLength = !!init?.strictContentLength;
26
26
  if (init.headers)
27
- this.setHeaders(Array.isArray(init.headers) ? new Map([init.headers]) : init.headers);
27
+ this.setHeaders(Array.isArray(init.headers)
28
+ ? new Map([init.headers])
29
+ : init.headers);
28
30
  this.body = init.body;
29
31
  }
30
32
  }
@@ -64,7 +66,9 @@ export class NodeOutgoingMessageHost extends Duplex {
64
66
  }
65
67
  addTrailers(headers) {
66
68
  if (headers && typeof headers === 'object') {
67
- const entries = typeof headers.entries === 'function' ? headers.entries() : Object.entries(headers);
69
+ const entries = typeof headers.entries === 'function'
70
+ ? headers.entries()
71
+ : Object.entries(headers);
68
72
  let trailers = this[kOutTrailers];
69
73
  if (trailers == null)
70
74
  this[kOutTrailers] = trailers = { __proto__: null };
@@ -95,7 +99,9 @@ export class NodeOutgoingMessageHost extends Duplex {
95
99
  if (this.headersSent)
96
100
  throw new Error(`Cannot set headers after they are sent to the client`);
97
101
  if (headers && typeof headers === 'object' && !Array.isArray(headers)) {
98
- const entries = typeof headers.entries === 'function' ? headers.entries() : Object.entries(headers);
102
+ const entries = typeof headers.entries === 'function'
103
+ ? headers.entries()
104
+ : Object.entries(headers);
99
105
  for (const entry of entries) {
100
106
  this.setHeader(entry[0], entry[1]);
101
107
  }
@@ -1,7 +1,7 @@
1
1
  import { HTTPParser } from '@browsery/http-parser';
2
2
  import { isAsyncIterable, isIterable } from '@jsopen/objects';
3
3
  import { Readable } from 'stream';
4
- import { CRLF, kHttpParser, NodeIncomingMessageHost } from '../impl/node-incoming-message.host.js';
4
+ import { CRLF, kHttpParser, NodeIncomingMessageHost, } from '../impl/node-incoming-message.host.js';
5
5
  import { concatReadable } from '../utils/concat-readable.js';
6
6
  /**
7
7
  *
@@ -14,7 +14,8 @@ export var NodeIncomingMessage;
14
14
  * @param iterable
15
15
  */
16
16
  function from(iterable) {
17
- if (typeof iterable === 'object' && !(isIterable(iterable) || isAsyncIterable(iterable))) {
17
+ if (typeof iterable === 'object' &&
18
+ !(isIterable(iterable) || isAsyncIterable(iterable))) {
18
19
  return new NodeIncomingMessageHost(iterable);
19
20
  }
20
21
  const msg = new NodeIncomingMessageHost();
@@ -1,6 +1,9 @@
1
1
  import { isReadable, isStream } from '@opra/common';
2
2
  export function isNodeIncomingMessage(v) {
3
- return v && typeof v.method === 'string' && Array.isArray(v.rawHeaders) && isReadable(v);
3
+ return (v &&
4
+ typeof v.method === 'string' &&
5
+ Array.isArray(v.rawHeaders) &&
6
+ isReadable(v));
4
7
  }
5
8
  export function isHttpIncoming(v) {
6
9
  return (isNodeIncomingMessage(v) &&
@@ -12,5 +15,7 @@ export function isNodeOutgoingMessage(v) {
12
15
  return v && typeof v.getHeaders === 'function' && isStream(v);
13
16
  }
14
17
  export function isHttpOutgoing(v) {
15
- return isNodeOutgoingMessage(v) && typeof v.clearCookie === 'function' && typeof v.cookie === 'function';
18
+ return (isNodeOutgoingMessage(v) &&
19
+ typeof v.clearCookie === 'function' &&
20
+ typeof v.cookie === 'function');
16
21
  }
@@ -1,5 +1,5 @@
1
1
  import typeIs from '@browsery/type-is';
2
- import { BadRequestError, InternalServerError, OpraHttpError } from '@opra/common';
2
+ import { BadRequestError, InternalServerError, OpraHttpError, } from '@opra/common';
3
3
  import { Base64Decode } from 'base64-stream';
4
4
  import byteParser from 'bytes';
5
5
  import { parse as parseContentType } from 'content-type';
@@ -58,13 +58,16 @@ export class BodyReader extends EventEmitter {
58
58
  * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
59
59
  */
60
60
  const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
61
- if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength))) {
61
+ if (this.req.headers['transfer-encoding'] === undefined &&
62
+ !(contentLength && !isNaN(contentLength))) {
62
63
  return this.onEnd();
63
64
  }
64
65
  // check the length and limit options.
65
66
  // note: we intentionally leave the stream paused,
66
67
  // so users should handle the stream themselves.
67
- if (this.limit != null && contentLength != null && contentLength > this.limit) {
68
+ if (this.limit != null &&
69
+ contentLength != null &&
70
+ contentLength > this.limit) {
68
71
  return this.onEnd(new OpraHttpError({
69
72
  message: 'Content Too Large',
70
73
  code: 'HTTP.CONTENT_TOO_LARGE',
@@ -167,7 +170,9 @@ export class BodyReader extends EventEmitter {
167
170
  }
168
171
  static encoderPipeline(req) {
169
172
  const contentEncoding = req.headers['content-encoding'] || 'identity';
170
- const contentEncodings = (Array.isArray(contentEncoding) ? contentEncoding : contentEncoding.split(/\s*,\s*/))
173
+ const contentEncodings = (Array.isArray(contentEncoding)
174
+ ? contentEncoding
175
+ : contentEncoding.split(/\s*,\s*/))
171
176
  .map(s => s.toLowerCase())
172
177
  .reverse();
173
178
  return contentEncodings.reduce((prev, encoding) => {
@@ -10,7 +10,9 @@ export function convertToRawHeaders(src) {
10
10
  return a;
11
11
  }
12
12
  if (flag === COMMA_DELIMITED_FIELD || flag === SEMICOLON_DELIMITED_FIELD) {
13
- v = Array.isArray(v) ? v.join(flag === COMMA_DELIMITED_FIELD ? ', ' : '; ') : String(v);
13
+ v = Array.isArray(v)
14
+ ? v.join(flag === COMMA_DELIMITED_FIELD ? ', ' : '; ')
15
+ : String(v);
14
16
  }
15
17
  else
16
18
  v = Array.isArray(v) ? String(v[0]) : String(v);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/http",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Opra Http Server Adapter",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -9,8 +9,8 @@
9
9
  "@browsery/http-parser": "^0.5.9-r1",
10
10
  "@browsery/type-is": "^1.6.18-r5",
11
11
  "@jsopen/objects": "^1.5.0",
12
- "@opra/common": "^1.4.3",
13
- "@opra/core": "^1.4.3",
12
+ "@opra/common": "^1.5.0",
13
+ "@opra/core": "^1.5.0",
14
14
  "accepts": "^1.3.8",
15
15
  "base64-stream": "^1.0.0",
16
16
  "busboy": "^1.6.0",