@opra/core 0.20.3 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/cjs/adapter/adapter.js +2 -2
  2. package/cjs/adapter/http/express-adapter.js +29 -7
  3. package/cjs/adapter/http/helpers/common.js +66 -0
  4. package/cjs/adapter/http/helpers/convert-to-headers.js +65 -0
  5. package/cjs/adapter/http/helpers/convert-to-raw-headers.js +25 -0
  6. package/cjs/adapter/http/helpers/match-known-fields.js +47 -0
  7. package/cjs/adapter/http/http-adapter.js +76 -438
  8. package/cjs/adapter/http/impl/http-incoming-message-host.js +127 -0
  9. package/cjs/adapter/http/impl/http-outgoing-message-host.js +210 -0
  10. package/cjs/adapter/http/impl/http-server-request.js +125 -0
  11. package/cjs/adapter/http/impl/http-server-response.js +226 -0
  12. package/cjs/adapter/http/request-parsers/batch-request-parser.js +169 -0
  13. package/cjs/adapter/http/request-parsers/parse-collection-request.js +165 -0
  14. package/cjs/adapter/http/request-parsers/parse-request.js +24 -0
  15. package/cjs/adapter/http/request-parsers/parse-singleton-request.js +96 -0
  16. package/cjs/adapter/request-context.host.js +17 -3
  17. package/cjs/adapter/request.host.js +6 -3
  18. package/cjs/adapter/response.host.js +5 -3
  19. package/cjs/index.js +4 -2
  20. package/esm/adapter/adapter.js +2 -2
  21. package/esm/adapter/http/express-adapter.js +6 -6
  22. package/esm/adapter/http/helpers/common.js +60 -0
  23. package/esm/adapter/http/helpers/convert-to-headers.js +60 -0
  24. package/esm/adapter/http/helpers/convert-to-raw-headers.js +21 -0
  25. package/esm/adapter/http/helpers/match-known-fields.js +43 -0
  26. package/esm/adapter/http/http-adapter.js +77 -439
  27. package/esm/adapter/http/impl/http-incoming-message-host.js +122 -0
  28. package/esm/adapter/http/impl/http-outgoing-message-host.js +205 -0
  29. package/esm/adapter/http/impl/http-server-request.js +121 -0
  30. package/esm/adapter/http/impl/http-server-response.js +222 -0
  31. package/esm/adapter/http/request-parsers/batch-request-parser.js +169 -0
  32. package/esm/adapter/http/request-parsers/parse-collection-request.js +161 -0
  33. package/esm/adapter/http/request-parsers/parse-request.js +20 -0
  34. package/esm/adapter/http/request-parsers/parse-singleton-request.js +92 -0
  35. package/esm/adapter/request-context.host.js +17 -3
  36. package/esm/adapter/request.host.js +6 -3
  37. package/esm/adapter/response.host.js +5 -3
  38. package/esm/index.js +4 -2
  39. package/package.json +20 -16
  40. package/types/adapter/adapter.d.ts +1 -1
  41. package/types/adapter/http/helpers/common.d.ts +17 -0
  42. package/types/adapter/http/helpers/convert-to-headers.d.ts +2 -0
  43. package/types/adapter/http/helpers/convert-to-raw-headers.d.ts +3 -0
  44. package/types/adapter/http/helpers/match-known-fields.d.ts +6 -0
  45. package/types/adapter/http/http-adapter.d.ts +7 -12
  46. package/types/adapter/http/impl/http-incoming-message-host.d.ts +58 -0
  47. package/types/adapter/http/impl/http-outgoing-message-host.d.ts +72 -0
  48. package/types/adapter/http/{http-request-message.d.ts → impl/http-server-request.d.ts} +52 -85
  49. package/types/adapter/http/impl/http-server-response.d.ts +137 -0
  50. package/types/adapter/http/request-parsers/batch-request-parser.d.ts +0 -0
  51. package/types/adapter/http/request-parsers/parse-collection-request.d.ts +4 -0
  52. package/types/adapter/http/request-parsers/parse-request.d.ts +4 -0
  53. package/types/adapter/http/request-parsers/parse-singleton-request.d.ts +4 -0
  54. package/types/adapter/interfaces/request-context.interface.d.ts +14 -10
  55. package/types/adapter/interfaces/request.interface.d.ts +3 -2
  56. package/types/adapter/interfaces/response.interface.d.ts +2 -2
  57. package/types/adapter/request-context.host.d.ts +9 -6
  58. package/types/adapter/request.host.d.ts +8 -4
  59. package/types/adapter/response.host.d.ts +6 -4
  60. package/types/index.d.ts +4 -2
  61. package/cjs/adapter/http/http-message.host.js +0 -251
  62. package/cjs/adapter/http/http-request-context.host.js +0 -28
  63. package/cjs/adapter/http/http-request-message.js +0 -152
  64. package/cjs/adapter/http/http-request.host.js +0 -14
  65. package/cjs/adapter/http/http-response-message.js +0 -238
  66. package/cjs/adapter/http/http-response.host.js +0 -14
  67. package/esm/adapter/http/http-message.host.js +0 -246
  68. package/esm/adapter/http/http-request-context.host.js +0 -24
  69. package/esm/adapter/http/http-request-message.js +0 -148
  70. package/esm/adapter/http/http-request.host.js +0 -10
  71. package/esm/adapter/http/http-response-message.js +0 -233
  72. package/esm/adapter/http/http-response.host.js +0 -10
  73. package/types/adapter/http/http-message.host.d.ts +0 -122
  74. package/types/adapter/http/http-request-context.host.d.ts +0 -16
  75. package/types/adapter/http/http-request.host.d.ts +0 -7
  76. package/types/adapter/http/http-response-message.d.ts +0 -321
  77. package/types/adapter/http/http-response.host.d.ts +0 -7
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ // async parseMultiPart(
3
+ // context: TExecutionContext,
4
+ // url: OpraURL,
5
+ // headers: IncomingHttpHeaders,
6
+ // input: Readable,
7
+ // boundary: string
8
+ // ): Promise<BatchRequestContext> {
9
+ // return await new Promise((resolve, reject) => {
10
+ // let _resolved = false;
11
+ // const dicer = new Dicer({boundary});
12
+ // const doReject = (e) => {
13
+ // if (_resolved) return;
14
+ // _resolved = true;
15
+ // reject(e);
16
+ // taskQueue.clearQueue();
17
+ // dicer.destroy();
18
+ // }
19
+ // const taskQueue = new TaskQueue({concurrency: 1});
20
+ // taskQueue.on('error', doReject);
21
+ //
22
+ // const queries: SingleRequestContext[] = [];
23
+ // let partCounter = 0;
24
+ // dicer.on('error', doReject);
25
+ // dicer.on('part', part => {
26
+ // const partIndex = partCounter++;
27
+ // let header: any;
28
+ // const chunks: Buffer[] = [];
29
+ // part.on('error', doReject);
30
+ // part.on('header', (_header) => header = normalizeHeaders(_header));
31
+ // part.on('data', (chunk: Buffer) => chunks.push(chunk));
32
+ // part.on('end', () => {
33
+ // if (_resolved || !(header || chunks.length))
34
+ // return;
35
+ // const ct = header['content-type'];
36
+ // if (ct === 'application/http') {
37
+ // taskQueue.enqueue(async () => {
38
+ // const data = Buffer.concat(chunks);
39
+ // if (!(data && data.length))
40
+ // return;
41
+ // const r = HttpRequest.parse(data);
42
+ // await callMiddlewares(r, [jsonBodyParser]);
43
+ // const subUrl = new OpraURL(r.url);
44
+ // const contentId = header && header['content-id'];
45
+ // queries.push(this.parseSingleQuery({
46
+ // context,
47
+ // url: subUrl,
48
+ // method: r.method,
49
+ // headers: r.headers,
50
+ // body: r.body,
51
+ // contentId
52
+ // }));
53
+ // });
54
+ // } else doReject(new BadRequestError({
55
+ // message: 'Unaccepted "content-type" header in multipart data',
56
+ // details: {
57
+ // position: `${boundary}[${partIndex}]`
58
+ // }
59
+ // }))
60
+ // });
61
+ // });
62
+ // dicer.on('finish', () => {
63
+ // taskQueue.enqueue(() => {
64
+ // if (_resolved) return;
65
+ // _resolved = true;
66
+ // const batch = new BatchRequestContext({
67
+ // service: this.document,
68
+ // context,
69
+ // headers,
70
+ // queries,
71
+ // params: url.searchParams,
72
+ // continueOnError: false
73
+ // });
74
+ // resolve(batch);
75
+ // });
76
+ // });
77
+ // input.pipe(dicer);
78
+ // });
79
+ // }
80
+ // protected async sendBatchResponse(context: TExecutionContext, requestContext: BatchRequestContext) {
81
+ // const resp = context.getResponse();
82
+ // resp.setStatus(HttpStatus.OK);
83
+ // resp.setHeader(HttpHeaderCodes.Cache_Control, 'no-cache');
84
+ // resp.setHeader(HttpHeaderCodes.Pragma, 'no-cache');
85
+ // resp.setHeader(HttpHeaderCodes.Expires, '-1');
86
+ // if (requestContext.headers) {
87
+ // for (const [k, v] of Object.entries(requestContext.headers)) {
88
+ // if (v)
89
+ // resp.setHeader(k, v);
90
+ // }
91
+ // }
92
+ // const boundary = 'batch_' + uuid();
93
+ // resp.setHeader(HttpHeaderCodes.Content_Type, 'multipart/mixed;boundary=' + boundary);
94
+ // resp.setHeader(HttpHeaderCodes.X_Opra_Version, OpraSchema.Version);
95
+ //
96
+ // const bodyBuilder = new HttpMultipartData();
97
+ //
98
+ // const chunks: any[] = [];
99
+ // let msgIdx = 0;
100
+ // for (const ctx of requestContext.queries) {
101
+ // msgIdx++;
102
+ // const out = this.createOutput(ctx);
103
+ //
104
+ //
105
+ // // chunks.push('--' + boundary + CRLF);
106
+ // // let s = 'Content-Type: application/http' + CRLF +
107
+ // // 'Content-Transfer-Encoding: binary' + CRLF +
108
+ // // 'Content-ID:' + (ctx.contentId || msgIdx) + CRLF +
109
+ // // CRLF +
110
+ // // 'HTTP/1.1 ' + out.status + (HttpStatus[out.status] || 'Unknown') + CRLF;
111
+ //
112
+ // let body = out.body;
113
+ // const headers = out.headers || {};
114
+ // if (body) {
115
+ // const contentType = String(headers['content-type'] || '').split(/\s*;\s*/);
116
+ // let charset = '';
117
+ // if (Highland.isStream(body)) {
118
+ // const l = parseInt(String(headers['content-length']), 10);
119
+ // if (isNaN(l))
120
+ // throw new TypeError('"content-length" header required for streamed responses');
121
+ // } else if (typeof body === 'object') {
122
+ // if (typeof body.stream === 'function') { // File and Blob
123
+ // contentType[0] = body.type || 'binary';
124
+ // headers['content-length'] = String(body.size);
125
+ // body = body.stream();
126
+ // } else if (Buffer.isBuffer(body)) {
127
+ // headers['content-length'] = String(body.length);
128
+ // } else {
129
+ // contentType[0] = contentType[0] || 'application/json';
130
+ // charset = 'utf-8';
131
+ // body = Buffer.from(JSON.stringify(body), 'utf-8');
132
+ // headers['content-length'] = String(body.length);
133
+ // }
134
+ // } else {
135
+ // contentType[0] = contentType[0] || 'text/plain';
136
+ // charset = 'utf-8';
137
+ // body = Buffer.from(String(body), 'utf-8');
138
+ // headers['content-length'] = String(body.length);
139
+ // }
140
+ // if (contentType[0]) {
141
+ // if (charset) {
142
+ // const i = contentType.findIndex(x => CHARSET_PATTERN.test(String(x)));
143
+ // if (i > 0) contentType[i] = 'charset=' + charset;
144
+ // else contentType.join('charset=' + charset);
145
+ // }
146
+ // headers['content-type'] = contentType.join(';');
147
+ // }
148
+ // }
149
+ // for (const [k, v] of Object.entries(headers))
150
+ // s += k + ': ' + (Array.isArray(v) ? v.join(';') : v) + CRLF
151
+ //
152
+ // chunks.push(s + CRLF);
153
+ //
154
+ // if (body) {
155
+ // if (typeof body === 'string')
156
+ // chunks.push(body + CRLF + CRLF);
157
+ // else {
158
+ // chunks.push(body);
159
+ // chunks.push(CRLF + CRLF);
160
+ // }
161
+ // }
162
+ // }
163
+ //
164
+ // chunks.push('--' + boundary + '--' + CRLF);
165
+ //
166
+ // resp.setHeader('content-type', 'multipart/mixed;boundary=' + boundary);
167
+ // resp.send(Highland(chunks).flatten());
168
+ // resp.end();
169
+ // }
@@ -0,0 +1,161 @@
1
+ import { BadRequestError, MethodNotAllowedError } from '@opra/common';
2
+ import { RequestHost } from '../../request.host.js';
3
+ export async function parseCollectionRequest(incoming, resource, url) {
4
+ if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
5
+ incoming.headers['content-type'] !== 'application/json')
6
+ throw new BadRequestError({ message: 'Unsupported Content-Type' });
7
+ url.searchParams.define({
8
+ '$search': { codec: 'string' },
9
+ '$pick': { codec: 'string', array: 'strict' },
10
+ '$omit': { codec: 'string', array: 'strict' },
11
+ '$include': { codec: 'string', array: 'strict' },
12
+ '$sort': { codec: 'string', array: 'strict' },
13
+ '$filter': { codec: 'filter' },
14
+ '$limit': { codec: 'number' },
15
+ '$skip': { codec: 'number' },
16
+ '$distinct': { codec: 'boolean' },
17
+ '$count': { codec: 'boolean' },
18
+ });
19
+ url.parse(incoming.url || '');
20
+ const contentId = incoming.headers['content-id'];
21
+ const p = url.path.get(0);
22
+ const params = url.searchParams;
23
+ switch (incoming.method) {
24
+ case 'POST': {
25
+ if (!p.key) {
26
+ const pick = params.get('$pick');
27
+ const omit = params.get('$omit');
28
+ const include = params.get('$include');
29
+ return new RequestHost({
30
+ http: incoming,
31
+ kind: 'CollectionCreateRequest',
32
+ contentId,
33
+ resource,
34
+ operation: 'create',
35
+ crud: 'create',
36
+ many: false,
37
+ args: {
38
+ data: incoming.body,
39
+ pick: pick && resource.normalizeFieldPath(pick),
40
+ omit: omit && resource.normalizeFieldPath(omit),
41
+ include: include && resource.normalizeFieldPath(include)
42
+ }
43
+ });
44
+ }
45
+ break;
46
+ }
47
+ case 'DELETE': {
48
+ if (p.key) {
49
+ return new RequestHost({
50
+ http: incoming,
51
+ kind: 'CollectionDeleteRequest',
52
+ contentId,
53
+ resource,
54
+ operation: 'delete',
55
+ crud: 'delete',
56
+ many: false,
57
+ args: {
58
+ key: resource.parseKeyValue(p.key)
59
+ }
60
+ });
61
+ }
62
+ const filter = resource.normalizeFilter(params.get('$filter'));
63
+ return new RequestHost({
64
+ http: incoming,
65
+ kind: 'CollectionDeleteManyRequest',
66
+ contentId,
67
+ resource,
68
+ operation: 'deleteMany',
69
+ crud: 'delete',
70
+ many: true,
71
+ args: {
72
+ filter
73
+ }
74
+ });
75
+ }
76
+ case 'GET': {
77
+ const pick = params.get('$pick');
78
+ const omit = params.get('$omit');
79
+ const include = params.get('$include');
80
+ if (p.key) {
81
+ return new RequestHost({
82
+ http: incoming,
83
+ kind: 'CollectionGetRequest',
84
+ contentId,
85
+ resource,
86
+ operation: 'get',
87
+ crud: 'read',
88
+ many: false,
89
+ args: {
90
+ key: resource.parseKeyValue(p.key),
91
+ pick: pick && resource.normalizeFieldPath(pick),
92
+ omit: omit && resource.normalizeFieldPath(omit),
93
+ include: include && resource.normalizeFieldPath(include)
94
+ }
95
+ });
96
+ }
97
+ const filter = resource.normalizeFilter(params.get('$filter'));
98
+ const sort = params.get('$sort');
99
+ return new RequestHost({
100
+ http: incoming,
101
+ kind: 'CollectionFindManyRequest',
102
+ contentId,
103
+ resource,
104
+ operation: 'findMany',
105
+ crud: 'read',
106
+ many: true,
107
+ args: {
108
+ pick: pick && resource.normalizeFieldPath(pick),
109
+ omit: omit && resource.normalizeFieldPath(omit),
110
+ include: include && resource.normalizeFieldPath(include),
111
+ sort: sort && resource.normalizeSortFields(sort),
112
+ filter,
113
+ limit: params.get('$limit'),
114
+ skip: params.get('$skip'),
115
+ distinct: params.get('$distinct'),
116
+ count: params.get('$count'),
117
+ }
118
+ });
119
+ }
120
+ case 'PATCH': {
121
+ if (p.key) {
122
+ const pick = params.get('$pick');
123
+ const omit = params.get('$omit');
124
+ const include = params.get('$include');
125
+ return new RequestHost({
126
+ http: incoming,
127
+ kind: 'CollectionUpdateRequest',
128
+ contentId,
129
+ resource,
130
+ operation: 'update',
131
+ crud: 'update',
132
+ many: false,
133
+ args: {
134
+ key: resource.parseKeyValue(p.key),
135
+ data: incoming.body,
136
+ pick: pick && resource.normalizeFieldPath(pick),
137
+ omit: omit && resource.normalizeFieldPath(omit),
138
+ include: include && resource.normalizeFieldPath(include),
139
+ }
140
+ });
141
+ }
142
+ const filter = resource.normalizeFilter(params.get('$filter'));
143
+ return new RequestHost({
144
+ http: incoming,
145
+ kind: 'CollectionUpdateManyRequest',
146
+ contentId,
147
+ resource,
148
+ operation: 'updateMany',
149
+ crud: 'update',
150
+ many: true,
151
+ args: {
152
+ data: incoming.body,
153
+ filter,
154
+ }
155
+ });
156
+ }
157
+ }
158
+ throw new MethodNotAllowedError({
159
+ message: `Collection resource does not accept http "${incoming.method}" method`
160
+ });
161
+ }
@@ -0,0 +1,20 @@
1
+ import { BadRequestError, Collection, OpraURL, Singleton } from '@opra/common';
2
+ import { parseCollectionRequest } from './parse-collection-request.js';
3
+ import { parseSingletonRequest } from './parse-singleton-request.js';
4
+ export async function parseRequest(api, incoming) {
5
+ const url = new OpraURL(incoming.url);
6
+ if (!url.path.size) {
7
+ // Batch
8
+ if (incoming.headers['content-type'] === 'multipart/mixed') {
9
+ // todo
10
+ }
11
+ throw new BadRequestError();
12
+ }
13
+ const p = url.path.get(0);
14
+ const resource = api.getResource(p.resource);
15
+ if (resource instanceof Collection)
16
+ return await parseCollectionRequest(incoming, resource, url);
17
+ if (resource instanceof Singleton)
18
+ return await parseSingletonRequest(incoming, resource, url);
19
+ throw new BadRequestError();
20
+ }
@@ -0,0 +1,92 @@
1
+ import { BadRequestError, MethodNotAllowedError } from '@opra/common';
2
+ import { RequestHost } from '../../request.host.js';
3
+ export async function parseSingletonRequest(incoming, resource, url) {
4
+ if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
5
+ incoming.headers['content-type'] !== 'application/json')
6
+ throw new BadRequestError({ message: 'Unsupported Content-Type' });
7
+ url.searchParams.define({
8
+ '$pick': { codec: 'string', array: 'strict' },
9
+ '$omit': { codec: 'string', array: 'strict' },
10
+ '$include': { codec: 'string', array: 'strict' }
11
+ });
12
+ url.parse(incoming.url || '');
13
+ const contentId = incoming.headers['content-id'];
14
+ const params = url.searchParams;
15
+ switch (incoming.method) {
16
+ case 'POST': {
17
+ const pick = params.get('$pick');
18
+ const omit = params.get('$omit');
19
+ const include = params.get('$include');
20
+ return new RequestHost({
21
+ http: incoming,
22
+ kind: 'SingletonCreateRequest',
23
+ contentId,
24
+ resource,
25
+ operation: 'create',
26
+ crud: 'create',
27
+ many: false,
28
+ args: {
29
+ data: incoming.body,
30
+ pick: pick && resource.normalizeFieldPath(pick),
31
+ omit: omit && resource.normalizeFieldPath(omit),
32
+ include: include && resource.normalizeFieldPath(include),
33
+ }
34
+ });
35
+ }
36
+ case 'DELETE': {
37
+ return new RequestHost({
38
+ http: incoming,
39
+ kind: 'SingletonDeleteRequest',
40
+ contentId,
41
+ resource,
42
+ operation: 'delete',
43
+ crud: 'delete',
44
+ many: false,
45
+ args: {}
46
+ });
47
+ }
48
+ case 'GET': {
49
+ const pick = params.get('$pick');
50
+ const omit = params.get('$omit');
51
+ const include = params.get('$include');
52
+ return new RequestHost({
53
+ http: incoming,
54
+ kind: 'SingletonGetRequest',
55
+ contentId,
56
+ resource,
57
+ operation: 'get',
58
+ crud: 'read',
59
+ many: false,
60
+ args: {
61
+ pick: pick && resource.normalizeFieldPath(pick),
62
+ omit: omit && resource.normalizeFieldPath(omit),
63
+ include: include && resource.normalizeFieldPath(include),
64
+ }
65
+ });
66
+ }
67
+ case 'PATCH': {
68
+ const pick = params.get('$pick');
69
+ const omit = params.get('$omit');
70
+ const include = params.get('$include');
71
+ return new RequestHost({
72
+ http: incoming,
73
+ kind: 'SingletonUpdateRequest',
74
+ contentId,
75
+ resource,
76
+ operation: 'update',
77
+ crud: 'update',
78
+ many: false,
79
+ args: {
80
+ data: incoming.body,
81
+ pick: pick && resource.normalizeFieldPath(pick),
82
+ omit: omit && resource.normalizeFieldPath(omit),
83
+ include: include && resource.normalizeFieldPath(include),
84
+ }
85
+ });
86
+ }
87
+ default:
88
+ throw new MethodNotAllowedError({
89
+ message: `Singleton resource does not accept http "${incoming.method}" method`
90
+ });
91
+ }
92
+ }
@@ -7,6 +7,14 @@ export class RequestContextHost extends AsyncEventEmitter {
7
7
  this.api = api;
8
8
  this._request = _request;
9
9
  this._response = _response;
10
+ if (this.protocol === 'http') {
11
+ this._http = {
12
+ platform,
13
+ request: this._request.switchToHttp(),
14
+ response: this._response.switchToHttp(),
15
+ switchToContext: () => this
16
+ };
17
+ }
10
18
  }
11
19
  get request() {
12
20
  return this._request;
@@ -15,12 +23,18 @@ export class RequestContextHost extends AsyncEventEmitter {
15
23
  return this._response;
16
24
  }
17
25
  switchToHttp() {
18
- throw new TypeError('Not executing in an "Http" protocol');
26
+ if (this._http)
27
+ return this._http;
28
+ throw new TypeError('Not executing in an "Http" context');
19
29
  }
20
30
  switchToWs() {
21
- throw new TypeError('Not executing in an "WebSocket" protocol');
31
+ if (this._ws)
32
+ return this._ws;
33
+ throw new TypeError('Not executing in an "WebSocket" context');
22
34
  }
23
35
  switchToRpc() {
24
- throw new TypeError('Not executing in an "RPC" protocol');
36
+ if (this._rpc)
37
+ return this._rpc;
38
+ throw new TypeError('Not executing in an "RPC" context');
25
39
  }
26
40
  }
@@ -1,15 +1,18 @@
1
1
  export class RequestHost {
2
2
  constructor(init) {
3
+ this.contentId = '';
3
4
  Object.assign(this, init);
4
5
  this.resourceKind = this.resource.kind;
5
6
  }
6
7
  switchToHttp() {
7
- throw new TypeError('Not executing in an "Http" protocol');
8
+ if (this.http)
9
+ return this.http;
10
+ throw new TypeError('Not executing in an "Http" context');
8
11
  }
9
12
  switchToWs() {
10
- throw new TypeError('Not executing in an "WebSocket" protocol');
13
+ throw new TypeError('Not executing in an "WebSocket" context');
11
14
  }
12
15
  switchToRpc() {
13
- throw new TypeError('Not executing in an "RPC" protocol');
16
+ throw new TypeError('Not executing in an "RPC" context');
14
17
  }
15
18
  }
@@ -5,12 +5,14 @@ export class ResponseHost {
5
5
  this.errors = this.errors || [];
6
6
  }
7
7
  switchToHttp() {
8
- throw new TypeError('Not executing in an "Http" protocol');
8
+ if (this.http)
9
+ return this.http;
10
+ throw new TypeError('Not executing in an "Http" context');
9
11
  }
10
12
  switchToWs() {
11
- throw new TypeError('Not executing in an "WebSocket" protocol');
13
+ throw new TypeError('Not executing in an "WebSocket" context');
12
14
  }
13
15
  switchToRpc() {
14
- throw new TypeError('Not executing in an "RPC" protocol');
16
+ throw new TypeError('Not executing in an "RPC" context');
15
17
  }
16
18
  }
package/esm/index.js CHANGED
@@ -4,8 +4,10 @@ export * from './types.js';
4
4
  export * from './adapter/adapter.js';
5
5
  export * from './adapter/http/express-adapter.js';
6
6
  export * from './adapter/http/http-adapter.js';
7
- export * from './adapter/http/http-request-message.js';
8
- export * from './adapter/http/http-response-message.js';
7
+ export * from './adapter/http/impl/http-server-request.js';
8
+ export * from './adapter/http/impl/http-server-response.js';
9
+ export * from './adapter/http/impl/http-incoming-message-host.js';
10
+ export * from './adapter/http/impl/http-outgoing-message-host.js';
9
11
  export * from './adapter/interfaces/request-context.interface.js';
10
12
  export * from './adapter/interfaces/logger.interface.js';
11
13
  export * from './adapter/interfaces/request.interface.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/core",
3
- "version": "0.20.3",
3
+ "version": "0.21.0",
4
4
  "description": "Opra schema package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -27,23 +27,24 @@
27
27
  "clean:cover": "rimraf ../../coverage/core"
28
28
  },
29
29
  "dependencies": {
30
- "@opra/common": "^0.20.3",
30
+ "@opra/common": "^0.21.0",
31
31
  "accepts": "^1.3.8",
32
+ "cookie": "^0.5.0",
33
+ "cookie-signature": "^1.2.1",
32
34
  "content-disposition": "^0.5.4",
33
35
  "content-type": "^1.0.5",
34
- "cookie": "^0.5.0",
35
- "lodash.isnil": "^4.0.0",
36
- "lodash.omitby": "^4.6.0",
36
+ "encodeurl": "^1.0.2",
37
+ "fresh": "^0.5.2",
38
+ "formidable": "^3.5.0",
37
39
  "mime-types": "^2.1.35",
38
40
  "power-tasks": "^1.7.0",
39
- "putil-isplainobject": "^1.1.5",
40
- "putil-merge": "^3.10.3",
41
41
  "putil-varhelpers": "^1.6.5",
42
+ "range-parser": "^1.2.1",
42
43
  "strict-typed-events": "^2.3.1",
43
- "type-is": "^1.6.18"
44
+ "type-is": "^1.6.18",
45
+ "vary": "^1.1.2"
44
46
  },
45
47
  "peerDependencies": {
46
- "body-parser": "^1.20.2",
47
48
  "express": "^4.x.x || ^5.x.x"
48
49
  },
49
50
  "devDependencies": {
@@ -52,11 +53,15 @@
52
53
  "@types/content-disposition": "^0.5.5",
53
54
  "@types/content-type": "^1.1.5",
54
55
  "@types/cookie": "^0.5.1",
55
- "@types/dicer": "^0.2.2",
56
+ "@types/cookie-signature": "^1.1.0",
57
+ "@types/encodeurl": "^1.0.0",
58
+ "@types/fresh": "^0.5.0",
59
+ "@types/formidable": "^3.4.0",
56
60
  "@types/express": "^4.17.17",
57
61
  "@types/mime-types": "^2.1.1",
62
+ "@types/range-parser": "^1.2.4",
58
63
  "@types/type-is": "^1.6.3",
59
- "cors": "^2.8.5",
64
+ "@types/vary": "^1.1.0",
60
65
  "crypto-browserify": "^3.12.0",
61
66
  "path-browserify": "^1.0.1",
62
67
  "ts-gems": "^2.4.0"
@@ -88,11 +93,10 @@
88
93
  "opra",
89
94
  "rest",
90
95
  "api",
91
- "oas",
92
- "open",
93
- "swagger",
94
- "raml",
96
+ "openapi",
95
97
  "http",
96
- "web"
98
+ "web",
99
+ "swagger",
100
+ "raml"
97
101
  ]
98
102
  }
@@ -44,7 +44,7 @@ export declare namespace OpraAdapter {
44
44
  */
45
45
  export declare abstract class OpraAdapter extends AsyncEventEmitter {
46
46
  readonly api: ApiDocument;
47
- protected _internalDoc: ApiDocument;
47
+ protected _apiRoot: ApiDocument;
48
48
  i18n: I18n;
49
49
  logger?: ILogger;
50
50
  protected constructor(api: ApiDocument);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Verifies that the given val is a valid HTTP token
3
+ * per the rules defined in RFC 7230
4
+ * See https://tools.ietf.org/html/rfc7230#section-3.2.6
5
+ *
6
+ * https://github.com/nodejs/node/blob/main/lib/_http_common.js
7
+ */
8
+ export declare function checkIsHttpToken(val: any): boolean;
9
+ /**
10
+ * This function removes unnecessary frames from Node.js core errors.
11
+ *
12
+ * https://github.com/nodejs/node/blob/main/lib/internal/errors.js
13
+ */
14
+ export declare function hideStackFrames(fn: Function): Function;
15
+ export declare const validateHeaderName: Function;
16
+ export declare const validateHeaderValue: Function;
17
+ export declare function validateString(value: any, name?: string): void;
@@ -0,0 +1,2 @@
1
+ export declare function convertToHeaders<T>(src: string[], dst: T, joinDuplicateHeaders?: boolean): T;
2
+ export declare function convertToHeadersDistinct<T>(src: string[], dst: T): T;
@@ -0,0 +1,3 @@
1
+ /// <reference types="node" />
2
+ import { IncomingHttpHeaders } from 'http';
3
+ export declare function convertToRawHeaders(src: IncomingHttpHeaders | Record<string, any>): string[];
@@ -0,0 +1,6 @@
1
+ export declare const NO_DUPLICATES_FIELD = 0;
2
+ export declare const COMMA_DELIMITED_FIELD = 1;
3
+ export declare const SEMICOLON_DELIMITED_FIELD = 2;
4
+ export declare const ARRAY_FIELD = 3;
5
+ export type FIELD_FLAG = typeof NO_DUPLICATES_FIELD | typeof COMMA_DELIMITED_FIELD | typeof SEMICOLON_DELIMITED_FIELD | typeof ARRAY_FIELD;
6
+ export declare function matchKnownFields(field: string): [string, FIELD_FLAG];