@opra/core 1.0.0-alpha.7 → 1.0.0-alpha.9

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 (34) hide show
  1. package/cjs/augmentation/18n.augmentation.js +1 -1
  2. package/cjs/http/express-adapter.js +6 -12
  3. package/cjs/http/http-context.js +5 -3
  4. package/cjs/http/impl/http-handler.js +53 -39
  5. package/cjs/http/impl/http-incoming.host.js +3 -3
  6. package/cjs/http/impl/http-outgoing.host.js +2 -2
  7. package/cjs/http/impl/multipart-reader.js +4 -10
  8. package/cjs/http/impl/node-incoming-message.host.js +5 -3
  9. package/cjs/http/interfaces/node-incoming-message.interface.js +3 -2
  10. package/cjs/http/utils/body-reader.js +6 -4
  11. package/cjs/http/utils/common.js +2 -1
  12. package/cjs/index.js +3 -3
  13. package/cjs/platform-adapter.js +1 -1
  14. package/esm/augmentation/18n.augmentation.js +1 -1
  15. package/esm/http/express-adapter.js +6 -12
  16. package/esm/http/http-context.js +5 -3
  17. package/esm/http/impl/http-handler.js +53 -39
  18. package/esm/http/impl/http-incoming.host.js +3 -3
  19. package/esm/http/impl/http-outgoing.host.js +2 -2
  20. package/esm/http/impl/multipart-reader.js +4 -10
  21. package/esm/http/impl/node-incoming-message.host.js +5 -3
  22. package/esm/http/interfaces/node-incoming-message.interface.js +3 -2
  23. package/esm/http/utils/body-reader.js +6 -4
  24. package/esm/http/utils/common.js +2 -1
  25. package/esm/index.js +3 -3
  26. package/esm/platform-adapter.js +1 -1
  27. package/package.json +10 -4
  28. package/types/augmentation/18n.augmentation.d.ts +1 -1
  29. package/types/execution-context.d.ts +1 -1
  30. package/types/http/express-adapter.d.ts +1 -1
  31. package/types/http/impl/node-incoming-message.host.d.ts +1 -1
  32. package/types/http/utils/body-reader.d.ts +1 -1
  33. package/types/index.d.ts +3 -3
  34. package/types/platform-adapter.d.ts +1 -1
@@ -1,6 +1,6 @@
1
- import { vg } from 'valgen';
2
1
  import typeIs from '@browsery/type-is';
3
2
  import { BadRequestError, InternalServerError, NotAcceptableError, } from '@opra/common';
3
+ import { vg } from 'valgen';
4
4
  import { kAssetCache } from '../constants.js';
5
5
  import { ExecutionContext } from '../execution-context.js';
6
6
  import { MultipartReader } from './impl/multipart-reader.js';
@@ -74,10 +74,11 @@ export class HttpContext extends ExecutionContext {
74
74
  }
75
75
  /** Check required fields */
76
76
  for (const field of multipartFields) {
77
- if (field.required && !fieldsFound.get(field))
77
+ if (field.required && !fieldsFound.get(field)) {
78
78
  throw new BadRequestError({
79
79
  message: `Multipart field (${field.fieldName}) is required`,
80
80
  });
81
+ }
81
82
  }
82
83
  }
83
84
  return this._body;
@@ -85,8 +86,9 @@ export class HttpContext extends ExecutionContext {
85
86
  this._body = await this.request.readBody({ limit: operation.requestBody?.maxContentSize });
86
87
  if (this._body != null) {
87
88
  // Convert Buffer to string if media is text
88
- if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text']))
89
+ if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text'])) {
89
90
  this._body = this._body.toString('utf-8');
91
+ }
90
92
  // Transform text to Object if media is JSON
91
93
  if (typeof this._body === 'string' && request.is(['json']))
92
94
  this._body = JSON.parse(this._body);
@@ -1,10 +1,10 @@
1
+ import * as process from 'node:process';
2
+ import typeIs from '@browsery/type-is';
3
+ import { BadRequestError, HttpHeaderCodes, HttpStatusCode, InternalServerError, isBlob, isReadableStream, IssueSeverity, MethodNotAllowedError, MimeTypes, OperationResult, OpraException, OpraSchema, translate, } from '@opra/common';
1
4
  import { parse as parseContentType } from 'content-type';
2
5
  import { splitString } from 'fast-tokenizer';
3
- import * as process from 'node:process';
4
6
  import { asMutable } from 'ts-gems';
5
7
  import { toArray, ValidationError, vg } from 'valgen';
6
- import typeIs from '@browsery/type-is';
7
- import { BadRequestError, HttpHeaderCodes, HttpStatusCode, InternalServerError, isBlob, isReadableStream, IssueSeverity, MethodNotAllowedError, MimeTypes, OperationResult, OpraException, OpraSchema, translate, } from '@opra/common';
8
8
  import { kAssetCache } from '../../constants.js';
9
9
  import { wrapException } from '../utils/wrap-exception.js';
10
10
  /**
@@ -60,7 +60,8 @@ export class HttpHandler {
60
60
  else
61
61
  await this._executeRequest(context);
62
62
  }
63
- catch (e) {
63
+ catch (error) {
64
+ let e = error;
64
65
  if (e instanceof ValidationError) {
65
66
  e = new InternalServerError({
66
67
  message: translate('error:RESPONSE_VALIDATION,', 'Response validation failed'),
@@ -108,10 +109,10 @@ export class HttpHandler {
108
109
  */
109
110
  async _parseParameters(context) {
110
111
  const { operation, request } = context;
111
- let prmName = '';
112
+ let key = '';
112
113
  try {
113
114
  const onFail = (issue) => {
114
- issue.location = prmName;
115
+ issue.location = key;
115
116
  return issue;
116
117
  };
117
118
  /** prepare decoders */
@@ -126,9 +127,9 @@ export class HttpHandler {
126
127
  const paramsLeft = new Set([...operation.parameters, ...operation.owner.parameters]);
127
128
  /** parse cookie parameters */
128
129
  if (request.cookies) {
129
- for (prmName of Object.keys(request.cookies)) {
130
- const oprPrm = operation.findParameter(prmName, 'cookie');
131
- const cntPrm = operation.owner.findParameter(prmName, 'cookie');
130
+ for (key of Object.keys(request.cookies)) {
131
+ const oprPrm = operation.findParameter(key, 'cookie');
132
+ const cntPrm = operation.owner.findParameter(key, 'cookie');
132
133
  const prm = oprPrm || cntPrm;
133
134
  if (!prm)
134
135
  continue;
@@ -137,16 +138,17 @@ export class HttpHandler {
137
138
  if (cntPrm)
138
139
  paramsLeft.delete(cntPrm);
139
140
  const decode = getDecoder(prm);
140
- const v = decode(request.cookies[prmName], { coerce: true, label: prmName, onFail });
141
+ const v = decode(request.cookies[key], { coerce: true, label: key, onFail });
142
+ const prmName = typeof prm.name === 'string' ? prm.name : key;
141
143
  if (v !== undefined)
142
144
  context.cookies[prmName] = v;
143
145
  }
144
146
  }
145
147
  /** parse headers */
146
148
  if (request.headers) {
147
- for (prmName of Object.keys(request.headers)) {
148
- const oprPrm = operation.findParameter(prmName, 'header');
149
- const cntPrm = operation.owner.findParameter(prmName, 'header');
149
+ for (key of Object.keys(request.headers)) {
150
+ const oprPrm = operation.findParameter(key, 'header');
151
+ const cntPrm = operation.owner.findParameter(key, 'header');
150
152
  const prm = oprPrm || cntPrm;
151
153
  if (!prm)
152
154
  continue;
@@ -155,16 +157,17 @@ export class HttpHandler {
155
157
  if (cntPrm)
156
158
  paramsLeft.delete(cntPrm);
157
159
  const decode = getDecoder(prm);
158
- const v = decode(request.headers[prmName], { coerce: true, label: prmName, onFail });
160
+ const v = decode(request.headers[key], { coerce: true, label: key, onFail });
161
+ const prmName = typeof prm.name === 'string' ? prm.name : key;
159
162
  if (v !== undefined)
160
163
  context.headers[prmName] = v;
161
164
  }
162
165
  }
163
166
  /** parse path parameters */
164
167
  if (request.params) {
165
- for (prmName of Object.keys(request.params)) {
166
- const oprPrm = operation.findParameter(prmName, 'path');
167
- const cntPrm = operation.owner.findParameter(prmName, 'path');
168
+ for (key of Object.keys(request.params)) {
169
+ const oprPrm = operation.findParameter(key, 'path');
170
+ const cntPrm = operation.owner.findParameter(key, 'path');
168
171
  const prm = oprPrm || cntPrm;
169
172
  if (!prm)
170
173
  continue;
@@ -173,17 +176,17 @@ export class HttpHandler {
173
176
  if (cntPrm)
174
177
  paramsLeft.delete(cntPrm);
175
178
  const decode = getDecoder(prm);
176
- const v = decode(request.params[prmName], { coerce: true, label: prmName, onFail });
179
+ const v = decode(request.params[key], { coerce: true, label: key, onFail });
177
180
  if (v !== undefined)
178
- context.pathParams[prmName] = v;
181
+ context.pathParams[key] = v;
179
182
  }
180
183
  }
181
184
  /** parse query parameters */
182
185
  const url = new URL(request.originalUrl || request.url || '/', 'http://tempuri.org');
183
186
  const { searchParams } = url;
184
- for (prmName of searchParams.keys()) {
185
- const oprPrm = operation.findParameter(prmName, 'query');
186
- const cntPrm = operation.owner.findParameter(prmName, 'query');
187
+ for (key of searchParams.keys()) {
188
+ const oprPrm = operation.findParameter(key, 'query');
189
+ const cntPrm = operation.owner.findParameter(key, 'query');
187
190
  const prm = oprPrm || cntPrm;
188
191
  if (!prm)
189
192
  continue;
@@ -192,15 +195,16 @@ export class HttpHandler {
192
195
  if (cntPrm)
193
196
  paramsLeft.delete(cntPrm);
194
197
  const decode = getDecoder(prm);
195
- let values = searchParams?.getAll(prmName);
198
+ let values = searchParams?.getAll(key);
199
+ const prmName = typeof prm.name === 'string' ? prm.name : key;
196
200
  if (values?.length && prm.isArray) {
197
201
  values = values.map(v => splitString(v, { delimiters: prm.arraySeparator, quotes: true })).flat();
198
- values = values.map(v => decode(v, { coerce: true, label: prmName, onFail }));
202
+ values = values.map(v => decode(v, { coerce: true, label: key, onFail }));
199
203
  if (values.length)
200
204
  context.queryParams[prmName] = values;
201
205
  }
202
206
  else {
203
- const v = decode(values[0], { coerce: true, label: prmName, onFail });
207
+ const v = decode(values[0], { coerce: true, label: key, onFail });
204
208
  if (values.length)
205
209
  context.queryParams[prmName] = v;
206
210
  }
@@ -215,8 +219,8 @@ export class HttpHandler {
215
219
  }
216
220
  catch (e) {
217
221
  if (e instanceof ValidationError) {
218
- e = new BadRequestError({
219
- message: `Invalid parameter (${prmName}) value. ` + e.message,
222
+ throw new BadRequestError({
223
+ message: `Invalid parameter (${key}) value. ` + e.message,
220
224
  code: 'REQUEST_VALIDATION',
221
225
  details: e.issues,
222
226
  }, e);
@@ -236,9 +240,8 @@ export class HttpHandler {
236
240
  let contentType = request.header('content-type');
237
241
  if (contentType) {
238
242
  contentType = parseContentType(contentType).type;
239
- mediaType = operation.requestBody.content.find(mc => {
240
- return (mc.contentType && typeIs.is(contentType, Array.isArray(mc.contentType) ? mc.contentType : [mc.contentType]));
241
- });
243
+ mediaType = operation.requestBody.content.find(mc => mc.contentType &&
244
+ typeIs.is(contentType, Array.isArray(mc.contentType) ? mc.contentType : [mc.contentType]));
242
245
  }
243
246
  if (!mediaType) {
244
247
  const contentTypes = operation.requestBody.content.map(mc => mc.contentType).flat();
@@ -257,11 +260,12 @@ export class HttpHandler {
257
260
  throw new MethodNotAllowedError();
258
261
  const responseValue = await context.operationHandler.call(context.controllerInstance, context);
259
262
  const { response } = context;
260
- if (!response.writableEnded)
263
+ if (!response.writableEnded) {
261
264
  await this._sendResponse(context, responseValue).finally(() => {
262
265
  if (!response.writableEnded)
263
266
  response.end();
264
267
  });
268
+ }
265
269
  }
266
270
  /**
267
271
  *
@@ -387,8 +391,9 @@ export class HttpHandler {
387
391
  /** Filter available HttpOperationResponse instances according to status code. */
388
392
  const filteredResponses = operation.responses.filter(r => r.statusCode.find(sc => sc.start <= statusCode && sc.end >= statusCode));
389
393
  /** Throw InternalServerError if controller returns non-configured status code */
390
- if (!filteredResponses.length && statusCode < 400)
394
+ if (!filteredResponses.length && statusCode < 400) {
391
395
  throw new InternalServerError(`No responses defined for status code ${statusCode} in operation "${operation.name}"`);
396
+ }
392
397
  /** We search for content-type in filtered HttpOperationResponse array */
393
398
  if (filteredResponses.length) {
394
399
  /** If no response returned, and content-type has not been set (No response wants to be returned by operation) */
@@ -401,8 +406,9 @@ export class HttpHandler {
401
406
  if (contentType) {
402
407
  // Find HttpEndpointResponse instance according to content-type header
403
408
  operationResponse = filteredResponses.find(r => typeIs.is(contentType, toArray(r.contentType)));
404
- if (!operationResponse)
409
+ if (!operationResponse) {
405
410
  throw new InternalServerError(`Operation didn't configured to return "${contentType}" content`);
411
+ }
406
412
  }
407
413
  else {
408
414
  /** Select first HttpOperationResponse if content-type header has not been set */
@@ -434,23 +440,26 @@ export class HttpHandler {
434
440
  case 'Entity.Get':
435
441
  case 'Entity.FindMany':
436
442
  case 'Entity.Update': {
437
- if (!(body instanceof OperationResult))
443
+ if (!(body instanceof OperationResult)) {
438
444
  body = new OperationResult({
439
445
  payload: body,
440
446
  });
447
+ }
441
448
  if ((composition === 'Entity.Create' || composition === 'Entity.Update') &&
442
449
  composition &&
443
- body.affected == null)
450
+ body.affected == null) {
444
451
  body.affected = 1;
452
+ }
445
453
  break;
446
454
  }
447
455
  case 'Entity.Delete':
448
456
  case 'Entity.DeleteMany':
449
457
  case 'Entity.UpdateMany': {
450
- if (!(body instanceof OperationResult))
458
+ if (!(body instanceof OperationResult)) {
451
459
  body = new OperationResult({
452
460
  affected: body,
453
461
  });
462
+ }
454
463
  body.affected =
455
464
  typeof body.affected === 'number'
456
465
  ? body.affected
@@ -461,15 +470,19 @@ export class HttpHandler {
461
470
  : undefined;
462
471
  break;
463
472
  }
473
+ default:
474
+ break;
464
475
  }
465
476
  }
466
- if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type)
477
+ if (responseArgs.contentType && responseArgs.contentType !== parsedContentType?.type) {
467
478
  response.setHeader('content-type', responseArgs.contentType);
479
+ }
468
480
  if (responseArgs.contentType &&
469
481
  body != null &&
470
482
  !(body instanceof OperationResult) &&
471
- typeIs.is(responseArgs.contentType, [MimeTypes.opra_response_json]))
483
+ typeIs.is(responseArgs.contentType, [MimeTypes.opra_response_json])) {
472
484
  body = new OperationResult({ payload: body });
485
+ }
473
486
  if (hasBody)
474
487
  responseArgs.body = body;
475
488
  return responseArgs;
@@ -482,12 +495,13 @@ export class HttpHandler {
482
495
  const { searchParams } = url;
483
496
  const documentId = searchParams.get('id');
484
497
  const doc = documentId ? document.findDocument(documentId) : document;
485
- if (!doc)
498
+ if (!doc) {
486
499
  return this.sendErrorResponse(response, [
487
500
  new BadRequestError({
488
501
  message: `Document with given id [${documentId}] does not exists`,
489
502
  }),
490
503
  ]);
504
+ }
491
505
  /** Check if response cache exists */
492
506
  let responseBody = this[kAssetCache].get(doc, `$schema`);
493
507
  /** Create response if response cache does not exists */
@@ -2,10 +2,10 @@
2
2
  Some parts of this file contains codes from open source express library
3
3
  https://github.com/expressjs
4
4
  */
5
+ import typeIs from '@browsery/type-is';
5
6
  import accepts from 'accepts';
6
7
  import fresh from 'fresh';
7
8
  import parseRange from 'range-parser';
8
- import typeIs from '@browsery/type-is';
9
9
  import { BodyReader } from '../utils/body-reader.js';
10
10
  export class HttpIncomingHost {
11
11
  get protocol() {
@@ -37,11 +37,11 @@ export class HttpIncomingHost {
37
37
  get fresh() {
38
38
  const method = this.method;
39
39
  // GET or HEAD for weak freshness validation only
40
- if ('GET' !== method && 'HEAD' !== method)
40
+ if (method !== 'GET' && method !== 'HEAD')
41
41
  return false;
42
42
  const status = this.res?.statusCode;
43
43
  // 2xx or 304 as per rfc2616 14.26
44
- if ((status >= 200 && status < 300) || 304 === status) {
44
+ if ((status >= 200 && status < 300) || status === 304) {
45
45
  return fresh(this.headers, {
46
46
  etag: this.res.getHeader('ETag'),
47
47
  'last-modified': this.res.getHeader('Last-Modified'),
@@ -2,6 +2,7 @@
2
2
  Some parts of this file contains codes from open source express library
3
3
  https://github.com/expressjs
4
4
  */
5
+ import { HttpStatusCode } from '@opra/common';
5
6
  import contentDisposition from 'content-disposition';
6
7
  import contentType from 'content-type';
7
8
  import cookie from 'cookie';
@@ -11,7 +12,6 @@ import mime from 'mime-types';
11
12
  import path from 'path';
12
13
  import { toString } from 'putil-varhelpers';
13
14
  import vary from 'vary';
14
- import { HttpStatusCode } from '@opra/common';
15
15
  const charsetRegExp = /;\s*charset\s*=/;
16
16
  export class HttpOutgoingHost {
17
17
  attachment(filename) {
@@ -160,7 +160,7 @@ export class HttpOutgoingHost {
160
160
  if (req?.fresh)
161
161
  this.statusCode = 304;
162
162
  // strip irrelevant headers
163
- if (204 === this.statusCode || 304 === this.statusCode) {
163
+ if (this.statusCode === 204 || this.statusCode === 304) {
164
164
  this.removeHeader('Content-Type');
165
165
  this.removeHeader('Content-Length');
166
166
  this.removeHeader('Transfer-Encoding');
@@ -12,9 +12,7 @@ export class MultipartReader extends EventEmitter {
12
12
  this._incoming = incoming;
13
13
  const form = (this._form = formidable({
14
14
  ...options,
15
- filter: (part) => {
16
- return !this._cancelled && (!options?.filter || options.filter(part));
17
- },
15
+ filter: (part) => !this._cancelled && (!options?.filter || options.filter(part)),
18
16
  }));
19
17
  form.once('error', () => {
20
18
  this._cancelled = true;
@@ -69,7 +67,7 @@ export class MultipartReader extends EventEmitter {
69
67
  }
70
68
  resume() {
71
69
  if (!this._started)
72
- this._form.parse(this._incoming, () => void 0);
70
+ this._form.parse(this._incoming, () => undefined);
73
71
  if (this._form.req)
74
72
  this._form.resume();
75
73
  }
@@ -88,12 +86,8 @@ export class MultipartReader extends EventEmitter {
88
86
  return resolve();
89
87
  file._writeStream.once('close', resolve);
90
88
  })
91
- .then(() => {
92
- return fs.unlink(file.filepath);
93
- })
94
- .then(() => {
95
- return 0;
96
- }));
89
+ .then(() => fs.unlink(file.filepath))
90
+ .then(() => 0));
97
91
  });
98
92
  return Promise.allSettled(promises);
99
93
  }
@@ -1,5 +1,5 @@
1
- import { Duplex, Readable } from 'stream';
2
1
  import { isAsyncIterable, isIterable } from '@opra/common';
2
+ import { Duplex, Readable } from 'stream';
3
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');
@@ -33,10 +33,12 @@ export class NodeIncomingMessageHost extends Duplex {
33
33
  else
34
34
  this.body = Buffer.from(JSON.stringify(init.body), 'utf-8');
35
35
  }
36
- if (init.headers)
36
+ if (init.headers) {
37
37
  this.rawHeaders = Array.isArray(init.headers) ? init.headers : convertToRawHeaders(init.headers);
38
- if (init.trailers)
38
+ }
39
+ if (init.trailers) {
39
40
  this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : convertToRawHeaders(init.trailers);
41
+ }
40
42
  this.ip = init.ip || '';
41
43
  this.ips = init.ips || (this.ip ? [this.ip] : []);
42
44
  if (this.body && !this.headers['content-length'])
@@ -1,6 +1,6 @@
1
- import { Readable } from 'stream';
2
1
  import { HTTPParser } from '@browsery/http-parser';
3
2
  import { isAsyncIterable, isIterable } from '@opra/common';
3
+ import { Readable } from 'stream';
4
4
  import { CRLF, kHttpParser, NodeIncomingMessageHost } from '../impl/node-incoming-message.host.js';
5
5
  import { concatReadable } from '../utils/concat-readable.js';
6
6
  /**
@@ -14,8 +14,9 @@ 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' && !(isIterable(iterable) || isAsyncIterable(iterable))) {
18
18
  return new NodeIncomingMessageHost(iterable);
19
+ }
19
20
  const msg = new NodeIncomingMessageHost();
20
21
  const parser = (msg[kHttpParser] = new HTTPParser(HTTPParser.REQUEST));
21
22
  let bodyChunks;
@@ -1,3 +1,5 @@
1
+ import typeIs from '@browsery/type-is';
2
+ import { BadRequestError, InternalServerError, OpraHttpError } from '@opra/common';
1
3
  import { Base64Decode } from 'base64-stream';
2
4
  import byteParser from 'bytes';
3
5
  import { parse as parseContentType } from 'content-type';
@@ -5,8 +7,6 @@ import { EventEmitter } from 'events';
5
7
  import iconv from 'iconv-lite';
6
8
  import { Writable } from 'stream';
7
9
  import * as zlib from 'zlib';
8
- import typeIs from '@browsery/type-is';
9
- import { BadRequestError, InternalServerError, OpraHttpError } from '@opra/common';
10
10
  /**
11
11
  *
12
12
  * @class BodyReader
@@ -29,11 +29,12 @@ export class BodyReader extends EventEmitter {
29
29
  }
30
30
  async read() {
31
31
  /* istanbul ignore next */
32
- if (this._completed)
32
+ if (this._completed) {
33
33
  throw new InternalServerError({
34
34
  message: 'Stream already read',
35
35
  code: 'STREAM_ALREADY_READ',
36
36
  });
37
+ }
37
38
  if (!this.req.readable) {
38
39
  throw new InternalServerError({
39
40
  message: 'Stream is not readable',
@@ -57,8 +58,9 @@ export class BodyReader extends EventEmitter {
57
58
  * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
58
59
  */
59
60
  const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
60
- if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength)))
61
+ if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength))) {
61
62
  return this.onEnd();
63
+ }
62
64
  // check the length and limit options.
63
65
  // note: we intentionally leave the stream paused,
64
66
  // so users should handle the stream themselves.
@@ -55,6 +55,7 @@ export const validateHeaderValue = hideStackFrames((name, value) => {
55
55
  }
56
56
  });
57
57
  export function validateString(value, name) {
58
- if (typeof value !== 'string')
58
+ if (typeof value !== 'string') {
59
59
  throw new TypeError(`Invalid ${name ? name + ' ' : ''}argument. Value must be a string`);
60
+ }
60
61
  }
package/esm/index.js CHANGED
@@ -6,20 +6,20 @@ import * as HttpOutgoingHost_ from './http/impl/http-outgoing.host.js';
6
6
  import * as NodeIncomingMessageHost_ from './http/impl/node-incoming-message.host.js';
7
7
  import * as NodeOutgoingMessageHost_ from './http/impl/node-outgoing-message.host.js';
8
8
  export * from './execution-context.js';
9
- export * from './platform-adapter.js';
10
- export * from './type-guards.js';
11
9
  export * from './helpers/logger.js';
12
10
  export * from './helpers/service-base.js';
13
11
  export * from './http/express-adapter.js';
14
12
  export * from './http/http-adapter.js';
15
13
  export * from './http/http-context.js';
14
+ export * from './http/impl/multipart-reader.js';
16
15
  export * from './http/interfaces/http-incoming.interface.js';
17
16
  export * from './http/interfaces/http-outgoing.interface.js';
18
17
  export * from './http/interfaces/node-incoming-message.interface.js';
19
18
  export * from './http/interfaces/node-outgoing-message.interface.js';
20
- export * from './http/impl/multipart-reader.js';
21
19
  export * from './http/utils/wrap-exception.js';
22
20
  export * from './interfaces/logger.interface.js';
21
+ export * from './platform-adapter.js';
22
+ export * from './type-guards.js';
23
23
  export var classes;
24
24
  (function (classes) {
25
25
  classes.HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
@@ -1,6 +1,6 @@
1
1
  import './augmentation/18n.augmentation.js';
2
- import { AsyncEventEmitter } from 'strict-typed-events';
3
2
  import { I18n } from '@opra/common';
3
+ import { AsyncEventEmitter } from 'strict-typed-events';
4
4
  import { kAssetCache } from './constants.js';
5
5
  import { Logger } from './helpers/logger.js';
6
6
  import { AssetCache } from './http/impl/asset-cache.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/core",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.9",
4
4
  "description": "Opra schema package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -19,8 +19,9 @@
19
19
  "_copy_pkg_files": "cp README.md package.json ../../LICENSE ../../build/core && cp ../../package.cjs.json ../../build/core/cjs/package.json",
20
20
  "_copyi18n": "cp -R i18n ../../build/core/i18n",
21
21
  "lint": "eslint . --max-warnings=0",
22
- "check": "madge --circular src/**",
22
+ "lint:fix": "eslint . --max-warnings=0 --fix",
23
23
  "format": "prettier . --write --log-level=warn",
24
+ "check": "madge --circular src/**",
24
25
  "test": "jest --passWithNoTests",
25
26
  "cover": "jest --passWithNoTests --collect-coverage",
26
27
  "clean": "npm run clean:src && npm run clean:test && npm run clean:dist && npm run clean:cover",
@@ -30,8 +31,9 @@
30
31
  "clean:cover": "rimraf ../../coverage/client"
31
32
  },
32
33
  "dependencies": {
34
+ "@browsery/http-parser": "^0.5.8",
33
35
  "@browsery/type-is": "^1.6.18-r2",
34
- "@opra/common": "^1.0.0-alpha.7",
36
+ "@opra/common": "^1.0.0-alpha.9",
35
37
  "@types/formidable": "^3.4.5",
36
38
  "accepts": "^1.3.8",
37
39
  "base64-stream": "^1.0.0",
@@ -44,12 +46,15 @@
44
46
  "encodeurl": "^2.0.0",
45
47
  "formidable": "^3.5.1",
46
48
  "fresh": "^0.5.2",
49
+ "iconv-lite": "^0.6.3",
47
50
  "mime-types": "^2.1.35",
48
51
  "power-tasks": "^1.7.3",
49
52
  "putil-isplainobject": "^1.1.5",
53
+ "putil-merge": "^3.12.1",
50
54
  "putil-varhelpers": "^1.6.5",
51
55
  "range-parser": "^1.2.1",
52
56
  "raw-body": "^2.5.2",
57
+ "reflect-metadata": "^0.2.2",
53
58
  "strict-typed-events": "^2.3.3",
54
59
  "vary": "^1.1.2"
55
60
  },
@@ -76,8 +81,9 @@
76
81
  "cookie-parser": "^1.4.6",
77
82
  "crypto-browserify": "^3.12.0",
78
83
  "express": "^4.19.2",
79
- "fastify": "^4.28.0",
84
+ "fastify": "^4.28.1",
80
85
  "path-browserify": "^1.0.1",
86
+ "supertest": "^7.0.0",
81
87
  "ts-gems": "^3.4.0"
82
88
  },
83
89
  "type": "module",
@@ -1,4 +1,3 @@
1
- import { FallbackLng, LanguageResource } from '@opra/common';
2
1
  declare module '@opra/common' {
3
2
  interface I18n {
4
3
  loadResourceDir(dirnames: string | string[], deep?: boolean, overwrite?: boolean): Promise<void>;
@@ -35,3 +34,4 @@ declare module '@opra/common' {
35
34
  }
36
35
  }
37
36
  }
37
+ export {};
@@ -1,5 +1,5 @@
1
- import { AsyncEventEmitter } from 'strict-typed-events';
2
1
  import { ApiDocument, OpraSchema } from '@opra/common';
2
+ import { AsyncEventEmitter } from 'strict-typed-events';
3
3
  /**
4
4
  * @namespace ExecutionContext
5
5
  */
@@ -1,5 +1,5 @@
1
- import { Application } from 'express';
2
1
  import { ApiDocument, HttpController } from '@opra/common';
2
+ import { Application } from 'express';
3
3
  import { HttpAdapter } from './http-adapter.js';
4
4
  export declare class ExpressAdapter extends HttpAdapter {
5
5
  readonly app: Application;
@@ -2,9 +2,9 @@
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
4
  /// <reference types="node" />
5
+ import { HTTPParserJS } from '@browsery/http-parser';
5
6
  import { IncomingHttpHeaders } from 'http';
6
7
  import { Duplex, Readable } from 'stream';
7
- import { HTTPParserJS } from '@browsery/http-parser';
8
8
  import type { NodeIncomingMessage } from '../interfaces/node-incoming-message.interface';
9
9
  export declare const CRLF: Buffer;
10
10
  export declare const kHeaders: unique symbol;
@@ -1,8 +1,8 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
- import { EventEmitter } from 'events';
5
4
  import nodeStream from 'node:stream';
5
+ import { EventEmitter } from 'events';
6
6
  import type { HttpIncoming } from '../interfaces/http-incoming.interface.js';
7
7
  /**
8
8
  *
package/types/index.d.ts CHANGED
@@ -6,20 +6,20 @@ import * as HttpOutgoingHost_ from './http/impl/http-outgoing.host.js';
6
6
  import * as NodeIncomingMessageHost_ from './http/impl/node-incoming-message.host.js';
7
7
  import * as NodeOutgoingMessageHost_ from './http/impl/node-outgoing-message.host.js';
8
8
  export * from './execution-context.js';
9
- export * from './platform-adapter.js';
10
- export * from './type-guards.js';
11
9
  export * from './helpers/logger.js';
12
10
  export * from './helpers/service-base.js';
13
11
  export * from './http/express-adapter.js';
14
12
  export * from './http/http-adapter.js';
15
13
  export * from './http/http-context.js';
14
+ export * from './http/impl/multipart-reader.js';
16
15
  export * from './http/interfaces/http-incoming.interface.js';
17
16
  export * from './http/interfaces/http-outgoing.interface.js';
18
17
  export * from './http/interfaces/node-incoming-message.interface.js';
19
18
  export * from './http/interfaces/node-outgoing-message.interface.js';
20
- export * from './http/impl/multipart-reader.js';
21
19
  export * from './http/utils/wrap-exception.js';
22
20
  export * from './interfaces/logger.interface.js';
21
+ export * from './platform-adapter.js';
22
+ export * from './type-guards.js';
23
23
  export declare namespace classes {
24
24
  export import HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
25
25
  export import HttpOutgoingHost = HttpOutgoingHost_.HttpOutgoingHost;
@@ -1,6 +1,6 @@
1
1
  import './augmentation/18n.augmentation.js';
2
- import { AsyncEventEmitter } from 'strict-typed-events';
3
2
  import { ApiDocument, I18n, OpraSchema } from '@opra/common';
3
+ import { AsyncEventEmitter } from 'strict-typed-events';
4
4
  import { kAssetCache } from './constants.js';
5
5
  import { Logger } from './helpers/logger.js';
6
6
  import { AssetCache } from './http/impl/asset-cache.js';