@opra/core 0.33.13 → 1.0.0-alpha.10

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 (155) hide show
  1. package/cjs/augmentation/18n.augmentation.js +18 -5
  2. package/cjs/augmentation/http-controller.augmentation.js +25 -0
  3. package/cjs/constants.js +5 -0
  4. package/cjs/execution-context.js +24 -12
  5. package/cjs/{services → helpers}/logger.js +1 -2
  6. package/cjs/{services/api-service.js → helpers/service-base.js} +8 -8
  7. package/cjs/http/express-adapter.js +153 -0
  8. package/cjs/http/http-adapter.js +27 -0
  9. package/cjs/http/http-context.js +119 -0
  10. package/cjs/http/impl/asset-cache.js +21 -0
  11. package/cjs/http/impl/http-handler.js +584 -0
  12. package/cjs/http/{http-server-request.js → impl/http-incoming.host.js} +24 -49
  13. package/cjs/http/{http-server-response.js → impl/http-outgoing.host.js} +9 -28
  14. package/cjs/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +23 -27
  15. package/cjs/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +18 -57
  16. package/cjs/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +11 -14
  17. package/cjs/http/interfaces/http-incoming.interface.js +25 -0
  18. package/cjs/http/interfaces/http-outgoing.interface.js +22 -0
  19. package/cjs/http/interfaces/node-incoming-message.interface.js +64 -0
  20. package/cjs/http/interfaces/node-outgoing-message.interface.js +15 -0
  21. package/cjs/http/utils/body-reader.js +217 -0
  22. package/cjs/http/{helpers → utils}/common.js +2 -1
  23. package/cjs/http/{helpers → utils}/convert-to-raw-headers.js +1 -2
  24. package/cjs/http/{helpers → utils}/match-known-fields.js +11 -9
  25. package/cjs/http/utils/wrap-exception.js +34 -0
  26. package/cjs/index.js +26 -26
  27. package/cjs/platform-adapter.js +21 -0
  28. package/cjs/type-guards.js +23 -0
  29. package/esm/augmentation/18n.augmentation.js +20 -7
  30. package/esm/augmentation/http-controller.augmentation.js +23 -0
  31. package/esm/constants.js +2 -0
  32. package/esm/execution-context.js +24 -13
  33. package/esm/{services → helpers}/logger.js +1 -2
  34. package/esm/{services/api-service.js → helpers/service-base.js} +6 -6
  35. package/esm/http/express-adapter.js +148 -0
  36. package/esm/http/http-adapter.js +23 -0
  37. package/esm/http/http-context.js +114 -0
  38. package/esm/http/impl/asset-cache.js +17 -0
  39. package/esm/http/impl/http-handler.js +579 -0
  40. package/esm/http/{http-server-request.js → impl/http-incoming.host.js} +20 -46
  41. package/esm/http/{http-server-response.js → impl/http-outgoing.host.js} +7 -27
  42. package/esm/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +21 -25
  43. package/esm/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +16 -55
  44. package/esm/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +9 -12
  45. package/esm/http/interfaces/http-incoming.interface.js +22 -0
  46. package/esm/http/interfaces/http-outgoing.interface.js +19 -0
  47. package/esm/http/interfaces/node-incoming-message.interface.js +61 -0
  48. package/esm/http/interfaces/node-outgoing-message.interface.js +12 -0
  49. package/esm/http/utils/body-reader.js +212 -0
  50. package/esm/http/{helpers → utils}/common.js +2 -1
  51. package/esm/http/{helpers → utils}/convert-to-headers.js +1 -1
  52. package/esm/http/{helpers → utils}/convert-to-raw-headers.js +2 -3
  53. package/esm/http/{helpers → utils}/match-known-fields.js +11 -9
  54. package/esm/http/utils/wrap-exception.js +30 -0
  55. package/esm/index.js +26 -27
  56. package/esm/platform-adapter.js +19 -1
  57. package/esm/type-guards.js +16 -0
  58. package/package.json +31 -13
  59. package/types/augmentation/18n.augmentation.d.ts +31 -1
  60. package/types/augmentation/http-controller.augmentation.d.ts +21 -0
  61. package/types/constants.d.ts +2 -0
  62. package/types/execution-context.d.ts +22 -26
  63. package/types/helpers/service-base.d.ts +10 -0
  64. package/types/http/express-adapter.d.ts +13 -0
  65. package/types/http/http-adapter.d.ts +27 -0
  66. package/types/http/http-context.d.ts +44 -0
  67. package/types/http/impl/asset-cache.d.ts +5 -0
  68. package/types/http/impl/http-handler.d.ts +73 -0
  69. package/types/http/impl/http-incoming.host.d.ts +23 -0
  70. package/types/http/impl/http-outgoing.host.d.ts +17 -0
  71. package/types/http/{helpers/multipart-helper.d.ts → impl/multipart-reader.d.ts} +8 -6
  72. package/types/http/impl/{http-incoming-message.host.d.ts → node-incoming-message.host.d.ts} +10 -23
  73. package/types/http/impl/{http-outgoing-message.host.d.ts → node-outgoing-message.host.d.ts} +11 -27
  74. package/types/http/{http-server-request.d.ts → interfaces/http-incoming.interface.d.ts} +28 -17
  75. package/types/http/{http-server-response.d.ts → interfaces/http-outgoing.interface.d.ts} +17 -10
  76. package/types/http/interfaces/node-incoming-message.interface.d.ts +38 -0
  77. package/types/http/interfaces/node-outgoing-message.interface.d.ts +29 -0
  78. package/types/http/utils/body-reader.d.ts +41 -0
  79. package/types/http/utils/wrap-exception.d.ts +2 -0
  80. package/types/index.d.ts +25 -27
  81. package/types/platform-adapter.d.ts +20 -48
  82. package/types/type-guards.d.ts +8 -0
  83. package/cjs/augmentation/collection.augmentation.js +0 -2
  84. package/cjs/augmentation/container.augmentation.js +0 -2
  85. package/cjs/augmentation/resource.augmentation.js +0 -26
  86. package/cjs/augmentation/singleton.augmentation.js +0 -2
  87. package/cjs/augmentation/storage.augmentation.js +0 -2
  88. package/cjs/execution-context.host.js +0 -46
  89. package/cjs/http/adapters/express-adapter.host.js +0 -34
  90. package/cjs/http/adapters/express-adapter.js +0 -14
  91. package/cjs/http/adapters/node-http-adapter.host.js +0 -70
  92. package/cjs/http/adapters/node-http-adapter.js +0 -14
  93. package/cjs/http/helpers/json-body-loader.js +0 -29
  94. package/cjs/http/helpers/query-parsers.js +0 -16
  95. package/cjs/http/http-adapter-host.js +0 -715
  96. package/cjs/interfaces/interceptor.interface.js +0 -2
  97. package/cjs/interfaces/request-handler.interface.js +0 -2
  98. package/cjs/platform-adapter.host.js +0 -154
  99. package/cjs/request-context.js +0 -25
  100. package/cjs/request.host.js +0 -24
  101. package/cjs/request.js +0 -2
  102. package/cjs/response.host.js +0 -22
  103. package/cjs/response.js +0 -2
  104. package/esm/augmentation/collection.augmentation.js +0 -1
  105. package/esm/augmentation/container.augmentation.js +0 -1
  106. package/esm/augmentation/resource.augmentation.js +0 -24
  107. package/esm/augmentation/singleton.augmentation.js +0 -1
  108. package/esm/augmentation/storage.augmentation.js +0 -1
  109. package/esm/execution-context.host.js +0 -42
  110. package/esm/http/adapters/express-adapter.host.js +0 -30
  111. package/esm/http/adapters/express-adapter.js +0 -11
  112. package/esm/http/adapters/node-http-adapter.host.js +0 -65
  113. package/esm/http/adapters/node-http-adapter.js +0 -11
  114. package/esm/http/helpers/json-body-loader.js +0 -24
  115. package/esm/http/helpers/query-parsers.js +0 -12
  116. package/esm/http/http-adapter-host.js +0 -710
  117. package/esm/interfaces/interceptor.interface.js +0 -1
  118. package/esm/interfaces/request-handler.interface.js +0 -1
  119. package/esm/platform-adapter.host.js +0 -149
  120. package/esm/request-context.js +0 -22
  121. package/esm/request.host.js +0 -20
  122. package/esm/request.js +0 -1
  123. package/esm/response.host.js +0 -18
  124. package/esm/response.js +0 -1
  125. package/types/augmentation/collection.augmentation.d.ts +0 -146
  126. package/types/augmentation/container.augmentation.d.ts +0 -14
  127. package/types/augmentation/resource.augmentation.d.ts +0 -38
  128. package/types/augmentation/singleton.augmentation.d.ts +0 -83
  129. package/types/augmentation/storage.augmentation.d.ts +0 -50
  130. package/types/execution-context.host.d.ts +0 -25
  131. package/types/http/adapters/express-adapter.d.ts +0 -15
  132. package/types/http/adapters/express-adapter.host.d.ts +0 -12
  133. package/types/http/adapters/node-http-adapter.d.ts +0 -17
  134. package/types/http/adapters/node-http-adapter.host.d.ts +0 -19
  135. package/types/http/helpers/json-body-loader.d.ts +0 -5
  136. package/types/http/helpers/query-parsers.d.ts +0 -1
  137. package/types/http/http-adapter-host.d.ts +0 -34
  138. package/types/interfaces/interceptor.interface.d.ts +0 -2
  139. package/types/interfaces/request-handler.interface.d.ts +0 -4
  140. package/types/platform-adapter.host.d.ts +0 -43
  141. package/types/request-context.d.ts +0 -13
  142. package/types/request.d.ts +0 -14
  143. package/types/request.host.d.ts +0 -27
  144. package/types/response.d.ts +0 -22
  145. package/types/response.host.d.ts +0 -22
  146. package/types/services/api-service.d.ts +0 -10
  147. /package/cjs/http/{helpers → utils}/concat-readable.js +0 -0
  148. /package/cjs/http/{helpers → utils}/convert-to-headers.js +0 -0
  149. /package/esm/http/{helpers → utils}/concat-readable.js +0 -0
  150. /package/types/{services → helpers}/logger.d.ts +0 -0
  151. /package/types/http/{helpers → utils}/common.d.ts +0 -0
  152. /package/types/http/{helpers → utils}/concat-readable.d.ts +0 -0
  153. /package/types/http/{helpers → utils}/convert-to-headers.d.ts +0 -0
  154. /package/types/http/{helpers → utils}/convert-to-raw-headers.d.ts +0 -0
  155. /package/types/http/{helpers → utils}/match-known-fields.d.ts +0 -0
@@ -0,0 +1,212 @@
1
+ import typeIs from '@browsery/type-is';
2
+ import { BadRequestError, InternalServerError, OpraHttpError } from '@opra/common';
3
+ import { Base64Decode } from 'base64-stream';
4
+ import byteParser from 'bytes';
5
+ import { parse as parseContentType } from 'content-type';
6
+ import { EventEmitter } from 'events';
7
+ import iconv from 'iconv-lite';
8
+ import { Writable } from 'stream';
9
+ import * as zlib from 'zlib';
10
+ /**
11
+ *
12
+ * @class BodyReader
13
+ */
14
+ export class BodyReader extends EventEmitter {
15
+ constructor(req, options) {
16
+ super();
17
+ this.req = req;
18
+ this._completed = false;
19
+ this._receivedSize = 0;
20
+ this.onAborted = () => this._onAborted();
21
+ this.onData = (chunk) => this._onData(chunk);
22
+ this.onEnd = (err) => this._onEnd(err);
23
+ this.cleanup = () => this._cleanup();
24
+ this.limit = options?.limit
25
+ ? typeof options.limit === 'number'
26
+ ? options.limit
27
+ : byteParser(options.limit)
28
+ : undefined;
29
+ }
30
+ async read() {
31
+ /* istanbul ignore next */
32
+ if (this._completed) {
33
+ throw new InternalServerError({
34
+ message: 'Stream already read',
35
+ code: 'STREAM_ALREADY_READ',
36
+ });
37
+ }
38
+ if (!this.req.readable) {
39
+ throw new InternalServerError({
40
+ message: 'Stream is not readable',
41
+ code: 'STREAM_NOT_READABLE',
42
+ });
43
+ }
44
+ return new Promise((resolve, reject) => {
45
+ // eslint-disable-next-line prefer-const
46
+ let sizeStream;
47
+ this.once('finish', (error, data) => {
48
+ if (sizeStream)
49
+ this.req.unpipe(sizeStream);
50
+ if (error)
51
+ return reject(error);
52
+ resolve(data);
53
+ });
54
+ /**
55
+ * Check if a request has a request body.
56
+ * A request with a body __must__ either have `transfer-encoding`
57
+ * or `content-length` headers set.
58
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
59
+ */
60
+ const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
61
+ if (this.req.headers['transfer-encoding'] === undefined && !(contentLength && !isNaN(contentLength))) {
62
+ return this.onEnd();
63
+ }
64
+ // check the length and limit options.
65
+ // note: we intentionally leave the stream paused,
66
+ // so users should handle the stream themselves.
67
+ if (this.limit != null && contentLength != null && contentLength > this.limit) {
68
+ return this.onEnd(new OpraHttpError({
69
+ message: 'Content Too Large',
70
+ code: 'HTTP.CONTENT_TOO_LARGE',
71
+ details: {
72
+ length: contentLength,
73
+ limit: this.limit,
74
+ },
75
+ }, 413));
76
+ }
77
+ // Pipe to a Writable stream to count received bytes
78
+ const _this = this;
79
+ sizeStream = new Writable({
80
+ write(chunk, encoding, callback) {
81
+ if (_this._completed)
82
+ return;
83
+ _this._receivedSize += chunk.length;
84
+ if (_this.limit != null && _this._receivedSize > _this.limit) {
85
+ callback(new OpraHttpError({
86
+ message: 'Content Too Large',
87
+ code: 'HTTP.CONTENT_TOO_LARGE',
88
+ details: {
89
+ limit: _this.limit,
90
+ received: _this._receivedSize,
91
+ },
92
+ }, 413));
93
+ }
94
+ },
95
+ });
96
+ this.req.pipe(sizeStream);
97
+ let stream = BodyReader.encoderPipeline(this.req);
98
+ const mediaType = parseContentType(this.req.headers['content-type'] || '');
99
+ let charset = (mediaType.parameters.charset || '').toLowerCase();
100
+ if (!charset && typeIs.is(mediaType.type, ['json', 'xml', 'txt']))
101
+ charset = 'utf-8';
102
+ if (charset) {
103
+ const newStream = iconv.decodeStream(charset);
104
+ stream.pipe(newStream);
105
+ stream = newStream;
106
+ }
107
+ this._stream = stream;
108
+ // attach listeners
109
+ stream.on('aborted', this.onAborted);
110
+ stream.on('close', this.cleanup);
111
+ stream.on('data', this.onData);
112
+ stream.on('end', this.onEnd);
113
+ stream.on('error', this.onEnd);
114
+ });
115
+ }
116
+ _onEnd(error) {
117
+ if (this._completed)
118
+ return;
119
+ this._completed = true;
120
+ if (error) {
121
+ this._stream?.unpipe();
122
+ this._stream?.pause();
123
+ }
124
+ if (error)
125
+ this.emit('finish', error);
126
+ else if (Array.isArray(this._buffer))
127
+ this.emit('finish', error, Buffer.concat(this._buffer));
128
+ else
129
+ this.emit('finish', error, this._buffer);
130
+ this._cleanup();
131
+ }
132
+ _cleanup() {
133
+ if (this._stream) {
134
+ this._stream.removeListener('aborted', this.onAborted);
135
+ this._stream.removeListener('close', this.cleanup);
136
+ this._stream.removeListener('data', this.onData);
137
+ this._stream.removeListener('end', this.onEnd);
138
+ this._stream.removeListener('error', this.onEnd);
139
+ }
140
+ }
141
+ _onAborted() {
142
+ if (this._completed)
143
+ return;
144
+ this.onEnd(new BadRequestError({
145
+ message: 'request aborted',
146
+ code: 'ECONNABORTED',
147
+ details: {
148
+ length,
149
+ received: this._receivedSize,
150
+ },
151
+ }));
152
+ }
153
+ _onData(chunk) {
154
+ if (this._completed)
155
+ return;
156
+ if (typeof chunk === 'string') {
157
+ this._buffer = this._buffer || '';
158
+ this._buffer += chunk;
159
+ }
160
+ else {
161
+ this._buffer = this._buffer || [];
162
+ this._buffer.push(chunk);
163
+ }
164
+ }
165
+ static async read(req, options) {
166
+ const bodyReady = new BodyReader(req, options);
167
+ return bodyReady.read();
168
+ }
169
+ static encoderPipeline(req) {
170
+ const contentEncoding = req.headers['content-encoding'] || 'identity';
171
+ const contentEncodings = (Array.isArray(contentEncoding) ? contentEncoding : contentEncoding.split(/\s*,\s*/))
172
+ .map(s => s.toLowerCase())
173
+ .reverse();
174
+ return contentEncodings.reduce((prev, encoding) => {
175
+ switch (encoding) {
176
+ case 'gzip':
177
+ case 'x-gzip': {
178
+ const newStream = zlib.createGunzip();
179
+ prev.pipe(newStream);
180
+ return newStream;
181
+ }
182
+ case 'deflate':
183
+ case 'x-deflate': {
184
+ const newStream = zlib.createInflate();
185
+ prev.pipe(newStream);
186
+ return newStream;
187
+ }
188
+ case 'br': {
189
+ const newStream = zlib.createBrotliDecompress();
190
+ prev.pipe(newStream);
191
+ return newStream;
192
+ }
193
+ case 'base64': {
194
+ const newStream = new Base64Decode();
195
+ prev.pipe(newStream);
196
+ return newStream;
197
+ }
198
+ case 'identity':
199
+ // prev.length = 0;
200
+ return prev;
201
+ default:
202
+ throw new BadRequestError({
203
+ message: 'unsupported content encoding "' + encoding + '"',
204
+ code: '',
205
+ details: {
206
+ encoding,
207
+ },
208
+ }, 415);
209
+ }
210
+ }, req);
211
+ }
212
+ }
@@ -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
  }
@@ -1,4 +1,4 @@
1
- import { ARRAY_FIELD, COMMA_DELIMITED_FIELD, matchKnownFields, SEMICOLON_DELIMITED_FIELD } from './match-known-fields.js';
1
+ import { ARRAY_FIELD, COMMA_DELIMITED_FIELD, matchKnownFields, SEMICOLON_DELIMITED_FIELD, } from './match-known-fields.js';
2
2
  export function convertToHeaders(src, dst, joinDuplicateHeaders) {
3
3
  for (let n = 0; n < src.length; n += 2) {
4
4
  addHeaderLine(src[n], src[n + 1], dst, joinDuplicateHeaders);
@@ -1,7 +1,6 @@
1
- import { ARRAY_FIELD, COMMA_DELIMITED_FIELD, matchKnownFields, SEMICOLON_DELIMITED_FIELD } from './match-known-fields.js';
1
+ import { ARRAY_FIELD, COMMA_DELIMITED_FIELD, matchKnownFields, SEMICOLON_DELIMITED_FIELD, } from './match-known-fields.js';
2
2
  export function convertToRawHeaders(src) {
3
- return Object.entries(src)
4
- .reduce((a, [field, v]) => {
3
+ return Object.entries(src).reduce((a, [field, v]) => {
5
4
  const [name, flag] = matchKnownFields(field);
6
5
  if (flag === ARRAY_FIELD) {
7
6
  if (Array.isArray(v))
@@ -3,9 +3,7 @@ export const NO_DUPLICATES_FIELD = 0;
3
3
  export const COMMA_DELIMITED_FIELD = 1;
4
4
  export const SEMICOLON_DELIMITED_FIELD = 2;
5
5
  export const ARRAY_FIELD = 3;
6
- const ARRAY_HEADERS = [
7
- 'set-cookie'
8
- ];
6
+ const ARRAY_HEADERS = ['set-cookie'];
9
7
  const NO_DUPLICATES_HEADERS = [
10
8
  'age',
11
9
  'from',
@@ -27,13 +25,17 @@ const NO_DUPLICATES_HEADERS = [
27
25
  'if-unmodified-since',
28
26
  ];
29
27
  const SEMICOLON_DELIMITED_HEADERS = ['cookie'];
30
- const KNOWN_FIELDS = Object.values(HttpHeaderCodes)
31
- .reduce((o, k) => {
28
+ const KNOWN_FIELDS = Object.values(HttpHeaderCodes).reduce((o, k) => {
32
29
  const n = k.toLowerCase();
33
- o[n] = [k,
34
- (NO_DUPLICATES_HEADERS.includes(n) ? NO_DUPLICATES_FIELD :
35
- (ARRAY_HEADERS.includes(n) ? ARRAY_FIELD :
36
- (SEMICOLON_DELIMITED_HEADERS.includes(n) ? SEMICOLON_DELIMITED_FIELD : COMMA_DELIMITED_FIELD)))
30
+ o[n] = [
31
+ k,
32
+ NO_DUPLICATES_HEADERS.includes(n)
33
+ ? NO_DUPLICATES_FIELD
34
+ : ARRAY_HEADERS.includes(n)
35
+ ? ARRAY_FIELD
36
+ : SEMICOLON_DELIMITED_HEADERS.includes(n)
37
+ ? SEMICOLON_DELIMITED_FIELD
38
+ : COMMA_DELIMITED_FIELD,
37
39
  ];
38
40
  return o;
39
41
  }, {});
@@ -0,0 +1,30 @@
1
+ import { BadRequestError, FailedDependencyError, ForbiddenError, InternalServerError, MethodNotAllowedError, NotAcceptableError, NotFoundError, OpraHttpError, UnauthorizedError, UnprocessableEntityError, } from '@opra/common';
2
+ export function wrapException(error) {
3
+ if (error instanceof OpraHttpError)
4
+ return error;
5
+ let status = 500;
6
+ if (typeof error.status === 'number')
7
+ status = error.status;
8
+ else if (typeof error.getStatus === 'function')
9
+ status = error.getStatus();
10
+ switch (status) {
11
+ case 400:
12
+ return new BadRequestError(error);
13
+ case 401:
14
+ return new UnauthorizedError(error);
15
+ case 403:
16
+ return new ForbiddenError(error);
17
+ case 404:
18
+ return new NotFoundError(error);
19
+ case 405:
20
+ return new MethodNotAllowedError(error);
21
+ case 406:
22
+ return new NotAcceptableError(error);
23
+ case 422:
24
+ return new UnprocessableEntityError(error);
25
+ case 424:
26
+ return new FailedDependencyError(error);
27
+ default:
28
+ return new InternalServerError(error);
29
+ }
30
+ }
package/esm/index.js CHANGED
@@ -1,30 +1,29 @@
1
- import "reflect-metadata";
1
+ import 'reflect-metadata';
2
2
  import './augmentation/18n.augmentation.js';
3
- import './augmentation/resource.augmentation.js';
4
- import './augmentation/collection.augmentation.js';
5
- import './augmentation/container.augmentation.js';
6
- import './augmentation/singleton.augmentation.js';
7
- import './augmentation/storage.augmentation.js';
3
+ import './augmentation/http-controller.augmentation.js';
4
+ import * as HttpIncomingHost_ from './http/impl/http-incoming.host.js';
5
+ import * as HttpOutgoingHost_ from './http/impl/http-outgoing.host.js';
6
+ import * as NodeIncomingMessageHost_ from './http/impl/node-incoming-message.host.js';
7
+ import * as NodeOutgoingMessageHost_ from './http/impl/node-outgoing-message.host.js';
8
8
  export * from './execution-context.js';
9
- export * from './execution-context.host.js';
10
- export * from './platform-adapter.js';
11
- export * from './platform-adapter.host.js';
12
- export * from './request.js';
13
- export * from './request.host.js';
14
- export * from './request-context.js';
15
- export * from './response.js';
16
- export * from './response.host.js';
17
- export * from './http/adapters/express-adapter.js';
18
- export * from './http/adapters/express-adapter.host.js';
19
- export * from './http/adapters/node-http-adapter.js';
20
- export * from './http/adapters/node-http-adapter.host.js';
21
- export * from './http/impl/http-incoming-message.host.js';
22
- export * from './http/impl/http-outgoing-message.host.js';
23
- export * from './http/http-server-request.js';
24
- export * from './http/http-server-response.js';
25
- export * from './http/helpers/multipart-helper.js';
26
- export * from './interfaces/interceptor.interface.js';
9
+ export * from './helpers/logger.js';
10
+ export * from './helpers/service-base.js';
11
+ export * from './http/express-adapter.js';
12
+ export * from './http/http-adapter.js';
13
+ export * from './http/http-context.js';
14
+ export * from './http/impl/multipart-reader.js';
15
+ export * from './http/interfaces/http-incoming.interface.js';
16
+ export * from './http/interfaces/http-outgoing.interface.js';
17
+ export * from './http/interfaces/node-incoming-message.interface.js';
18
+ export * from './http/interfaces/node-outgoing-message.interface.js';
19
+ export * from './http/utils/wrap-exception.js';
27
20
  export * from './interfaces/logger.interface.js';
28
- export * from './interfaces/request-handler.interface.js';
29
- export * from './services/logger.js';
30
- export * from './services/api-service.js';
21
+ export * from './platform-adapter.js';
22
+ export * from './type-guards.js';
23
+ export var classes;
24
+ (function (classes) {
25
+ classes.HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
26
+ classes.HttpOutgoingHost = HttpOutgoingHost_.HttpOutgoingHost;
27
+ classes.NodeIncomingMessageHost = NodeIncomingMessageHost_.NodeIncomingMessageHost;
28
+ classes.NodeOutgoingMessageHost = NodeOutgoingMessageHost_.NodeOutgoingMessageHost;
29
+ })(classes || (classes = {}));
@@ -1 +1,19 @@
1
- export {};
1
+ import './augmentation/18n.augmentation.js';
2
+ import { I18n } from '@opra/common';
3
+ import { AsyncEventEmitter } from 'strict-typed-events';
4
+ import { kAssetCache } from './constants.js';
5
+ import { Logger } from './helpers/logger.js';
6
+ import { AssetCache } from './http/impl/asset-cache.js';
7
+ /**
8
+ * @class PlatformAdapter
9
+ */
10
+ export class PlatformAdapter extends AsyncEventEmitter {
11
+ constructor(document, options) {
12
+ super();
13
+ this[kAssetCache] = new AssetCache();
14
+ this.document = document;
15
+ this.logger =
16
+ options?.logger && options.logger instanceof Logger ? options.logger : new Logger({ instance: options?.logger });
17
+ this.i18n = options?.i18n || I18n.defaultInstance;
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ import { isReadable, isStream } from '@opra/common';
2
+ export function isNodeIncomingMessage(v) {
3
+ return v && typeof v.method === 'string' && Array.isArray(v.rawHeaders) && isReadable(v);
4
+ }
5
+ export function isHttpIncoming(v) {
6
+ return (isNodeIncomingMessage(v) &&
7
+ typeof v.header === 'function' &&
8
+ typeof v.acceptsLanguages === 'function' &&
9
+ typeof v.readBody === 'function');
10
+ }
11
+ export function isNodeOutgoingMessage(v) {
12
+ return v && typeof v.getHeaders === 'function' && isStream(v);
13
+ }
14
+ export function isHttpOutgoing(v) {
15
+ return isNodeOutgoingMessage(v) && typeof v.clearCookie === 'function' && typeof v.cookie === 'function';
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/core",
3
- "version": "0.33.13",
3
+ "version": "1.0.0-alpha.10",
4
4
  "description": "Opra schema package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -19,8 +19,11 @@
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
- "test": "jest",
23
- "cover": "jest --collect-coverage",
22
+ "lint:fix": "eslint . --max-warnings=0 --fix",
23
+ "format": "prettier . --write --log-level=warn",
24
+ "check": "madge --circular src/**",
25
+ "test": "jest --passWithNoTests",
26
+ "cover": "jest --passWithNoTests --collect-coverage",
24
27
  "clean": "npm run clean:src && npm run clean:test && npm run clean:dist && npm run clean:cover",
25
28
  "clean:src": "ts-cleanup -s src --all",
26
29
  "clean:test": "ts-cleanup -s test --all",
@@ -28,45 +31,60 @@
28
31
  "clean:cover": "rimraf ../../coverage/client"
29
32
  },
30
33
  "dependencies": {
31
- "@browsery/type-is": "^0.6.3",
32
- "@opra/common": "^0.33.13",
34
+ "@browsery/http-parser": "^0.5.8",
35
+ "@browsery/type-is": "^1.6.18-r2",
36
+ "@opra/common": "^1.0.0-alpha.10",
33
37
  "@types/formidable": "^3.4.5",
34
38
  "accepts": "^1.3.8",
39
+ "base64-stream": "^1.0.0",
40
+ "bytes": "^3.1.2",
35
41
  "content-disposition": "^0.5.4",
36
42
  "content-type": "^1.0.5",
37
43
  "cookie": "^0.6.0",
38
44
  "cookie-signature": "^1.2.1",
39
- "encodeurl": "^1.0.2",
45
+ "cppzst": "^2.0.12",
46
+ "encodeurl": "^2.0.0",
40
47
  "formidable": "^3.5.1",
41
48
  "fresh": "^0.5.2",
49
+ "iconv-lite": "^0.6.3",
42
50
  "mime-types": "^2.1.35",
43
- "power-tasks": "^1.7.3",
51
+ "power-tasks": "^1.7.4",
44
52
  "putil-isplainobject": "^1.1.5",
53
+ "putil-merge": "^3.12.1",
45
54
  "putil-varhelpers": "^1.6.5",
46
55
  "range-parser": "^1.2.1",
56
+ "raw-body": "^2.5.2",
57
+ "reflect-metadata": "^0.2.2",
47
58
  "strict-typed-events": "^2.3.3",
48
59
  "vary": "^1.1.2"
49
60
  },
50
- "peerDependencies": {
51
- "express": "^4.x.x || ^5.x.x"
61
+ "optionalDependencies": {
62
+ "express": "^4.x.x || ^5.x.x",
63
+ "fastify": "^4.x.x"
52
64
  },
53
65
  "devDependencies": {
54
- "@faker-js/faker": "^8.4.0",
66
+ "@faker-js/faker": "^8.4.1",
55
67
  "@types/accepts": "^1.3.7",
68
+ "@types/base64-stream": "^1.0.5",
69
+ "@types/bytes": "^3.1.4",
56
70
  "@types/content-disposition": "^0.5.8",
57
71
  "@types/content-type": "^1.1.8",
58
72
  "@types/cookie": "^0.6.0",
73
+ "@types/cookie-parser": "^1.4.7",
59
74
  "@types/cookie-signature": "^1.1.2",
60
75
  "@types/encodeurl": "^1.0.2",
61
76
  "@types/express": "^4.17.21",
62
77
  "@types/fresh": "^0.5.2",
63
78
  "@types/mime-types": "^2.1.4",
64
79
  "@types/range-parser": "^1.2.7",
65
- "@types/type-is": "^1.6.6",
66
80
  "@types/vary": "^1.1.3",
81
+ "cookie-parser": "^1.4.6",
67
82
  "crypto-browserify": "^3.12.0",
83
+ "express": "^4.19.2",
84
+ "fastify": "^4.28.1",
68
85
  "path-browserify": "^1.0.1",
69
- "ts-gems": "^3.1.1"
86
+ "supertest": "^7.0.0",
87
+ "ts-gems": "^3.4.0"
70
88
  },
71
89
  "type": "module",
72
90
  "module": "./esm/index.js",
@@ -95,4 +113,4 @@
95
113
  "swagger",
96
114
  "raml"
97
115
  ]
98
- }
116
+ }
@@ -1,7 +1,37 @@
1
- declare module "@opra/common" {
1
+ declare module '@opra/common' {
2
2
  interface I18n {
3
3
  loadResourceDir(dirnames: string | string[], deep?: boolean, overwrite?: boolean): Promise<void>;
4
4
  loadResourceBundle(lang: string, ns: string, filePath: string, deep?: boolean, overwrite?: boolean): Promise<void>;
5
5
  }
6
+ namespace I18n {
7
+ function load(): Promise<I18n>;
8
+ interface Options {
9
+ /**
10
+ * Language to use
11
+ * @default undefined
12
+ */
13
+ lng?: string;
14
+ /**
15
+ * Language to use if translations in user language are not available.
16
+ * @default 'dev'
17
+ */
18
+ fallbackLng?: false | FallbackLng;
19
+ /**
20
+ * Default namespace used if not passed to translation function
21
+ * @default 'translation'
22
+ */
23
+ defaultNS?: string;
24
+ /**
25
+ * Resources to initialize with
26
+ * @default undefined
27
+ */
28
+ resources?: LanguageResource;
29
+ /**
30
+ * Resource directories to initialize with (if not using loading or not appending using addResourceBundle)
31
+ * @default undefined
32
+ */
33
+ resourceDirs?: string[];
34
+ }
35
+ }
6
36
  }
7
37
  export {};
@@ -0,0 +1,21 @@
1
+ import type { HttpContext } from '../http/http-context';
2
+ declare module '@opra/common' {
3
+ interface HttpControllerStatic {
4
+ OnInit(): PropertyDecorator;
5
+ OnShutdown(): PropertyDecorator;
6
+ }
7
+ interface HttpController {
8
+ onInit?: (resource: HttpController) => void;
9
+ onShutdown?: (resource: HttpController) => void | Promise<void>;
10
+ }
11
+ namespace HttpController {
12
+ interface InitArguments {
13
+ onInit?: (resource: HttpController) => void;
14
+ onShutdown?: (resource: HttpController) => void | Promise<void>;
15
+ }
16
+ }
17
+ namespace HttpOperation {
18
+ interface Context extends HttpContext {
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,2 @@
1
+ export declare const kHandler: unique symbol;
2
+ export declare const kAssetCache: unique symbol;
@@ -1,30 +1,26 @@
1
- import type { HttpServerRequest } from './http/http-server-request.js';
2
- import type { HttpServerResponse } from './http/http-server-response.js';
3
- import type { Protocol } from './platform-adapter.js';
4
- export interface ExecutionContext {
5
- readonly protocol: Protocol;
6
- readonly platform: string;
7
- switchToHttp(): HttpMessageContext;
8
- switchToWs(): WsMessageContext;
9
- switchToRpc(): RpcMessageContext;
10
- on(event: 'finish', fn: (args: ExecutionContext.OnFinishArgs) => void | Promise<void>): any;
11
- }
1
+ import { ApiDocument, OpraSchema } from '@opra/common';
2
+ import { AsyncEventEmitter } from 'strict-typed-events';
3
+ /**
4
+ * @namespace ExecutionContext
5
+ */
12
6
  export declare namespace ExecutionContext {
13
- type OnFinishArgs = {
14
- context: ExecutionContext;
15
- failed: boolean;
16
- };
17
- function is(v: any): boolean;
7
+ interface Initiator {
8
+ document: ApiDocument;
9
+ protocol: OpraSchema.Protocol;
10
+ platform: string;
11
+ }
12
+ type OnFinishListener = (error: Error | undefined, context: ExecutionContext) => void | Promise<void>;
18
13
  }
19
- export interface HttpMessageContext {
14
+ /**
15
+ * @class ExecutionContext
16
+ */
17
+ export declare abstract class ExecutionContext extends AsyncEventEmitter {
18
+ readonly document: ApiDocument;
19
+ readonly protocol: OpraSchema.Protocol;
20
20
  readonly platform: string;
21
- readonly incoming: HttpServerRequest;
22
- readonly outgoing: HttpServerResponse;
23
- switchToContext(): ExecutionContext;
24
- }
25
- export interface WsMessageContext {
26
- switchToContext(): ExecutionContext;
27
- }
28
- export interface RpcMessageContext {
29
- switchToContext(): ExecutionContext;
21
+ protected constructor(init: ExecutionContext.Initiator);
22
+ addListener(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
23
+ removeListener(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
24
+ on(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
25
+ off(event: 'finish', listener: ExecutionContext.OnFinishListener): this;
30
26
  }
@@ -0,0 +1,10 @@
1
+ import { Nullish } from 'ts-gems';
2
+ import type { HttpContext } from '../http/http-context';
3
+ export declare abstract class ServiceBase {
4
+ protected _context: HttpContext;
5
+ get context(): HttpContext;
6
+ for<C extends HttpContext, P extends Partial<this>>(context: C, overwriteProperties?: Nullish<P>, overwriteContext?: Partial<C>): this & Required<P>;
7
+ }
8
+ export declare namespace ServiceBase {
9
+ const extendSymbol: unique symbol;
10
+ }
@@ -0,0 +1,13 @@
1
+ import { ApiDocument, HttpController } from '@opra/common';
2
+ import { Application } from 'express';
3
+ import { HttpAdapter } from './http-adapter.js';
4
+ export declare class ExpressAdapter extends HttpAdapter {
5
+ readonly app: Application;
6
+ protected _controllerInstances: Map<HttpController, any>;
7
+ constructor(app: Application, document: ApiDocument, options?: HttpAdapter.Options);
8
+ get platform(): string;
9
+ close(): Promise<void>;
10
+ getControllerInstance<T>(controllerPath: string): T | undefined;
11
+ protected _initRouter(basePath?: string): void;
12
+ protected _createControllers(controller: HttpController): void;
13
+ }