@tramvai/module-server 2.70.1 → 2.72.3

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 (48) hide show
  1. package/lib/browser.js +2 -31
  2. package/lib/modules/debugRequests.es.js +143 -0
  3. package/lib/modules/debugRequests.js +151 -0
  4. package/lib/modules/dependenciesVersion.es.js +47 -0
  5. package/lib/modules/dependenciesVersion.js +49 -0
  6. package/lib/modules/gracefulShutdown.es.js +104 -0
  7. package/lib/modules/gracefulShutdown.js +106 -0
  8. package/lib/modules/keepAlive.es.js +47 -0
  9. package/lib/modules/keepAlive.js +49 -0
  10. package/lib/modules/papi/api/index.es.js +80 -0
  11. package/lib/modules/papi/api/index.js +88 -0
  12. package/lib/modules/papi/papi.browser.browser.js +13 -0
  13. package/lib/modules/papi/papi.browser.es.js +13 -0
  14. package/lib/modules/papi/papi.browser.js +15 -0
  15. package/lib/modules/papi/papi.es.js +111 -0
  16. package/lib/modules/papi/papi.js +118 -0
  17. package/lib/modules/papi/server/executor.es.js +39 -0
  18. package/lib/modules/papi/server/executor.js +43 -0
  19. package/lib/modules/papi/server/fileApi.es.js +44 -0
  20. package/lib/modules/papi/server/fileApi.js +52 -0
  21. package/lib/modules/papi/shared.browser.js +25 -0
  22. package/lib/modules/papi/shared.es.js +25 -0
  23. package/lib/modules/papi/shared.js +29 -0
  24. package/lib/modules/proxy.es.js +65 -0
  25. package/lib/modules/proxy.js +73 -0
  26. package/lib/modules/serverTiming.es.js +30 -0
  27. package/lib/modules/serverTiming.js +34 -0
  28. package/lib/modules/statics.es.js +48 -0
  29. package/lib/modules/statics.js +54 -0
  30. package/lib/modules/utilityServer.es.js +99 -0
  31. package/lib/modules/utilityServer.js +101 -0
  32. package/lib/modules/utils/require.es.js +11 -0
  33. package/lib/modules/utils/require.js +16 -0
  34. package/lib/modules/utils/tramvaiDepsFilter.es.js +8 -0
  35. package/lib/modules/utils/tramvaiDepsFilter.js +16 -0
  36. package/lib/server/error.es.js +54 -0
  37. package/lib/server/error.js +62 -0
  38. package/lib/server/server.es.js +17 -0
  39. package/lib/server/server.js +26 -0
  40. package/lib/server/static.es.js +34 -0
  41. package/lib/server/static.js +44 -0
  42. package/lib/server/webApp.es.js +103 -0
  43. package/lib/server/webApp.js +113 -0
  44. package/lib/server/xHeaders.es.js +21 -0
  45. package/lib/server/xHeaders.js +30 -0
  46. package/lib/server.es.js +24 -1035
  47. package/lib/server.js +29 -1055
  48. package/package.json +19 -20
@@ -0,0 +1,8 @@
1
+ import filterObj from '@tinkoff/utils/object/filter';
2
+
3
+ const RegExp = /^@tramvai/;
4
+ const tramvaiDepsFilter = (deps) => {
5
+ return filterObj((v, k) => RegExp.test(k), deps);
6
+ };
7
+
8
+ export { tramvaiDepsFilter };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var filterObj = require('@tinkoff/utils/object/filter');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var filterObj__default = /*#__PURE__*/_interopDefaultLegacy(filterObj);
10
+
11
+ const RegExp = /^@tramvai/;
12
+ const tramvaiDepsFilter = (deps) => {
13
+ return filterObj__default["default"]((v, k) => RegExp.test(k), deps);
14
+ };
15
+
16
+ exports.tramvaiDepsFilter = tramvaiDepsFilter;
@@ -0,0 +1,54 @@
1
+ import isNil from '@tinkoff/utils/is/nil';
2
+ import { isRedirectFoundError, isNotFoundError, isHttpError } from '@tinkoff/errors';
3
+
4
+ const errorHandler = (app, { log, beforeError, processError, afterError, }) => {
5
+ app.setErrorHandler(async (error, request, reply) => {
6
+ const runHandlers = async (handlers) => {
7
+ if (handlers) {
8
+ for (const handler of handlers) {
9
+ const result = await handler(error, request, reply);
10
+ if (result) {
11
+ return result;
12
+ }
13
+ }
14
+ }
15
+ };
16
+ const requestInfo = {
17
+ ip: request.ip,
18
+ requestId: request.headers['x-request-id'],
19
+ url: request.url,
20
+ };
21
+ const beforeErrorResult = await runHandlers(beforeError);
22
+ if (!isNil(beforeErrorResult)) {
23
+ return beforeErrorResult;
24
+ }
25
+ if (isRedirectFoundError(error)) {
26
+ reply.header('cache-control', 'no-cache, no-store, must-revalidate');
27
+ reply.redirect(error.httpStatus || 307, error.nextUrl);
28
+ return;
29
+ }
30
+ if (isNotFoundError(error)) {
31
+ reply.status(404);
32
+ return '';
33
+ }
34
+ const processErrorResult = await runHandlers(processError);
35
+ if (!isNil(processErrorResult)) {
36
+ return processErrorResult;
37
+ }
38
+ if (isHttpError(error)) {
39
+ if (error.httpStatus >= 500) {
40
+ log.error({ event: 'send-server-error', error, requestInfo });
41
+ }
42
+ reply.status(error.httpStatus);
43
+ return '';
44
+ }
45
+ log.error({ event: 'send-server-error', error, requestInfo });
46
+ const afterErrorResult = await runHandlers(afterError);
47
+ if (!isNil(afterErrorResult)) {
48
+ return afterErrorResult;
49
+ }
50
+ throw error;
51
+ });
52
+ };
53
+
54
+ export { errorHandler };
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var isNil = require('@tinkoff/utils/is/nil');
6
+ var errors = require('@tinkoff/errors');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
11
+
12
+ const errorHandler = (app, { log, beforeError, processError, afterError, }) => {
13
+ app.setErrorHandler(async (error, request, reply) => {
14
+ const runHandlers = async (handlers) => {
15
+ if (handlers) {
16
+ for (const handler of handlers) {
17
+ const result = await handler(error, request, reply);
18
+ if (result) {
19
+ return result;
20
+ }
21
+ }
22
+ }
23
+ };
24
+ const requestInfo = {
25
+ ip: request.ip,
26
+ requestId: request.headers['x-request-id'],
27
+ url: request.url,
28
+ };
29
+ const beforeErrorResult = await runHandlers(beforeError);
30
+ if (!isNil__default["default"](beforeErrorResult)) {
31
+ return beforeErrorResult;
32
+ }
33
+ if (errors.isRedirectFoundError(error)) {
34
+ reply.header('cache-control', 'no-cache, no-store, must-revalidate');
35
+ reply.redirect(error.httpStatus || 307, error.nextUrl);
36
+ return;
37
+ }
38
+ if (errors.isNotFoundError(error)) {
39
+ reply.status(404);
40
+ return '';
41
+ }
42
+ const processErrorResult = await runHandlers(processError);
43
+ if (!isNil__default["default"](processErrorResult)) {
44
+ return processErrorResult;
45
+ }
46
+ if (errors.isHttpError(error)) {
47
+ if (error.httpStatus >= 500) {
48
+ log.error({ event: 'send-server-error', error, requestInfo });
49
+ }
50
+ reply.status(error.httpStatus);
51
+ return '';
52
+ }
53
+ log.error({ event: 'send-server-error', error, requestInfo });
54
+ const afterErrorResult = await runHandlers(afterError);
55
+ if (!isNil__default["default"](afterErrorResult)) {
56
+ return afterErrorResult;
57
+ }
58
+ throw error;
59
+ });
60
+ };
61
+
62
+ exports.errorHandler = errorHandler;
@@ -0,0 +1,17 @@
1
+ import http from 'http';
2
+
3
+ const serverFactory = () => {
4
+ return http.createServer();
5
+ };
6
+ const serverListenCommand = ({ server, logger, envManager, }) => {
7
+ const log = logger('server');
8
+ const port = envManager.get('PORT');
9
+ return function serverListen() {
10
+ server.listen({
11
+ host: '',
12
+ port,
13
+ }, () => log.warn({ event: 'server-listen-port', message: `Server listen ${port} port` }));
14
+ };
15
+ };
16
+
17
+ export { serverFactory, serverListenCommand };
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var http = require('http');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
10
+
11
+ const serverFactory = () => {
12
+ return http__default["default"].createServer();
13
+ };
14
+ const serverListenCommand = ({ server, logger, envManager, }) => {
15
+ const log = logger('server');
16
+ const port = envManager.get('PORT');
17
+ return function serverListen() {
18
+ server.listen({
19
+ host: '',
20
+ port,
21
+ }, () => log.warn({ event: 'server-listen-port', message: `Server listen ${port} port` }));
22
+ };
23
+ };
24
+
25
+ exports.serverFactory = serverFactory;
26
+ exports.serverListenCommand = serverListenCommand;
@@ -0,0 +1,34 @@
1
+ import fastify from 'fastify';
2
+ import fastifyCompress from '@fastify/compress';
3
+ import { fastifyStatic } from '@fastify/static';
4
+ import os from 'os';
5
+
6
+ const staticAppCommand = ({ logger, envManager, appInfo, }) => {
7
+ if (!envManager.get('DEV_STATIC')) {
8
+ return function staticAppNoop() { };
9
+ }
10
+ const log = logger('server:static');
11
+ const port = +envManager.get('PORT_STATIC');
12
+ const appVersion = envManager.get('APP_VERSION');
13
+ return async function staticApp() {
14
+ const appStatic = fastify();
15
+ await appStatic.register(fastifyCompress);
16
+ await appStatic.register(fastifyStatic, {
17
+ root: process.cwd(),
18
+ prefix: '/',
19
+ setHeaders: (res) => {
20
+ res.headers({
21
+ 'Access-Control-Allow-Origin': '*',
22
+ 'Timing-Allow-Origin': '*',
23
+ 'X-App-Id': appInfo.appName,
24
+ 'X-App-Version': appVersion,
25
+ 'X-Host': os.hostname(),
26
+ });
27
+ },
28
+ });
29
+ appStatic.listen({ port }, () => log.info(`Running static server on port: ${port}`));
30
+ return appStatic;
31
+ };
32
+ };
33
+
34
+ export { staticAppCommand };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var fastify = require('fastify');
6
+ var fastifyCompress = require('@fastify/compress');
7
+ var FastifyStatic = require('@fastify/static');
8
+ var os = require('os');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ var fastify__default = /*#__PURE__*/_interopDefaultLegacy(fastify);
13
+ var fastifyCompress__default = /*#__PURE__*/_interopDefaultLegacy(fastifyCompress);
14
+ var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
15
+
16
+ const staticAppCommand = ({ logger, envManager, appInfo, }) => {
17
+ if (!envManager.get('DEV_STATIC')) {
18
+ return function staticAppNoop() { };
19
+ }
20
+ const log = logger('server:static');
21
+ const port = +envManager.get('PORT_STATIC');
22
+ const appVersion = envManager.get('APP_VERSION');
23
+ return async function staticApp() {
24
+ const appStatic = fastify__default["default"]();
25
+ await appStatic.register(fastifyCompress__default["default"]);
26
+ await appStatic.register(FastifyStatic.fastifyStatic, {
27
+ root: process.cwd(),
28
+ prefix: '/',
29
+ setHeaders: (res) => {
30
+ res.headers({
31
+ 'Access-Control-Allow-Origin': '*',
32
+ 'Timing-Allow-Origin': '*',
33
+ 'X-App-Id': appInfo.appName,
34
+ 'X-App-Version': appVersion,
35
+ 'X-Host': os__default["default"].hostname(),
36
+ });
37
+ },
38
+ });
39
+ appStatic.listen({ port }, () => log.info(`Running static server on port: ${port}`));
40
+ return appStatic;
41
+ };
42
+ };
43
+
44
+ exports.staticAppCommand = staticAppCommand;
@@ -0,0 +1,103 @@
1
+ import fastify from 'fastify';
2
+ import { fastifyCookie } from '@fastify/cookie';
3
+ import fastifyFormBody from '@fastify/formbody';
4
+ import { ROOT_EXECUTION_CONTEXT_TOKEN, RESPONSE_MANAGER_TOKEN } from '@tramvai/tokens-common';
5
+ import { Scope } from '@tramvai/core';
6
+ import { FASTIFY_REQUEST, FASTIFY_RESPONSE } from '@tramvai/tokens-server-private';
7
+ import { provide } from '@tinkoff/dippy';
8
+ import { errorHandler } from './error.es.js';
9
+
10
+ const webAppFactory = ({ server }) => {
11
+ const app = fastify({
12
+ ignoreTrailingSlash: true,
13
+ bodyLimit: 2097152,
14
+ serverFactory: (handler) => {
15
+ server.on('request', handler);
16
+ return server;
17
+ },
18
+ });
19
+ return app;
20
+ };
21
+ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextManager, beforeInit, requestMetrics, limiterRequest, init, afterInit, beforeError, processError, afterError, }) => {
22
+ const log = logger('server:webapp');
23
+ const runHandlers = (instance, handlers) => {
24
+ return Promise.all([handlers && Promise.all(handlers.map((handler) => handler(instance)))]);
25
+ };
26
+ return async function webAppInit() {
27
+ errorHandler(app, { log, beforeError, processError, afterError });
28
+ await app.register(async (instance) => {
29
+ await runHandlers(instance, beforeInit);
30
+ });
31
+ await app.register(async (instance) => {
32
+ await runHandlers(instance, requestMetrics);
33
+ await runHandlers(instance, limiterRequest);
34
+ await app.register(fastifyCookie);
35
+ await app.register(fastifyFormBody);
36
+ await runHandlers(instance, init);
37
+ // break the cycle of event loop to allow server to handle other requests
38
+ // while current on is in processing
39
+ // mainly to prevent problems and response hanging in case the response process
40
+ // uses only sync and microtask code
41
+ instance.addHook('preHandler', (req, res, next) => {
42
+ setImmediate(next);
43
+ });
44
+ instance.all('*', async (request, reply) => {
45
+ try {
46
+ log.debug({
47
+ event: 'start:request',
48
+ message: 'Клиент зашел на страницу',
49
+ url: request.url,
50
+ });
51
+ await executionContextManager.withContext(null, 'root', async (rootExecutionContext) => {
52
+ const di = await commandLineRunner.run('server', 'customer', [
53
+ provide({
54
+ provide: ROOT_EXECUTION_CONTEXT_TOKEN,
55
+ useValue: rootExecutionContext,
56
+ }),
57
+ {
58
+ provide: FASTIFY_REQUEST,
59
+ scope: Scope.REQUEST,
60
+ useValue: request,
61
+ },
62
+ {
63
+ provide: FASTIFY_RESPONSE,
64
+ scope: Scope.REQUEST,
65
+ useValue: reply,
66
+ },
67
+ ]);
68
+ const responseManager = di.get(RESPONSE_MANAGER_TOKEN);
69
+ if (reply.sent) {
70
+ log.debug({
71
+ event: 'response-ended',
72
+ message: 'Response was already ended.',
73
+ url: request.url,
74
+ });
75
+ }
76
+ else {
77
+ reply
78
+ .header('content-type', 'text/html')
79
+ .headers(responseManager.getHeaders())
80
+ .status(responseManager.getStatus())
81
+ .send(responseManager.getBody());
82
+ }
83
+ });
84
+ }
85
+ catch (err) {
86
+ if (err.di) {
87
+ const responseManager = err.di.get(RESPONSE_MANAGER_TOKEN);
88
+ if (responseManager && !reply.sent) {
89
+ reply.headers(responseManager.getHeaders());
90
+ }
91
+ }
92
+ throw err;
93
+ }
94
+ });
95
+ });
96
+ await app.register(async (instance) => {
97
+ await runHandlers(instance, afterInit);
98
+ });
99
+ await app.ready();
100
+ };
101
+ };
102
+
103
+ export { webAppFactory, webAppInitCommand };
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var fastify = require('fastify');
6
+ var cookie = require('@fastify/cookie');
7
+ var fastifyFormBody = require('@fastify/formbody');
8
+ var tokensCommon = require('@tramvai/tokens-common');
9
+ var core = require('@tramvai/core');
10
+ var tokensServerPrivate = require('@tramvai/tokens-server-private');
11
+ var dippy = require('@tinkoff/dippy');
12
+ var error = require('./error.js');
13
+
14
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
15
+
16
+ var fastify__default = /*#__PURE__*/_interopDefaultLegacy(fastify);
17
+ var fastifyFormBody__default = /*#__PURE__*/_interopDefaultLegacy(fastifyFormBody);
18
+
19
+ const webAppFactory = ({ server }) => {
20
+ const app = fastify__default["default"]({
21
+ ignoreTrailingSlash: true,
22
+ bodyLimit: 2097152,
23
+ serverFactory: (handler) => {
24
+ server.on('request', handler);
25
+ return server;
26
+ },
27
+ });
28
+ return app;
29
+ };
30
+ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextManager, beforeInit, requestMetrics, limiterRequest, init, afterInit, beforeError, processError, afterError, }) => {
31
+ const log = logger('server:webapp');
32
+ const runHandlers = (instance, handlers) => {
33
+ return Promise.all([handlers && Promise.all(handlers.map((handler) => handler(instance)))]);
34
+ };
35
+ return async function webAppInit() {
36
+ error.errorHandler(app, { log, beforeError, processError, afterError });
37
+ await app.register(async (instance) => {
38
+ await runHandlers(instance, beforeInit);
39
+ });
40
+ await app.register(async (instance) => {
41
+ await runHandlers(instance, requestMetrics);
42
+ await runHandlers(instance, limiterRequest);
43
+ await app.register(cookie.fastifyCookie);
44
+ await app.register(fastifyFormBody__default["default"]);
45
+ await runHandlers(instance, init);
46
+ // break the cycle of event loop to allow server to handle other requests
47
+ // while current on is in processing
48
+ // mainly to prevent problems and response hanging in case the response process
49
+ // uses only sync and microtask code
50
+ instance.addHook('preHandler', (req, res, next) => {
51
+ setImmediate(next);
52
+ });
53
+ instance.all('*', async (request, reply) => {
54
+ try {
55
+ log.debug({
56
+ event: 'start:request',
57
+ message: 'Клиент зашел на страницу',
58
+ url: request.url,
59
+ });
60
+ await executionContextManager.withContext(null, 'root', async (rootExecutionContext) => {
61
+ const di = await commandLineRunner.run('server', 'customer', [
62
+ dippy.provide({
63
+ provide: tokensCommon.ROOT_EXECUTION_CONTEXT_TOKEN,
64
+ useValue: rootExecutionContext,
65
+ }),
66
+ {
67
+ provide: tokensServerPrivate.FASTIFY_REQUEST,
68
+ scope: core.Scope.REQUEST,
69
+ useValue: request,
70
+ },
71
+ {
72
+ provide: tokensServerPrivate.FASTIFY_RESPONSE,
73
+ scope: core.Scope.REQUEST,
74
+ useValue: reply,
75
+ },
76
+ ]);
77
+ const responseManager = di.get(tokensCommon.RESPONSE_MANAGER_TOKEN);
78
+ if (reply.sent) {
79
+ log.debug({
80
+ event: 'response-ended',
81
+ message: 'Response was already ended.',
82
+ url: request.url,
83
+ });
84
+ }
85
+ else {
86
+ reply
87
+ .header('content-type', 'text/html')
88
+ .headers(responseManager.getHeaders())
89
+ .status(responseManager.getStatus())
90
+ .send(responseManager.getBody());
91
+ }
92
+ });
93
+ }
94
+ catch (err) {
95
+ if (err.di) {
96
+ const responseManager = err.di.get(tokensCommon.RESPONSE_MANAGER_TOKEN);
97
+ if (responseManager && !reply.sent) {
98
+ reply.headers(responseManager.getHeaders());
99
+ }
100
+ }
101
+ throw err;
102
+ }
103
+ });
104
+ });
105
+ await app.register(async (instance) => {
106
+ await runHandlers(instance, afterInit);
107
+ });
108
+ await app.ready();
109
+ };
110
+ };
111
+
112
+ exports.webAppFactory = webAppFactory;
113
+ exports.webAppInitCommand = webAppInitCommand;
@@ -0,0 +1,21 @@
1
+ import filterObj from '@tinkoff/utils/object/filter';
2
+ import os from 'os';
3
+
4
+ const xHeadersFactory = ({ app, envManager, appInfo, }) => {
5
+ const xHeaders = filterObj((val) => !!val, {
6
+ 'x-app-id': appInfo.appName,
7
+ 'x-host': encodeURIComponent(os.hostname()),
8
+ 'x-app-version': envManager.get('APP_VERSION'),
9
+ 'x-deploy-branch': envManager.get('DEPLOY_BRANCH'),
10
+ 'x-deploy-commit': envManager.get('DEPLOY_COMMIT'),
11
+ 'x-deploy-version': envManager.get('DEPLOY_VERSION'),
12
+ 'x-deploy-repository': envManager.get('DEPLOY_REPOSITORY'),
13
+ });
14
+ return async () => {
15
+ app.addHook('preHandler', async (_, reply) => {
16
+ reply.headers(xHeaders);
17
+ });
18
+ };
19
+ };
20
+
21
+ export { xHeadersFactory };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var filterObj = require('@tinkoff/utils/object/filter');
6
+ var os = require('os');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ var filterObj__default = /*#__PURE__*/_interopDefaultLegacy(filterObj);
11
+ var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
12
+
13
+ const xHeadersFactory = ({ app, envManager, appInfo, }) => {
14
+ const xHeaders = filterObj__default["default"]((val) => !!val, {
15
+ 'x-app-id': appInfo.appName,
16
+ 'x-host': encodeURIComponent(os__default["default"].hostname()),
17
+ 'x-app-version': envManager.get('APP_VERSION'),
18
+ 'x-deploy-branch': envManager.get('DEPLOY_BRANCH'),
19
+ 'x-deploy-commit': envManager.get('DEPLOY_COMMIT'),
20
+ 'x-deploy-version': envManager.get('DEPLOY_VERSION'),
21
+ 'x-deploy-repository': envManager.get('DEPLOY_REPOSITORY'),
22
+ });
23
+ return async () => {
24
+ app.addHook('preHandler', async (_, reply) => {
25
+ reply.headers(xHeaders);
26
+ });
27
+ };
28
+ };
29
+
30
+ exports.xHeadersFactory = xHeadersFactory;