@tramvai/module-server 2.70.0 → 2.72.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 (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
package/lib/server.es.js CHANGED
@@ -1,1045 +1,34 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { setDefaultResultOrder } from 'dns';
3
- import EventEmitter$1, { EventEmitter } from 'events';
4
- import { Scope, APP_INFO_TOKEN, Module, provide as provide$1, DI_TOKEN as DI_TOKEN$1, COMMAND_LINE_RUNNER_TOKEN, commandLineListTokens, createToken, declareModule } from '@tramvai/core';
5
- import { SERVER_MODULE_PAPI_PUBLIC_ROUTE, SERVER_MODULE_PAPI_PUBLIC_URL, SERVER_MODULE_PAPI_PRIVATE_URL, SERVER_MODULE_PAPI_PRIVATE_ROUTE, SERVER_MODULE_STATICS_OPTIONS, SERVER_TOKEN, LIVENESS_PATH_TOKEN, READINESS_PATH_TOKEN, READINESS_PROBE_TOKEN, LIVENESS_PROBE_TOKEN, UTILITY_SERVER_PATHS, PROXY_CONFIG_TOKEN, DEPENDENCIES_VERSION_FILTER_TOKEN, UTILITY_SERVER_PORT_TOKEN } from '@tramvai/tokens-server';
3
+ import EventEmitter from 'events';
4
+ import { Module, provide, Scope, commandLineListTokens, COMMAND_LINE_RUNNER_TOKEN, APP_INFO_TOKEN } from '@tramvai/core';
5
+ import { SERVER_TOKEN } from '@tramvai/tokens-server';
6
6
  export * from '@tramvai/tokens-server';
7
- import { FASTIFY_REQUEST, FASTIFY_RESPONSE, PAPI_EXECUTOR, WEB_FASTIFY_APP_BEFORE_INIT_TOKEN, UTILITY_WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_INIT_TOKEN, UTILITY_SERVER_TOKEN, SERVER_FACTORY_TOKEN, WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_FACTORY_TOKEN, WEB_FASTIFY_APP_AFTER_INIT_TOKEN, WEB_FASTIFY_APP_METRICS_TOKEN, WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN, WEB_FASTIFY_APP_PROCESS_ERROR_TOKEN, WEB_FASTIFY_APP_AFTER_ERROR_TOKEN } from '@tramvai/tokens-server-private';
8
- import { ROOT_EXECUTION_CONTEXT_TOKEN, RESPONSE_MANAGER_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, ENV_MANAGER_TOKEN, ENV_USED_TOKEN, EXECUTION_CONTEXT_MANAGER_TOKEN } from '@tramvai/tokens-common';
7
+ import { SERVER_FACTORY_TOKEN, WEB_FASTIFY_APP_FACTORY_TOKEN, WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_BEFORE_INIT_TOKEN, WEB_FASTIFY_APP_INIT_TOKEN, WEB_FASTIFY_APP_AFTER_INIT_TOKEN, WEB_FASTIFY_APP_METRICS_TOKEN, WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN, WEB_FASTIFY_APP_PROCESS_ERROR_TOKEN, WEB_FASTIFY_APP_AFTER_ERROR_TOKEN } from '@tramvai/tokens-server-private';
8
+ import { LOGGER_TOKEN, EXECUTION_CONTEXT_MANAGER_TOKEN, ENV_MANAGER_TOKEN, ENV_USED_TOKEN } from '@tramvai/tokens-common';
9
9
  import { MetricsModule } from '@tramvai/module-metrics';
10
10
  import { CacheWarmupModule } from '@tramvai/module-cache-warmup';
11
- import http from 'http';
12
- import fastify from 'fastify';
13
- import { fastifyCookie } from '@fastify/cookie';
14
- import fastifyFormBody from '@fastify/formbody';
15
- import { provide, createChildContainer, Scope as Scope$1, DI_TOKEN } from '@tinkoff/dippy';
16
- import isNil from '@tinkoff/utils/is/nil';
17
- import { isRedirectFoundError, isNotFoundError, isHttpError, HttpError } from '@tinkoff/errors';
18
- import fastifyCompress from '@fastify/compress';
19
- import FastifyStatic, { fastifyStatic } from '@fastify/static';
20
- import os from 'os';
21
- import filterObj from '@tinkoff/utils/object/filter';
22
- import flatten from '@tinkoff/utils/array/flatten';
23
- import toArray from '@tinkoff/utils/array/toArray';
24
- import { getPapiParameters, isPapiMethod, createPapiMethod } from '@tramvai/papi';
25
- import eachObj from '@tinkoff/utils/object/each';
26
- import { resolve } from 'path';
27
- import { createTerminus } from '@tinkoff/terminus';
28
- import { parse } from '@tinkoff/url';
29
- import monkeypatch from '@tinkoff/monkeypatch';
30
- import https from 'https';
31
- import isArray from '@tinkoff/utils/is/array';
32
- import isObject from '@tinkoff/utils/is/object';
33
- import { createProxyMiddleware } from 'http-proxy-middleware';
34
- import { ENV_MANAGER_TOKEN as ENV_MANAGER_TOKEN$1 } from '@tramvai/module-common';
35
- import { COMMAND_LINE_EXECUTION_END_TOKEN } from '@tramvai/tokens-core-private';
36
-
37
- const serverFactory = () => {
38
- return http.createServer();
39
- };
40
- const serverListenCommand = ({ server, logger, envManager, }) => {
41
- const log = logger('server');
42
- const port = envManager.get('PORT');
43
- return function serverListen() {
44
- server.listen({
45
- host: '',
46
- port,
47
- }, () => log.warn({ event: 'server-listen-port', message: `Server listen ${port} port` }));
48
- };
49
- };
50
-
51
- const errorHandler = (app, { log, beforeError, processError, afterError, }) => {
52
- app.setErrorHandler(async (error, request, reply) => {
53
- const runHandlers = async (handlers) => {
54
- if (handlers) {
55
- for (const handler of handlers) {
56
- const result = await handler(error, request, reply);
57
- if (result) {
58
- return result;
59
- }
60
- }
61
- }
62
- };
63
- const requestInfo = {
64
- ip: request.ip,
65
- requestId: request.headers['x-request-id'],
66
- url: request.url,
67
- };
68
- const beforeErrorResult = await runHandlers(beforeError);
69
- if (!isNil(beforeErrorResult)) {
70
- return beforeErrorResult;
71
- }
72
- if (isRedirectFoundError(error)) {
73
- reply.header('cache-control', 'no-cache, no-store, must-revalidate');
74
- reply.redirect(error.httpStatus || 307, error.nextUrl);
75
- return;
76
- }
77
- if (isNotFoundError(error)) {
78
- reply.status(404);
79
- return '';
80
- }
81
- const processErrorResult = await runHandlers(processError);
82
- if (!isNil(processErrorResult)) {
83
- return processErrorResult;
84
- }
85
- if (isHttpError(error)) {
86
- if (error.httpStatus >= 500) {
87
- log.error({ event: 'send-server-error', error, requestInfo });
88
- }
89
- reply.status(error.httpStatus);
90
- return '';
91
- }
92
- log.error({ event: 'send-server-error', error, requestInfo });
93
- const afterErrorResult = await runHandlers(afterError);
94
- if (!isNil(afterErrorResult)) {
95
- return afterErrorResult;
96
- }
97
- throw error;
98
- });
99
- };
100
-
101
- const webAppFactory = ({ server }) => {
102
- const app = fastify({
103
- ignoreTrailingSlash: true,
104
- bodyLimit: 2097152,
105
- serverFactory: (handler) => {
106
- server.on('request', handler);
107
- return server;
108
- },
109
- });
110
- return app;
111
- };
112
- const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextManager, beforeInit, requestMetrics, limiterRequest, init, afterInit, beforeError, processError, afterError, }) => {
113
- const log = logger('server:webapp');
114
- const runHandlers = (instance, handlers) => {
115
- return Promise.all([handlers && Promise.all(handlers.map((handler) => handler(instance)))]);
116
- };
117
- return async function webAppInit() {
118
- errorHandler(app, { log, beforeError, processError, afterError });
119
- await app.register(async (instance) => {
120
- await runHandlers(instance, beforeInit);
121
- });
122
- await app.register(async (instance) => {
123
- await runHandlers(instance, requestMetrics);
124
- await runHandlers(instance, limiterRequest);
125
- await app.register(fastifyCookie);
126
- await app.register(fastifyFormBody);
127
- await runHandlers(instance, init);
128
- // break the cycle of event loop to allow server to handle other requests
129
- // while current on is in processing
130
- // mainly to prevent problems and response hanging in case the response process
131
- // uses only sync and microtask code
132
- instance.addHook('preHandler', (req, res, next) => {
133
- setImmediate(next);
134
- });
135
- instance.all('*', async (request, reply) => {
136
- try {
137
- log.debug({
138
- event: 'start:request',
139
- message: 'Клиент зашел на страницу',
140
- url: request.url,
141
- });
142
- await executionContextManager.withContext(null, 'root', async (rootExecutionContext) => {
143
- const di = await commandLineRunner.run('server', 'customer', [
144
- provide({
145
- provide: ROOT_EXECUTION_CONTEXT_TOKEN,
146
- useValue: rootExecutionContext,
147
- }),
148
- {
149
- provide: FASTIFY_REQUEST,
150
- scope: Scope.REQUEST,
151
- useValue: request,
152
- },
153
- {
154
- provide: FASTIFY_RESPONSE,
155
- scope: Scope.REQUEST,
156
- useValue: reply,
157
- },
158
- ]);
159
- const responseManager = di.get(RESPONSE_MANAGER_TOKEN);
160
- if (reply.sent) {
161
- log.debug({
162
- event: 'response-ended',
163
- message: 'Response was already ended.',
164
- url: request.url,
165
- });
166
- }
167
- else {
168
- reply
169
- .header('content-type', 'text/html')
170
- .headers(responseManager.getHeaders())
171
- .status(responseManager.getStatus())
172
- .send(responseManager.getBody());
173
- }
174
- });
175
- }
176
- catch (err) {
177
- if (err.di) {
178
- const responseManager = err.di.get(RESPONSE_MANAGER_TOKEN);
179
- if (responseManager && !reply.sent) {
180
- reply.headers(responseManager.getHeaders());
181
- }
182
- }
183
- throw err;
184
- }
185
- });
186
- });
187
- await app.register(async (instance) => {
188
- await runHandlers(instance, afterInit);
189
- });
190
- await app.ready();
191
- };
192
- };
193
-
194
- const staticAppCommand = ({ logger, envManager, appInfo, }) => {
195
- if (!envManager.get('DEV_STATIC')) {
196
- return function staticAppNoop() { };
197
- }
198
- const log = logger('server:static');
199
- const port = +envManager.get('PORT_STATIC');
200
- const appVersion = envManager.get('APP_VERSION');
201
- return async function staticApp() {
202
- const appStatic = fastify();
203
- await appStatic.register(fastifyCompress);
204
- await appStatic.register(fastifyStatic, {
205
- root: process.cwd(),
206
- prefix: '/',
207
- setHeaders: (res) => {
208
- res.headers({
209
- 'Access-Control-Allow-Origin': '*',
210
- 'Timing-Allow-Origin': '*',
211
- 'X-App-Id': appInfo.appName,
212
- 'X-App-Version': appVersion,
213
- 'X-Host': os.hostname(),
214
- });
215
- },
216
- });
217
- appStatic.listen({ port }, () => log.info(`Running static server on port: ${port}`));
218
- return appStatic;
219
- };
220
- };
221
-
222
- const xHeadersFactory = ({ app, envManager, appInfo, }) => {
223
- const xHeaders = filterObj((val) => !!val, {
224
- 'x-app-id': appInfo.appName,
225
- 'x-host': encodeURIComponent(os.hostname()),
226
- 'x-app-version': envManager.get('APP_VERSION'),
227
- 'x-deploy-branch': envManager.get('DEPLOY_BRANCH'),
228
- 'x-deploy-commit': envManager.get('DEPLOY_COMMIT'),
229
- 'x-deploy-version': envManager.get('DEPLOY_VERSION'),
230
- 'x-deploy-repository': envManager.get('DEPLOY_REPOSITORY'),
231
- });
232
- return async () => {
233
- app.addHook('preHandler', async (_, reply) => {
234
- reply.headers(xHeaders);
235
- });
236
- };
237
- };
238
-
239
- function createApi(rootApp, papiList, { baseUrl, di, logger }) {
240
- const paths = new Set();
241
- const papiLog = logger('papi');
242
- rootApp.register(async (app) => {
243
- await app.register(fastifyCookie);
244
- await app.register(fastifyFormBody, { bodyLimit: 2097152 }); // 2mb
245
- for (const papi of papiList) {
246
- const papiParams = getPapiParameters(papi);
247
- if (!papiParams) {
248
- throw new Error(`papi should be created using createPapiMethod from @tramvai/papi,
249
- got: ${JSON.stringify(papi)}`);
250
- }
251
- const { method, path, options } = papiParams;
252
- const { timeout, schema } = options;
253
- if (!path) {
254
- throw new Error(`No path in papi handler, got: ${JSON.stringify(papi)}`);
255
- }
256
- const key = `${method} ${path}`;
257
- if (paths.has(key)) {
258
- throw new Error(`papi: route '${key}' already registered`);
259
- }
260
- paths.add(key);
261
- const childLog = papiLog.child(`${papiParams.method}_${papiParams.path}`);
262
- app[method](path, {
263
- schema,
264
- errorHandler: async (error, req, res) => {
265
- var _a;
266
- res.status(error.validation ? 400 : 503);
267
- childLog.error(error);
268
- return {
269
- resultCode: 'INTERNAL_ERROR',
270
- errorMessage: (_a = error.message) !== null && _a !== void 0 ? _a : 'internal error',
271
- };
272
- },
273
- }, async (req, res) => {
274
- const childDi = createChildContainer(di, [
275
- {
276
- provide: FASTIFY_REQUEST,
277
- scope: Scope$1.REQUEST,
278
- useValue: req,
279
- },
280
- {
281
- provide: FASTIFY_RESPONSE,
282
- scope: Scope$1.REQUEST,
283
- useValue: res,
284
- },
285
- ]);
286
- const papiExecutor = childDi.get(PAPI_EXECUTOR);
287
- // TODO: use abortSignal
288
- const payload = await Promise.race([
289
- papiExecutor(papi),
290
- new Promise((resolve, reject) => setTimeout(() => reject(new HttpError({ httpStatus: 503, message: 'Execution timeout' })), timeout)),
291
- ]);
292
- const responseManager = childDi.get(RESPONSE_MANAGER_TOKEN);
293
- res.headers(responseManager.getHeaders()).status(responseManager.getStatus());
294
- if (res.sent) {
295
- return;
296
- }
297
- if (!payload && responseManager.getBody()) {
298
- res.send(responseManager.getBody());
299
- return res;
300
- }
301
- return {
302
- resultCode: 'OK',
303
- payload,
304
- };
305
- });
306
- }
307
- }, { prefix: baseUrl });
308
- }
309
-
310
- let papis;
311
- try {
312
- // eslint-disable-next-line import/no-extraneous-dependencies
313
- papis = require('@tramvai/cli/lib/external/api').default; // eslint-disable-line import/no-unresolved
314
- }
315
- catch (e) { }
316
- const getFileApi = ({ logger }) => {
317
- const log = logger('papi:fileApi');
318
- const result = [];
319
- eachObj(({ default: entry }, path) => {
320
- if (!isPapiMethod(entry)) {
321
- log.error({
322
- path,
323
- entry,
324
- message: `Cannot resolve a papi handler.
325
- Check that you are using file based papi right way by docs https://tramvai.dev/docs/how-to/how-create-papi#automatic-handler-creation
326
- In case you have not added any file papi handler, consider renaming directory ./src/api (by default) to the other name to resolve conflicts with papi, or
327
- change settings serverApiDir in tramvai.json`,
328
- });
329
- throw new Error('Not a papi');
330
- }
331
- const papiParameters = getPapiParameters(entry);
332
- result.push(createPapiMethod({
333
- ...papiParameters,
334
- path: `/${path}`,
335
- }));
336
- }, papis);
337
- return result;
338
- };
339
- const fileApiProvider = {
340
- provide: SERVER_MODULE_PAPI_PUBLIC_ROUTE,
341
- multi: true,
342
- useFactory: getFileApi,
343
- deps: {
344
- logger: LOGGER_TOKEN,
345
- },
346
- };
347
-
348
- const sharedProviders = [
349
- {
350
- provide: SERVER_MODULE_PAPI_PUBLIC_URL,
351
- useFactory: ({ appInfo }) => {
352
- return `/${appInfo.appName}/papi`;
353
- },
354
- deps: {
355
- appInfo: APP_INFO_TOKEN,
356
- },
357
- },
358
- {
359
- provide: SERVER_MODULE_PAPI_PRIVATE_URL,
360
- useFactory: ({ appInfo }) => {
361
- return `/${appInfo.appName}/private/papi`;
362
- },
363
- deps: {
364
- appInfo: APP_INFO_TOKEN,
365
- },
366
- },
367
- ];
368
-
369
- const papiExecutorProvider = provide({
370
- provide: PAPI_EXECUTOR,
371
- scope: Scope$1.REQUEST,
372
- useFactory: ({ di, logger, fastifyRequest, requestManager, responseManager }) => {
373
- var _a;
374
- const papiLog = logger('papi');
375
- const papiOptions = {
376
- requestManager,
377
- responseManager,
378
- params: (_a = fastifyRequest.params) !== null && _a !== void 0 ? _a : {},
379
- cookies: requestManager.getCookies(),
380
- headers: requestManager.getHeaders(),
381
- body: requestManager.getBody(),
382
- parsedUrl: requestManager.getParsedUrl(),
383
- };
384
- return (papi) => {
385
- const { handler, deps, method, path } = getPapiParameters(papi);
386
- const papiContext = {
387
- deps: di.getOfDeps(deps),
388
- log: papiLog.child(`${method}_${path}`),
389
- };
390
- return handler.call(papiContext, papiOptions);
391
- };
392
- },
393
- deps: {
394
- di: DI_TOKEN,
395
- logger: LOGGER_TOKEN,
396
- fastifyRequest: FASTIFY_REQUEST,
397
- requestManager: REQUEST_MANAGER_TOKEN,
398
- responseManager: RESPONSE_MANAGER_TOKEN,
399
- },
400
- });
401
-
402
- let ServerPapiModule = class ServerPapiModule {
403
- };
404
- ServerPapiModule = __decorate([
405
- Module({
406
- providers: [
407
- papiExecutorProvider,
408
- fileApiProvider,
409
- ...sharedProviders,
410
- provide$1({
411
- provide: WEB_FASTIFY_APP_BEFORE_INIT_TOKEN,
412
- useFactory: ({ di, logger, privateRoutes, publicRoutes, publicBaseUrl, privateBaseUrl }) => (app) => {
413
- if (process.env.NODE_ENV === 'development') {
414
- const papiListRoute = createPapiMethod({
415
- method: 'get',
416
- path: '/papi-list',
417
- async handler() {
418
- return [
419
- ...flatten(privateRoutes).map((papi) => {
420
- const params = getPapiParameters(papi);
421
- return {
422
- path: params.path,
423
- method: params.method,
424
- options: params.options,
425
- type: 'private',
426
- };
427
- }),
428
- ...flatten(publicRoutes).map((papi) => {
429
- const params = getPapiParameters(papi);
430
- return {
431
- path: params.path,
432
- method: params.method,
433
- options: params.options,
434
- type: 'public',
435
- };
436
- }),
437
- ];
438
- },
439
- });
440
- // eslint-disable-next-line no-param-reassign
441
- privateRoutes = privateRoutes
442
- ? [...toArray(privateRoutes), papiListRoute]
443
- : [papiListRoute];
444
- }
445
- if (privateRoutes) {
446
- createApi(app, flatten(privateRoutes), {
447
- baseUrl: privateBaseUrl,
448
- di,
449
- logger,
450
- });
451
- }
452
- if (publicRoutes) {
453
- createApi(app, flatten(publicRoutes), {
454
- baseUrl: publicBaseUrl,
455
- di,
456
- logger,
457
- });
458
- }
459
- },
460
- deps: {
461
- di: DI_TOKEN$1,
462
- logger: LOGGER_TOKEN,
463
- privateRoutes: {
464
- token: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
465
- optional: true,
466
- multi: true,
467
- },
468
- publicRoutes: {
469
- token: SERVER_MODULE_PAPI_PUBLIC_ROUTE,
470
- optional: true,
471
- multi: true,
472
- },
473
- privateBaseUrl: SERVER_MODULE_PAPI_PRIVATE_URL,
474
- publicBaseUrl: SERVER_MODULE_PAPI_PUBLIC_URL,
475
- },
476
- multi: true,
477
- }),
478
- // необходимо для утилит. Подумать как можно убрать в будующем. Если убрать не будет ломающим изменением
479
- provide$1({
480
- provide: SERVER_MODULE_PAPI_PUBLIC_ROUTE,
481
- multi: true,
482
- useValue: createPapiMethod({
483
- method: 'get',
484
- path: '/version',
485
- async handler() {
486
- return {
487
- version: this.deps.envManager.get('APP_VERSION'),
488
- };
489
- },
490
- deps: {
491
- envManager: ENV_MANAGER_TOKEN,
492
- },
493
- }),
494
- }),
495
- ],
496
- })
497
- ], ServerPapiModule);
498
-
499
- let BrowserPapiModule = class BrowserPapiModule {
500
- };
501
- BrowserPapiModule = __decorate([
502
- Module({
503
- providers: [...sharedProviders],
504
- })
505
- ], BrowserPapiModule);
506
-
507
- const ONE_YEAR = 365 * 24 * 60 * 60;
508
- let ServerStaticsModule = class ServerStaticsModule {
509
- };
510
- ServerStaticsModule = __decorate([
511
- Module({
512
- providers: [
513
- provide$1({
514
- provide: WEB_FASTIFY_APP_BEFORE_INIT_TOKEN,
515
- useFactory: ({ options }) => {
516
- const path = (options === null || options === void 0 ? void 0 : options.path) || 'public';
517
- return (instance) => {
518
- instance.register(FastifyStatic, {
519
- decorateReply: false,
520
- // for backward compatibility, leaving default prefix.
521
- // without `wildcard: false` property, this middleware has conflicts with express compatibility plugin
522
- prefix: `/`,
523
- // prevent errors by use FastifyStatic only for all defined files in the served folder,
524
- // will not serve the newly added file on the filesystem - https://github.com/fastify/fastify-static#wildcard
525
- wildcard: false,
526
- root: resolve(process.cwd(), path),
527
- setHeaders: (res) => {
528
- const oneYearForward = new Date(Date.now() + ONE_YEAR * 1000);
529
- res.setHeader('cache-control', `public, max-age=${ONE_YEAR}`);
530
- res.setHeader('expires', oneYearForward.toUTCString());
531
- },
532
- });
533
- };
534
- },
535
- deps: {
536
- options: {
537
- token: SERVER_MODULE_STATICS_OPTIONS,
538
- optional: true,
539
- },
540
- },
541
- multi: true,
542
- }),
543
- ],
544
- })
545
- ], ServerStaticsModule);
546
-
547
- const GRACEFUL_SHUTDOWN_TIMEOUT = 25000;
548
- const GRACEFUL_READINESS_TIMEOUT = 5000;
549
- const noopCheck = () => { };
550
- let ServerGracefulShutdownModule = class ServerGracefulShutdownModule {
551
- };
552
- ServerGracefulShutdownModule = __decorate([
553
- Module({
554
- providers: [
555
- provide$1({
556
- provide: WEB_FASTIFY_APP_BEFORE_INIT_TOKEN,
557
- multi: true,
558
- useFactory: ({ app, server, logger, commandLineRunner, livenessPath, readinessPath, livenessProbe, readinessProbe, }) => {
559
- const log = logger('server');
560
- return function serverListen() {
561
- createTerminus(server, app, {
562
- signal: 'SIGTERM',
563
- timeout: GRACEFUL_SHUTDOWN_TIMEOUT,
564
- logger: (msg, error) => {
565
- log.error({
566
- event: 'terminus',
567
- message: msg,
568
- error,
569
- });
570
- },
571
- // https://github.com/godaddy/terminus#how-to-set-terminus-up-with-kubernetes
572
- beforeShutdown: () => {
573
- log.warn({
574
- event: 'terminus-wait',
575
- message: 'wait for other tasks before shutdown',
576
- });
577
- return new Promise((resolve) => setTimeout(resolve, GRACEFUL_READINESS_TIMEOUT));
578
- },
579
- onSignal: () => {
580
- log.warn({
581
- event: 'terminus-run-command',
582
- message: 'run commandLineRunner close line',
583
- });
584
- commandLineRunner.run('server', 'close');
585
- },
586
- onShutdown: () => {
587
- log.warn({
588
- event: 'terminus-exit',
589
- message: 'calling process.exit',
590
- });
591
- process.exit();
592
- },
593
- healthChecks: {
594
- [livenessPath]: livenessProbe || noopCheck,
595
- [readinessPath]: readinessProbe || noopCheck,
596
- },
597
- });
598
- };
599
- },
600
- deps: {
601
- app: UTILITY_WEB_FASTIFY_APP_TOKEN,
602
- server: SERVER_TOKEN,
603
- logger: LOGGER_TOKEN,
604
- commandLineRunner: COMMAND_LINE_RUNNER_TOKEN,
605
- livenessPath: LIVENESS_PATH_TOKEN,
606
- readinessPath: READINESS_PATH_TOKEN,
607
- readinessProbe: { token: READINESS_PROBE_TOKEN, optional: true },
608
- livenessProbe: { token: LIVENESS_PROBE_TOKEN, optional: true },
609
- },
610
- }),
611
- provide$1({
612
- provide: LIVENESS_PATH_TOKEN,
613
- useValue: '/healthz',
614
- }),
615
- provide$1({
616
- provide: READINESS_PATH_TOKEN,
617
- useValue: '/readyz',
618
- }),
619
- provide$1({
620
- provide: UTILITY_SERVER_PATHS,
621
- useFactory: ({ livenessPath }) => {
622
- return livenessPath;
623
- },
624
- multi: true,
625
- deps: {
626
- livenessPath: LIVENESS_PATH_TOKEN,
627
- },
628
- }),
629
- provide$1({
630
- provide: UTILITY_SERVER_PATHS,
631
- useFactory: ({ readinessPath }) => {
632
- return readinessPath;
633
- },
634
- multi: true,
635
- deps: {
636
- readinessPath: READINESS_PATH_TOKEN,
637
- },
638
- }),
639
- ],
640
- })
641
- ], ServerGracefulShutdownModule);
642
-
643
- class Interceptor {
644
- constructor() {
645
- this.intercepted = false;
646
- this.delay = 0;
647
- }
648
- setIntercept(intercept) {
649
- this.intercepted = intercept;
650
- }
651
- setDelay(delay) {
652
- this.intercepted = true;
653
- this.delay = delay;
654
- }
655
- clear() {
656
- this.intercepted = false;
657
- this.delay = 0;
658
- }
659
- getStatus() {
660
- return {
661
- intercepted: this.intercepted,
662
- delay: this.delay,
663
- };
664
- }
665
- }
666
- const INTERCEPTOR_TOKEN = 'debugRequestsInterceptor';
667
- let DebugHttpRequestsModule = class DebugHttpRequestsModule {
668
- };
669
- DebugHttpRequestsModule = __decorate([
670
- Module({
671
- providers: [
672
- {
673
- provide: INTERCEPTOR_TOKEN,
674
- useClass: Interceptor,
675
- scope: Scope.SINGLETON,
676
- },
677
- {
678
- provide: commandLineListTokens.init,
679
- multi: true,
680
- useFactory: ({ logger, interceptor }) => {
681
- const log = logger('server:node-debug:request');
682
- return function debugHttp() {
683
- const handler = (request, options, cb) => {
684
- const parsed = typeof options === 'string' ? parse(options) : options;
685
- const wasHandled = typeof cb === 'function';
686
- return request(options, cb)
687
- .on('response', (response) => {
688
- interceptor.intercepted &&
689
- monkeypatch({
690
- obj: response,
691
- method: 'emit',
692
- handler: (emit, event, ...args) => {
693
- if (event === 'end') {
694
- setTimeout(() => {
695
- emit(event, ...args);
696
- }, interceptor.delay);
697
- return !!response.listenerCount(event);
698
- }
699
- return emit(event, ...args);
700
- },
701
- });
702
- })
703
- .on('response', (response) => {
704
- // Workaround for res._dump in Node.JS http client
705
- // https://github.com/nodejs/node/blob/20285ad17755187ece16b8a5effeaa87f5407da2/lib/_http_client.js#L421-L427
706
- if (!wasHandled && EventEmitter.listenerCount(response.req, 'response') === 0) {
707
- response.resume();
708
- }
709
- log.debug(`${response.statusCode}
710
- ${parsed.href || `${parsed.protocol}//${parsed.hostname}${parsed.path}`}
711
- `);
712
- })
713
- .on('error', (error) => {
714
- log.error({
715
- event: 'request-failed',
716
- error,
717
- url: parsed.href || options,
718
- });
719
- });
720
- };
721
- monkeypatch({ obj: http, method: 'request', handler });
722
- monkeypatch({ obj: https, method: 'request', handler });
723
- };
724
- },
725
- deps: {
726
- logger: LOGGER_TOKEN,
727
- interceptor: INTERCEPTOR_TOKEN,
728
- },
729
- },
730
- {
731
- provide: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
732
- multi: true,
733
- useFactory: ({ interceptor }) => {
734
- return createPapiMethod({
735
- method: 'post',
736
- path: '/debug-http-request',
737
- async handler({ body }) {
738
- const { delay = 10000 } = body;
739
- if (delay) {
740
- interceptor.setDelay(delay);
741
- }
742
- else {
743
- interceptor.setIntercept(true);
744
- }
745
- return interceptor.getStatus();
746
- },
747
- });
748
- },
749
- deps: {
750
- interceptor: INTERCEPTOR_TOKEN,
751
- },
752
- },
753
- {
754
- provide: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
755
- multi: true,
756
- useFactory: ({ interceptor }) => {
757
- return createPapiMethod({
758
- method: 'delete',
759
- path: '/debug-http-request',
760
- async handler() {
761
- interceptor.clear();
762
- return interceptor.getStatus();
763
- },
764
- });
765
- },
766
- deps: {
767
- interceptor: INTERCEPTOR_TOKEN,
768
- },
769
- },
770
- ],
771
- })
772
- ], DebugHttpRequestsModule);
773
-
774
- const nodeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
775
- const safeNodeRequire = (path) => {
776
- try {
777
- return nodeRequire(path);
778
- }
779
- catch (e) {
780
- return null;
781
- }
782
- };
783
-
784
- let ServerProxyModule = class ServerProxyModule {
785
- };
786
- ServerProxyModule = __decorate([
787
- Module({
788
- providers: [
789
- {
790
- provide: WEB_FASTIFY_APP_INIT_TOKEN,
791
- useFactory: ({ defaultProxies }) => {
792
- return (app) => {
793
- const proxyConfig = safeNodeRequire(resolve(process.cwd(), 'proxy.conf'));
794
- const proxies = defaultProxies !== null && defaultProxies !== void 0 ? defaultProxies : [];
795
- if (!proxyConfig && proxies.length === 0) {
796
- return;
797
- }
798
- if (isArray(proxyConfig)) {
799
- proxies.push(...proxyConfig);
800
- }
801
- else if (proxyConfig === null || proxyConfig === void 0 ? void 0 : proxyConfig.target) {
802
- proxies.push(proxyConfig);
803
- }
804
- else if (isObject(proxyConfig)) {
805
- eachObj((target, source) => {
806
- const options = typeof target === 'string' ? { target } : target;
807
- proxies.push({ context: source, ...options });
808
- }, proxyConfig);
809
- }
810
- proxies.forEach((proxy) => {
811
- const middleware = createProxyMiddleware(proxy.context, {
812
- changeOrigin: true,
813
- onProxyRes: (proxyRes) => {
814
- // eslint-disable-next-line no-param-reassign
815
- proxyRes.headers['x-tramvai-proxied-response'] = '1';
816
- },
817
- ...proxy,
818
- });
819
- app.addHook('onRequest', (req, res, next) => {
820
- middleware(req.raw, res.raw, next);
821
- });
822
- });
823
- };
824
- },
825
- deps: {
826
- defaultProxies: {
827
- token: PROXY_CONFIG_TOKEN,
828
- optional: true,
829
- },
830
- },
831
- multi: true,
832
- },
833
- ],
834
- })
835
- ], ServerProxyModule);
836
-
837
- const RegExp = /^@tramvai/;
838
- const tramvaiDepsFilter = (deps) => {
839
- return filterObj((v, k) => RegExp.test(k), deps);
840
- };
841
-
842
- let packageJson = {};
843
- try {
844
- // eslint-disable-next-line import/no-unresolved
845
- packageJson = require('../../../../package.json');
846
- }
847
- catch (e) {
848
- packageJson = safeNodeRequire(resolve(process.cwd(), 'package.json'));
849
- }
850
- let DependenciesVersionModule = class DependenciesVersionModule {
851
- };
852
- DependenciesVersionModule = __decorate([
853
- Module({
854
- providers: [
855
- {
856
- provide: SERVER_MODULE_PAPI_PRIVATE_ROUTE,
857
- multi: true,
858
- useFactory: ({ depsFilter }) => {
859
- const { dependencies = [] } = packageJson !== null && packageJson !== void 0 ? packageJson : {};
860
- return createPapiMethod({
861
- path: '/dependenciesVersion',
862
- method: 'get',
863
- handler: async () => {
864
- return depsFilter(dependencies);
865
- },
866
- });
867
- },
868
- deps: {
869
- depsFilter: DEPENDENCIES_VERSION_FILTER_TOKEN,
870
- },
871
- },
872
- {
873
- provide: DEPENDENCIES_VERSION_FILTER_TOKEN,
874
- useValue: tramvaiDepsFilter,
875
- },
876
- ],
877
- })
878
- ], DependenciesVersionModule);
879
-
880
- const IS_CUSTOM_SERVER_TOKEN = createToken('server utility isCustomServer');
881
- let UtilityServerModule = class UtilityServerModule {
882
- };
883
- UtilityServerModule = __decorate([
884
- Module({
885
- providers: [
886
- provide$1({
887
- provide: ENV_USED_TOKEN,
888
- multi: true,
889
- useValue: [{ key: 'UTILITY_SERVER_PORT', optional: true }],
890
- }),
891
- provide$1({
892
- provide: UTILITY_SERVER_PORT_TOKEN,
893
- scope: Scope.SINGLETON,
894
- useFactory: ({ envManager }) => {
895
- return +(envManager.get('UTILITY_SERVER_PORT') || envManager.get('PORT'));
896
- },
897
- deps: {
898
- envManager: ENV_MANAGER_TOKEN,
899
- },
900
- }),
901
- provide$1({
902
- provide: IS_CUSTOM_SERVER_TOKEN,
903
- scope: Scope.SINGLETON,
904
- useFactory: ({ port, envManager }) => {
905
- return +envManager.get('PORT') !== port;
906
- },
907
- deps: {
908
- envManager: ENV_MANAGER_TOKEN,
909
- port: UTILITY_SERVER_PORT_TOKEN,
910
- },
911
- }),
912
- provide$1({
913
- provide: UTILITY_SERVER_TOKEN,
914
- scope: Scope.SINGLETON,
915
- useFactory: ({ isCustomServer, serverFactory, server }) => {
916
- return isCustomServer ? serverFactory() : server;
917
- },
918
- deps: {
919
- isCustomServer: IS_CUSTOM_SERVER_TOKEN,
920
- server: SERVER_TOKEN,
921
- serverFactory: SERVER_FACTORY_TOKEN,
922
- },
923
- }),
924
- provide$1({
925
- provide: UTILITY_WEB_FASTIFY_APP_TOKEN,
926
- scope: Scope.SINGLETON,
927
- useFactory: ({ isCustomServer, app, appFactory, server }) => {
928
- return isCustomServer ? appFactory({ server }) : app;
929
- },
930
- deps: {
931
- isCustomServer: IS_CUSTOM_SERVER_TOKEN,
932
- app: WEB_FASTIFY_APP_TOKEN,
933
- appFactory: WEB_FASTIFY_APP_FACTORY_TOKEN,
934
- server: UTILITY_SERVER_TOKEN,
935
- },
936
- }),
937
- provide$1({
938
- provide: commandLineListTokens.listen,
939
- multi: true,
940
- scope: Scope.SINGLETON,
941
- useFactory: ({ logger, isCustomServer, port, app, server }) => {
942
- return async function utilityServerListen() {
943
- if (!isCustomServer) {
944
- return;
945
- }
946
- const log = logger('server:utility');
947
- await app.ready();
948
- return new Promise((resolve, reject) => {
949
- server.once('error', (error) => {
950
- log.error({ event: 'server-listen-port', error });
951
- reject(error);
952
- });
953
- server.listen(port, () => {
954
- log.warn({ event: 'server-listen-port', message: `Server listen ${port} port` });
955
- resolve();
956
- });
957
- });
958
- };
959
- },
960
- deps: {
961
- logger: LOGGER_TOKEN,
962
- isCustomServer: IS_CUSTOM_SERVER_TOKEN,
963
- port: UTILITY_SERVER_PORT_TOKEN,
964
- app: UTILITY_WEB_FASTIFY_APP_TOKEN,
965
- server: UTILITY_SERVER_TOKEN,
966
- },
967
- }),
968
- ],
969
- })
970
- ], UtilityServerModule);
971
-
972
- let KeepAliveModule = class KeepAliveModule {
973
- };
974
- KeepAliveModule = __decorate([
975
- Module({
976
- providers: [
977
- provide$1({
978
- provide: ENV_USED_TOKEN,
979
- useValue: [
980
- {
981
- key: 'NODE_KEEPALIVE_TIMEOUT',
982
- optional: true,
983
- validator(keepAliveTimeout) {
984
- const value = Number(keepAliveTimeout);
985
- if (Number.isNaN(value)) {
986
- return 'Env variable NODE_KEEPALIVE_TIMEOUT should be a number';
987
- }
988
- if (value < 0) {
989
- return 'Env variable NODE_KEEPALIVE_TIMEOUT should be greater or equal than 0';
990
- }
991
- return true;
992
- },
993
- },
994
- ],
995
- }),
996
- provide$1({
997
- provide: commandLineListTokens.init,
998
- useFactory: ({ server, envManager, }) => () => {
999
- const externalKeepAliveTimeout = envManager.get('NODE_KEEPALIVE_TIMEOUT');
1000
- if (externalKeepAliveTimeout !== 'undefined') {
1001
- // eslint-disable-next-line no-param-reassign
1002
- server.keepAliveTimeout = Number(externalKeepAliveTimeout);
1003
- }
1004
- },
1005
- multi: true,
1006
- deps: { server: SERVER_TOKEN, envManager: ENV_MANAGER_TOKEN$1 },
1007
- }),
1008
- ],
1009
- })
1010
- ], KeepAliveModule);
1011
-
1012
- const ServerTimingModule = declareModule({
1013
- name: 'ServerTiming',
1014
- providers: [
1015
- provide$1({
1016
- provide: COMMAND_LINE_EXECUTION_END_TOKEN,
1017
- multi: true,
1018
- useValue: (di, type, status, timingInfo) => {
1019
- var _a;
1020
- if (type === 'server' && status === 'customer') {
1021
- const responseManager = di.get(RESPONSE_MANAGER_TOKEN);
1022
- const initialHeader = (_a = responseManager.getHeader('Server-Timing')) !== null && _a !== void 0 ? _a : '';
1023
- const entries = [];
1024
- // index for custom sort
1025
- let index = 0;
1026
- for (const line in timingInfo) {
1027
- const info = timingInfo[line];
1028
- entries.push(`line_${index++}_${line};dur=${info.end - info.start}`);
1029
- }
1030
- responseManager.setHeader('Server-Timing', `${initialHeader ? `${initialHeader}, ` : ''}${entries.join(', ')}`);
1031
- }
1032
- },
1033
- }),
1034
- ],
1035
- });
11
+ import { serverFactory, serverListenCommand } from './server/server.es.js';
12
+ import { webAppFactory, webAppInitCommand } from './server/webApp.es.js';
13
+ import { staticAppCommand } from './server/static.es.js';
14
+ import { xHeadersFactory } from './server/xHeaders.es.js';
15
+ import { ServerPapiModule } from './modules/papi/papi.es.js';
16
+ import './modules/papi/papi.browser.es.js';
17
+ import { ServerStaticsModule } from './modules/statics.es.js';
18
+ import { ServerGracefulShutdownModule } from './modules/gracefulShutdown.es.js';
19
+ import { DebugHttpRequestsModule } from './modules/debugRequests.es.js';
20
+ import { ServerProxyModule } from './modules/proxy.es.js';
21
+ import { DependenciesVersionModule } from './modules/dependenciesVersion.es.js';
22
+ import { UtilityServerModule } from './modules/utilityServer.es.js';
23
+ import { KeepAliveModule } from './modules/keepAlive.es.js';
24
+ import { ServerTimingModule } from './modules/serverTiming.es.js';
1036
25
 
1037
26
  if (typeof setDefaultResultOrder === 'function') {
1038
27
  setDefaultResultOrder('ipv4first');
1039
28
  }
1040
29
  // tramvai add a lot of "abort" event listeners to AbortSignal, but we can't configure only AbortSignal max listeners,
1041
30
  // because AbortSignal is not instance of EventEmitter - https://github.com/southpolesteve/node-abort-controller/blob/master/index.js
1042
- EventEmitter$1.defaultMaxListeners = 50;
31
+ EventEmitter.defaultMaxListeners = 50;
1043
32
  let ServerModule = class ServerModule {
1044
33
  };
1045
34
  ServerModule = __decorate([
@@ -1058,12 +47,12 @@ ServerModule = __decorate([
1058
47
  process.env.NODE_ENV !== 'production' && DebugHttpRequestsModule,
1059
48
  ].filter(Boolean),
1060
49
  providers: [
1061
- provide$1({
50
+ provide({
1062
51
  provide: SERVER_FACTORY_TOKEN,
1063
52
  scope: Scope.SINGLETON,
1064
53
  useValue: serverFactory,
1065
54
  }),
1066
- provide$1({
55
+ provide({
1067
56
  provide: SERVER_TOKEN,
1068
57
  scope: Scope.SINGLETON,
1069
58
  useFactory: ({ factory }) => factory(),
@@ -1071,12 +60,12 @@ ServerModule = __decorate([
1071
60
  factory: SERVER_FACTORY_TOKEN,
1072
61
  },
1073
62
  }),
1074
- provide$1({
63
+ provide({
1075
64
  provide: WEB_FASTIFY_APP_FACTORY_TOKEN,
1076
65
  scope: Scope.SINGLETON,
1077
66
  useValue: webAppFactory,
1078
67
  }),
1079
- provide$1({
68
+ provide({
1080
69
  provide: WEB_FASTIFY_APP_TOKEN,
1081
70
  useFactory: ({ factory, server }) => factory({ server }),
1082
71
  scope: Scope.SINGLETON,