@opra/http 1.21.0 → 1.22.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 (70) hide show
  1. package/{esm/express-adapter.js → express-adapter.js} +2 -1
  2. package/{esm/http-adapter.js → http-adapter.js} +5 -1
  3. package/{esm/http-context.js → http-context.js} +10 -1
  4. package/{esm/http-handler.js → http-handler.js} +3 -0
  5. package/{esm/impl → impl}/http-incoming.host.js +1 -0
  6. package/{esm/impl → impl}/multipart-reader.js +10 -5
  7. package/{esm/impl → impl}/node-incoming-message.host.js +15 -4
  8. package/{esm/impl → impl}/node-outgoing-message.host.js +7 -2
  9. package/package.json +14 -31
  10. package/{esm/utils → utils}/body-reader.js +10 -2
  11. package/cjs/express-adapter.js +0 -134
  12. package/cjs/http-adapter.js +0 -25
  13. package/cjs/http-context.js +0 -114
  14. package/cjs/http-handler.js +0 -668
  15. package/cjs/impl/http-incoming.host.js +0 -112
  16. package/cjs/impl/http-outgoing.host.js +0 -207
  17. package/cjs/impl/multipart-reader.js +0 -209
  18. package/cjs/impl/node-incoming-message.host.js +0 -115
  19. package/cjs/impl/node-outgoing-message.host.js +0 -201
  20. package/cjs/index.js +0 -27
  21. package/cjs/interfaces/http-incoming.interface.js +0 -25
  22. package/cjs/interfaces/http-outgoing.interface.js +0 -22
  23. package/cjs/interfaces/node-incoming-message.interface.js +0 -65
  24. package/cjs/interfaces/node-outgoing-message.interface.js +0 -15
  25. package/cjs/package.json +0 -3
  26. package/cjs/type-guards.js +0 -27
  27. package/cjs/utils/body-reader.js +0 -227
  28. package/cjs/utils/common.js +0 -67
  29. package/cjs/utils/concat-readable.js +0 -19
  30. package/cjs/utils/convert-to-headers.js +0 -64
  31. package/cjs/utils/convert-to-raw-headers.js +0 -25
  32. package/cjs/utils/match-known-fields.js +0 -49
  33. package/cjs/utils/wrap-exception.js +0 -33
  34. package/esm/package.json +0 -3
  35. package/types/index.d.cts +0 -22
  36. /package/{types/express-adapter.d.ts → express-adapter.d.ts} +0 -0
  37. /package/{types/http-adapter.d.ts → http-adapter.d.ts} +0 -0
  38. /package/{types/http-context.d.ts → http-context.d.ts} +0 -0
  39. /package/{types/http-handler.d.ts → http-handler.d.ts} +0 -0
  40. /package/{types/impl → impl}/http-incoming.host.d.ts +0 -0
  41. /package/{types/impl → impl}/http-outgoing.host.d.ts +0 -0
  42. /package/{esm/impl → impl}/http-outgoing.host.js +0 -0
  43. /package/{types/impl → impl}/multipart-reader.d.ts +0 -0
  44. /package/{types/impl → impl}/node-incoming-message.host.d.ts +0 -0
  45. /package/{types/impl → impl}/node-outgoing-message.host.d.ts +0 -0
  46. /package/{types/index.d.ts → index.d.ts} +0 -0
  47. /package/{esm/index.js → index.js} +0 -0
  48. /package/{types/interfaces → interfaces}/http-incoming.interface.d.ts +0 -0
  49. /package/{esm/interfaces → interfaces}/http-incoming.interface.js +0 -0
  50. /package/{types/interfaces → interfaces}/http-outgoing.interface.d.ts +0 -0
  51. /package/{esm/interfaces → interfaces}/http-outgoing.interface.js +0 -0
  52. /package/{types/interfaces → interfaces}/node-incoming-message.interface.d.ts +0 -0
  53. /package/{esm/interfaces → interfaces}/node-incoming-message.interface.js +0 -0
  54. /package/{types/interfaces → interfaces}/node-outgoing-message.interface.d.ts +0 -0
  55. /package/{esm/interfaces → interfaces}/node-outgoing-message.interface.js +0 -0
  56. /package/{types/type-guards.d.ts → type-guards.d.ts} +0 -0
  57. /package/{esm/type-guards.js → type-guards.js} +0 -0
  58. /package/{types/utils → utils}/body-reader.d.ts +0 -0
  59. /package/{types/utils → utils}/common.d.ts +0 -0
  60. /package/{esm/utils → utils}/common.js +0 -0
  61. /package/{types/utils → utils}/concat-readable.d.ts +0 -0
  62. /package/{esm/utils → utils}/concat-readable.js +0 -0
  63. /package/{types/utils → utils}/convert-to-headers.d.ts +0 -0
  64. /package/{esm/utils → utils}/convert-to-headers.js +0 -0
  65. /package/{types/utils → utils}/convert-to-raw-headers.d.ts +0 -0
  66. /package/{esm/utils → utils}/convert-to-raw-headers.js +0 -0
  67. /package/{types/utils → utils}/match-known-fields.d.ts +0 -0
  68. /package/{esm/utils → utils}/match-known-fields.js +0 -0
  69. /package/{types/utils → utils}/wrap-exception.d.ts +0 -0
  70. /package/{esm/utils → utils}/wrap-exception.js +0 -0
@@ -6,9 +6,10 @@ import { HttpContext } from './http-context.js';
6
6
  import { HttpIncoming } from './interfaces/http-incoming.interface.js';
7
7
  import { HttpOutgoing } from './interfaces/http-outgoing.interface.js';
8
8
  export class ExpressAdapter extends HttpAdapter {
9
+ app;
10
+ _controllerInstances = new Map();
9
11
  constructor(app, document, options) {
10
12
  super(options);
11
- this._controllerInstances = new Map();
12
13
  this.app = app;
13
14
  if (!(document.api instanceof HttpApi))
14
15
  throw new TypeError(`The document does not expose an HTTP Api`);
@@ -5,9 +5,13 @@ import { HttpHandler } from './http-handler.js';
5
5
  * @class HttpAdapter
6
6
  */
7
7
  export class HttpAdapter extends PlatformAdapter {
8
+ handler;
9
+ transform = 'http';
10
+ basePath;
11
+ scope;
12
+ interceptors;
8
13
  constructor(options) {
9
14
  super(options);
10
- this.transform = 'http';
11
15
  this.handler = new HttpHandler(this);
12
16
  this.interceptors = [...(options?.interceptors || [])];
13
17
  this.basePath = options?.basePath || '/';
@@ -3,6 +3,16 @@ import { InternalServerError, NotAcceptableError, } from '@opra/common';
3
3
  import { ExecutionContext, kAssetCache } from '@opra/core';
4
4
  import { MultipartReader } from './impl/multipart-reader.js';
5
5
  export class HttpContext extends ExecutionContext {
6
+ _body;
7
+ _multipartReader;
8
+ request;
9
+ response;
10
+ mediaType;
11
+ cookies;
12
+ headers;
13
+ pathParams;
14
+ queryParams;
15
+ errors = [];
6
16
  constructor(init) {
7
17
  super({
8
18
  ...init,
@@ -11,7 +21,6 @@ export class HttpContext extends ExecutionContext {
11
21
  init.__adapter.document.node,
12
22
  transport: 'http',
13
23
  });
14
- this.errors = [];
15
24
  if (init.__contDef)
16
25
  this.__contDef = init.__contDef;
17
26
  if (init.__controller)
@@ -12,6 +12,9 @@ import { wrapException } from './utils/wrap-exception.js';
12
12
  * @class HttpHandler
13
13
  */
14
14
  export class HttpHandler {
15
+ adapter;
16
+ [kAssetCache];
17
+ onError;
15
18
  constructor(adapter) {
16
19
  this.adapter = adapter;
17
20
  this[kAssetCache] = adapter[kAssetCache];
@@ -8,6 +8,7 @@ import fresh from 'fresh';
8
8
  import parseRange from 'range-parser';
9
9
  import { BodyReader } from '../utils/body-reader.js';
10
10
  export class HttpIncomingHost {
11
+ body;
11
12
  get protocol() {
12
13
  const proto = this.header('X-Forwarded-Proto') || 'http';
13
14
  const index = proto.indexOf(',');
@@ -9,15 +9,20 @@ import { EventEmitter } from 'events';
9
9
  import fsPromise from 'fs/promises';
10
10
  import { isNotNullish } from 'valgen';
11
11
  export class MultipartReader extends EventEmitter {
12
+ context;
13
+ mediaType;
14
+ _started = false;
15
+ _finished = false;
16
+ _cancelled = false;
17
+ _form;
18
+ _items = [];
19
+ _stack = [];
20
+ tempDirectory;
21
+ scope;
12
22
  constructor(context, options, mediaType) {
13
23
  super();
14
24
  this.context = context;
15
25
  this.mediaType = mediaType;
16
- this._started = false;
17
- this._finished = false;
18
- this._cancelled = false;
19
- this._items = [];
20
- this._stack = [];
21
26
  this.setMaxListeners(1000);
22
27
  this.tempDirectory = options?.tempDirectory || os.tmpdir();
23
28
  this.scope = options?.scope;
@@ -13,12 +13,23 @@ export const kHttpParser = Symbol.for('kHttpParser');
13
13
  * @class NodeIncomingMessageHost
14
14
  */
15
15
  export class NodeIncomingMessageHost extends Duplex {
16
+ [kHeaders];
17
+ [kHeadersDistinct];
18
+ [kTrailers];
19
+ [kTrailersDistinct];
20
+ [kHttpParser];
21
+ _readStream;
22
+ rawHeaders = [];
23
+ rawTrailers = [];
24
+ params;
25
+ cookies;
26
+ body;
27
+ complete = false;
28
+ ip;
29
+ ips;
30
+ joinDuplicateHeaders = false;
16
31
  constructor(init) {
17
32
  super();
18
- this.rawHeaders = [];
19
- this.rawTrailers = [];
20
- this.complete = false;
21
- this.joinDuplicateHeaders = false;
22
33
  if (init) {
23
34
  this.complete = true;
24
35
  this.httpVersionMajor = init.httpVersionMajor || 1;
@@ -12,10 +12,15 @@ export const kOutTrailers = Symbol.for('kOutTrailers');
12
12
  * @class NodeOutgoingMessageHost
13
13
  */
14
14
  export class NodeOutgoingMessageHost extends Duplex {
15
+ [kOutHeaders];
16
+ [kOutTrailers];
17
+ _headersSent = false;
18
+ _httpVersionMajor;
19
+ _httpVersionMinor;
20
+ finished = false;
21
+ body;
15
22
  constructor(init) {
16
23
  super();
17
- this._headersSent = false;
18
- this.finished = false;
19
24
  if (init) {
20
25
  this.req = init.req;
21
26
  this.statusCode = init?.statusCode || 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/http",
3
- "version": "1.21.0",
3
+ "version": "1.22.0",
4
4
  "description": "Opra Http Server Adapter",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -19,11 +19,11 @@
19
19
  "cookie-signature": "^1.2.2",
20
20
  "encodeurl": "^2.0.0",
21
21
  "expect": "^30.2.0",
22
- "fast-tokenizer": "^1.7.0",
22
+ "fast-tokenizer": "^1.8.0",
23
23
  "fresh": "^0.5.2",
24
- "iconv-lite": "^0.7.0",
24
+ "iconv-lite": "^0.7.1",
25
25
  "mime-types": "^3.0.2",
26
- "node-events-async": "^1.2.0",
26
+ "node-events-async": "^1.4.0",
27
27
  "power-tasks": "^1.11.1",
28
28
  "putil-varhelpers": "^1.6.5",
29
29
  "range-parser": "^1.2.1",
@@ -35,48 +35,31 @@
35
35
  "vary": "^1.1.2"
36
36
  },
37
37
  "peerDependencies": {
38
- "@opra/common": "^1.21.0",
39
- "@opra/core": "^1.21.0"
38
+ "@opra/common": "^1.22.0",
39
+ "@opra/core": "^1.22.0"
40
40
  },
41
41
  "optionalDependencies": {
42
42
  "express": "^4.0.0 || ^5.0.0",
43
43
  "fastify": "^4.0.0 || ^5.0.0"
44
44
  },
45
- "type": "module",
46
45
  "exports": {
47
46
  ".": {
48
- "import": {
49
- "types": "./types/index.d.ts",
50
- "default": "./esm/index.js"
51
- },
52
- "require": {
53
- "types": "./types/index.d.cts",
54
- "default": "./cjs/index.js"
55
- },
56
- "default": "./esm/index.js"
47
+ "types": "./index.d.ts",
48
+ "default": "./index.js"
57
49
  },
58
50
  "./package.json": "./package.json"
59
51
  },
60
- "main": "./cjs/index.js",
61
- "module": "./esm/index.js",
62
- "types": "./types/index.d.ts",
52
+ "type": "module",
53
+ "module": "./index.js",
54
+ "types": "./index.d.ts",
55
+ "engines": {
56
+ "node": ">=20.0"
57
+ },
63
58
  "repository": {
64
59
  "type": "git",
65
60
  "url": "git+https://github.com/panates/opra.git",
66
61
  "directory": "packages/http"
67
62
  },
68
- "engines": {
69
- "node": ">=16.0",
70
- "npm": ">=7.0.0"
71
- },
72
- "files": [
73
- "cjs/",
74
- "esm/",
75
- "i18n/",
76
- "types/",
77
- "LICENSE",
78
- "README.md"
79
- ],
80
63
  "keywords": [
81
64
  "opra",
82
65
  "rest",
@@ -12,11 +12,19 @@ import * as zlib from 'zlib';
12
12
  * @class BodyReader
13
13
  */
14
14
  export class BodyReader extends EventEmitter {
15
+ req;
16
+ limit;
17
+ _stream;
18
+ _buffer;
19
+ _completed = false;
20
+ _receivedSize = 0;
21
+ cleanup;
22
+ onAborted;
23
+ onData;
24
+ onEnd;
15
25
  constructor(req, options) {
16
26
  super();
17
27
  this.req = req;
18
- this._completed = false;
19
- this._receivedSize = 0;
20
28
  this.onAborted = () => this._onAborted();
21
29
  this.onData = (chunk) => this._onData(chunk);
22
30
  this.onEnd = (err) => this._onEnd(err);
@@ -1,134 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExpressAdapter = void 0;
4
- const tslib_1 = require("tslib");
5
- const nodePath = tslib_1.__importStar(require("node:path"));
6
- const common_1 = require("@opra/common");
7
- const express_1 = require("express");
8
- const http_adapter_js_1 = require("./http-adapter.js");
9
- const http_context_js_1 = require("./http-context.js");
10
- const http_incoming_interface_js_1 = require("./interfaces/http-incoming.interface.js");
11
- const http_outgoing_interface_js_1 = require("./interfaces/http-outgoing.interface.js");
12
- class ExpressAdapter extends http_adapter_js_1.HttpAdapter {
13
- constructor(app, document, options) {
14
- super(options);
15
- this._controllerInstances = new Map();
16
- this.app = app;
17
- if (!(document.api instanceof common_1.HttpApi))
18
- throw new TypeError(`The document does not expose an HTTP Api`);
19
- this._document = document;
20
- for (const c of this.api.controllers.values())
21
- this._createControllers(c);
22
- this._initRouter();
23
- }
24
- get platform() {
25
- return 'express';
26
- }
27
- async close() {
28
- const processInstance = async (controller) => {
29
- if (controller.controllers.size) {
30
- const subResources = Array.from(controller.controllers.values());
31
- subResources.reverse();
32
- for (const subResource of subResources) {
33
- await processInstance(subResource);
34
- }
35
- }
36
- };
37
- for (const c of this.api.controllers.values())
38
- await processInstance(c);
39
- this._controllerInstances.clear();
40
- }
41
- getControllerInstance(controllerPath) {
42
- const controller = this.api.findController(controllerPath);
43
- return controller && this._controllerInstances.get(controller);
44
- }
45
- _initRouter() {
46
- const router = (0, express_1.Router)();
47
- this.app.use(this.basePath, router);
48
- const createContext = async (_req, _res, args) => {
49
- const request = http_incoming_interface_js_1.HttpIncoming.from(_req);
50
- const response = http_outgoing_interface_js_1.HttpOutgoing.from(_res);
51
- const ctx = new http_context_js_1.HttpContext({
52
- __adapter: this,
53
- platform: this.platform,
54
- request,
55
- response,
56
- __contDef: args?.controller,
57
- __controller: args?.controllerInstance,
58
- __oprDef: args?.operation,
59
- __handler: args?.operationHandler,
60
- });
61
- await this.emitAsync('createContext', ctx);
62
- return ctx;
63
- };
64
- /** Add an endpoint that returns document schema */
65
- router.get('/\\$schema', (_req, _res, next) => {
66
- createContext(_req, _res)
67
- .then(ctx => this.handler.sendDocumentSchema(ctx).catch(next))
68
- .catch(next);
69
- });
70
- /** Add operation endpoints */
71
- if (this.api.controllers.size) {
72
- const processResource = (controller, currentPath) => {
73
- currentPath = nodePath.posix.join(currentPath, controller.path);
74
- for (const operation of controller.operations.values()) {
75
- const routePath = currentPath + (operation.path || '');
76
- const controllerInstance = this._controllerInstances.get(controller);
77
- const operationHandler = controllerInstance[operation.name];
78
- if (!operationHandler)
79
- continue;
80
- /** Define router callback */
81
- router[operation.method.toLowerCase()](routePath, (_req, _res, _next) => {
82
- createContext(_req, _res, {
83
- controller,
84
- controllerInstance,
85
- operation,
86
- operationHandler,
87
- })
88
- .then(ctx => this.handler.handleRequest(ctx))
89
- .then(() => {
90
- if (!_res.headersSent)
91
- _next();
92
- })
93
- .catch((e) => this.emit('error', e));
94
- });
95
- }
96
- if (controller.controllers.size) {
97
- for (const child of controller.controllers.values())
98
- processResource(child, currentPath);
99
- }
100
- };
101
- for (const c of this.api.controllers.values())
102
- processResource(c, '/');
103
- }
104
- /** Add an endpoint that returns 404 error at last */
105
- router.use('/{*splat}', (_req, _res, next) => {
106
- createContext(_req, _res)
107
- .then(ctx => {
108
- ctx.errors.push(new common_1.NotFoundError({
109
- message: `No endpoint found at [${_req.method}]${_req.baseUrl}`,
110
- details: {
111
- path: _req.baseUrl,
112
- method: _req.method,
113
- },
114
- }));
115
- this.handler.sendResponse(ctx).catch(next);
116
- })
117
- .catch(next);
118
- });
119
- }
120
- _createControllers(controller) {
121
- let instance = controller.instance;
122
- if (!instance && controller.ctor)
123
- instance = new controller.ctor();
124
- if (instance) {
125
- this._controllerInstances.set(controller, instance);
126
- // Initialize sub resources
127
- for (const r of controller.controllers.values()) {
128
- this._createControllers(r);
129
- }
130
- }
131
- return instance;
132
- }
133
- }
134
- exports.ExpressAdapter = ExpressAdapter;
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpAdapter = void 0;
4
- const core_1 = require("@opra/core");
5
- const http_handler_js_1 = require("./http-handler.js");
6
- /**
7
- *
8
- * @class HttpAdapter
9
- */
10
- class HttpAdapter extends core_1.PlatformAdapter {
11
- constructor(options) {
12
- super(options);
13
- this.transform = 'http';
14
- this.handler = new http_handler_js_1.HttpHandler(this);
15
- this.interceptors = [...(options?.interceptors || [])];
16
- this.basePath = options?.basePath || '/';
17
- if (!this.basePath.startsWith('/'))
18
- this.basePath = '/' + this.basePath;
19
- this.scope = options?.scope;
20
- }
21
- get api() {
22
- return this.document.getHttpApi();
23
- }
24
- }
25
- exports.HttpAdapter = HttpAdapter;
@@ -1,114 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpContext = void 0;
4
- const tslib_1 = require("tslib");
5
- const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
6
- const common_1 = require("@opra/common");
7
- const core_1 = require("@opra/core");
8
- const multipart_reader_js_1 = require("./impl/multipart-reader.js");
9
- class HttpContext extends core_1.ExecutionContext {
10
- constructor(init) {
11
- super({
12
- ...init,
13
- __docNode: init.__oprDef?.node ||
14
- init.__contDef?.node ||
15
- init.__adapter.document.node,
16
- transport: 'http',
17
- });
18
- this.errors = [];
19
- if (init.__contDef)
20
- this.__contDef = init.__contDef;
21
- if (init.__controller)
22
- this.__controller = init.__controller;
23
- if (init.__oprDef)
24
- this.__oprDef = init.__oprDef;
25
- if (init.__handler)
26
- this.__handler = init.__handler;
27
- this.request = init.request;
28
- this.response = init.response;
29
- this.mediaType = init.mediaType;
30
- this.cookies = init.cookies || {};
31
- this.headers = init.headers || {};
32
- this.pathParams = init.pathParams || {};
33
- this.queryParams = init.queryParams || {};
34
- this._body = init.body;
35
- this.on('finish', () => {
36
- if (this._multipartReader)
37
- this._multipartReader.purge().catch(() => undefined);
38
- });
39
- }
40
- get isMultipart() {
41
- return !!this.request.is('multipart');
42
- }
43
- async getMultipartReader() {
44
- if (!this.isMultipart)
45
- throw new common_1.InternalServerError('Request content is not a multipart content');
46
- if (this._multipartReader)
47
- return this._multipartReader;
48
- const { mediaType } = this;
49
- if (mediaType?.contentType) {
50
- const arr = Array.isArray(mediaType.contentType)
51
- ? mediaType.contentType
52
- : [mediaType.contentType];
53
- const contentType = arr.find(ct => type_is_1.default.is(ct, ['multipart']));
54
- if (!contentType)
55
- throw new common_1.NotAcceptableError('This endpoint does not accept multipart requests');
56
- }
57
- const reader = new multipart_reader_js_1.MultipartReader(this, {
58
- limits: {
59
- fields: mediaType?.maxFields,
60
- fieldSize: mediaType?.maxFieldsSize,
61
- files: mediaType?.maxFiles,
62
- fileSize: mediaType?.maxFileSize,
63
- },
64
- }, mediaType);
65
- this._multipartReader = reader;
66
- return reader;
67
- }
68
- async getBody() {
69
- if (this._body !== undefined)
70
- return this._body;
71
- const { request, __oprDef, mediaType } = this;
72
- if (this.isMultipart) {
73
- const reader = await this.getMultipartReader();
74
- /** Retrieve all fields */
75
- const parts = await reader.getAll();
76
- /** Filter fields according to configuration */
77
- this._body = [...parts];
78
- return this._body;
79
- }
80
- this._body = await this.request.readBody({
81
- limit: __oprDef?.requestBody?.maxContentSize,
82
- });
83
- if (this._body != null) {
84
- // Convert Buffer to string if media is text
85
- if (Buffer.isBuffer(this._body) &&
86
- request.is(['json', 'xml', 'txt', 'text'])) {
87
- this._body = this._body.toString('utf-8');
88
- }
89
- // Transform text to Object if media is JSON
90
- if (typeof this._body === 'string' && request.is(['json']))
91
- this._body = JSON.parse(this._body);
92
- }
93
- if (mediaType) {
94
- // Decode/Validate the data object according to data model
95
- if (this._body && mediaType.type) {
96
- let decode = this.__adapter[core_1.kAssetCache].get(mediaType, 'decode');
97
- if (!decode) {
98
- decode = mediaType.generateCodec('decode', {
99
- scope: this.__adapter.scope,
100
- partial: __oprDef?.requestBody?.partial,
101
- projection: '*',
102
- ignoreReadonlyFields: true,
103
- allowPatchOperators: __oprDef?.requestBody?.allowPatchOperators,
104
- keepKeyFields: __oprDef?.requestBody?.keepKeyFields,
105
- });
106
- this.__adapter[core_1.kAssetCache].set(mediaType, 'decode', decode);
107
- }
108
- this._body = decode(this._body);
109
- }
110
- }
111
- return this._body;
112
- }
113
- }
114
- exports.HttpContext = HttpContext;