@sima-land/isomorph 11.0.0-alpha.0 → 11.0.0-alpha.1

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 (213) hide show
  1. package/{dist/cache → cache}/types.d.ts +0 -0
  2. package/{dist/utils/webpack/module-federation → cache}/types.js +0 -0
  3. package/{dist/cache → cache}/types.js.map +0 -0
  4. package/{dist/config → config}/browser.d.ts +0 -0
  5. package/{dist/config → config}/browser.js +0 -0
  6. package/{dist/config → config}/browser.js.map +0 -0
  7. package/{dist/config → config}/index.d.ts +0 -0
  8. package/{dist/config → config}/index.js +0 -0
  9. package/{dist/config → config}/index.js.map +0 -0
  10. package/{dist/config → config}/node.d.ts +0 -0
  11. package/{dist/config → config}/node.js +0 -0
  12. package/{dist/config → config}/node.js.map +0 -0
  13. package/{dist/config → config}/types.d.ts +0 -0
  14. package/{dist/tracer → config}/types.js +0 -0
  15. package/{dist/config → config}/types.js.map +0 -0
  16. package/{dist/config → config}/utils.d.ts +0 -0
  17. package/{dist/config → config}/utils.js +0 -0
  18. package/{dist/config → config}/utils.js.map +0 -0
  19. package/{dist/container → container}/application.d.ts +0 -0
  20. package/{dist/container → container}/application.js +0 -0
  21. package/{dist/container → container}/application.js.map +0 -0
  22. package/{dist/container → container}/index.d.ts +0 -0
  23. package/{dist/container → container}/index.js +0 -0
  24. package/{dist/container → container}/index.js.map +0 -0
  25. package/{dist/container → container}/types.d.ts +0 -0
  26. package/{dist/saga-runner → container}/types.js +0 -0
  27. package/{dist/container → container}/types.js.map +0 -0
  28. package/{dist/error-tracker → error-tracker}/browser.d.ts +0 -0
  29. package/{dist/error-tracker → error-tracker}/browser.js +0 -0
  30. package/{dist/error-tracker → error-tracker}/browser.js.map +0 -0
  31. package/{dist/error-tracker → error-tracker}/node.d.ts +0 -0
  32. package/{dist/error-tracker → error-tracker}/node.js +0 -0
  33. package/{dist/error-tracker → error-tracker}/node.js.map +0 -0
  34. package/{dist/error-tracker → error-tracker}/types.d.ts +0 -0
  35. package/{dist/preset → error-tracker}/types.js +0 -0
  36. package/{dist/error-tracker → error-tracker}/types.js.map +0 -0
  37. package/{dist/error-tracker → error-tracker}/utils.d.ts +0 -0
  38. package/{dist/error-tracker → error-tracker}/utils.js +0 -0
  39. package/{dist/error-tracker → error-tracker}/utils.js.map +0 -0
  40. package/{dist/http-client → http-client}/middleware/cookie.d.ts +0 -0
  41. package/{dist/http-client → http-client}/middleware/cookie.js +0 -0
  42. package/{dist/http-client → http-client}/middleware/cookie.js.map +0 -0
  43. package/{dist/http-client → http-client}/middleware/tracing.d.ts +0 -0
  44. package/{dist/http-client → http-client}/middleware/tracing.js +0 -0
  45. package/{dist/http-client → http-client}/middleware/tracing.js.map +0 -0
  46. package/{dist/http-client → http-client}/types.d.ts +0 -0
  47. package/{dist/logger → http-client}/types.js +0 -0
  48. package/{dist/http-client → http-client}/types.js.map +0 -0
  49. package/{dist/http-client → http-client}/utils.d.ts +0 -0
  50. package/{dist/http-client → http-client}/utils.js +0 -0
  51. package/{dist/http-client → http-client}/utils.js.map +0 -0
  52. package/{dist/http-server → http-server}/constants.d.ts +0 -0
  53. package/{dist/http-server → http-server}/constants.js +0 -0
  54. package/{dist/http-server → http-server}/constants.js.map +0 -0
  55. package/{dist/http-server → http-server}/handler/health-check.d.ts +0 -0
  56. package/{dist/http-server → http-server}/handler/health-check.js +0 -0
  57. package/{dist/http-server → http-server}/handler/health-check.js.map +0 -0
  58. package/{dist/http-server → http-server}/middleware/logging.d.ts +0 -0
  59. package/{dist/http-server → http-server}/middleware/logging.js +0 -0
  60. package/{dist/http-server → http-server}/middleware/logging.js.map +0 -0
  61. package/{dist/http-server → http-server}/middleware/metrics.d.ts +0 -0
  62. package/{dist/http-server → http-server}/middleware/metrics.js +0 -0
  63. package/{dist/http-server → http-server}/middleware/metrics.js.map +0 -0
  64. package/{dist/http-server → http-server}/middleware/tracing.d.ts +0 -0
  65. package/{dist/http-server → http-server}/middleware/tracing.js +0 -0
  66. package/{dist/http-server → http-server}/middleware/tracing.js.map +0 -0
  67. package/http-server/template/index.d.ts +1 -0
  68. package/http-server/template/index.js +36 -0
  69. package/http-server/template/index.js.map +1 -0
  70. package/{dist/http-server → http-server}/types.d.ts +8 -0
  71. package/{dist/http-server → http-server}/types.js +0 -0
  72. package/{dist/http-server → http-server}/types.js.map +0 -0
  73. package/{dist/http-server → http-server}/utils.d.ts +5 -1
  74. package/{dist/http-server → http-server}/utils.js +16 -4
  75. package/http-server/utils.js.map +1 -0
  76. package/{dist/logger → logger}/handler/console.d.ts +0 -0
  77. package/{dist/logger → logger}/handler/console.js +0 -0
  78. package/{dist/logger → logger}/handler/console.js.map +0 -0
  79. package/{dist/logger → logger}/handler/sentry.d.ts +0 -0
  80. package/{dist/logger → logger}/handler/sentry.js +0 -0
  81. package/{dist/logger → logger}/handler/sentry.js.map +0 -0
  82. package/{dist/logger → logger}/index.d.ts +0 -0
  83. package/{dist/logger → logger}/index.js +0 -0
  84. package/{dist/logger → logger}/index.js.map +0 -0
  85. package/{dist/logger → logger}/types.d.ts +0 -0
  86. package/{dist/http-client → logger}/types.js +0 -0
  87. package/{dist/logger → logger}/types.js.map +0 -0
  88. package/{dist/metrics → metrics}/constants.d.ts +0 -0
  89. package/{dist/metrics → metrics}/constants.js +0 -0
  90. package/{dist/metrics → metrics}/constants.js.map +0 -0
  91. package/{dist/metrics → metrics}/node.d.ts +0 -0
  92. package/{dist/metrics → metrics}/node.js +0 -0
  93. package/{dist/metrics → metrics}/node.js.map +0 -0
  94. package/package.json +5 -10
  95. package/{dist/preset → preset}/index.d.ts +0 -0
  96. package/{dist/preset → preset}/index.js +5 -3
  97. package/preset/index.js.map +1 -0
  98. package/{dist/preset → preset}/node/index.d.ts +0 -0
  99. package/{dist/preset → preset}/node/index.js +0 -0
  100. package/{dist/preset → preset}/node/index.js.map +0 -0
  101. package/{dist/preset → preset}/node/response.d.ts +6 -1
  102. package/{dist/preset → preset}/node/response.js +28 -2
  103. package/preset/node/response.js.map +1 -0
  104. package/{dist/preset → preset}/types.d.ts +2 -2
  105. package/{dist/error-tracker → preset}/types.js +0 -0
  106. package/{dist/preset → preset}/types.js.map +0 -0
  107. package/{dist/saga-runner → saga-runner}/index.d.ts +0 -0
  108. package/{dist/saga-runner → saga-runner}/index.js +3 -1
  109. package/saga-runner/index.js.map +1 -0
  110. package/{dist/saga-runner → saga-runner}/types.d.ts +0 -0
  111. package/{dist/container → saga-runner}/types.js +0 -0
  112. package/{dist/saga-runner → saga-runner}/types.js.map +0 -0
  113. package/{dist/tokens.d.ts → tokens.d.ts} +2 -1
  114. package/{dist/tokens.js → tokens.js} +1 -0
  115. package/{dist/tokens.js.map → tokens.js.map} +1 -1
  116. package/{dist/tracer → tracer}/node.d.ts +0 -0
  117. package/{dist/tracer → tracer}/node.js +0 -0
  118. package/{dist/tracer → tracer}/node.js.map +0 -0
  119. package/{dist/tracer → tracer}/types.d.ts +0 -0
  120. package/{dist/config → tracer}/types.js +0 -0
  121. package/{dist/tracer → tracer}/types.js.map +0 -0
  122. package/{dist/utils → utils}/browser/analytics/data-layer.d.ts +0 -0
  123. package/{dist/utils → utils}/browser/analytics/data-layer.js +0 -0
  124. package/{dist/utils → utils}/browser/analytics/data-layer.js.map +0 -0
  125. package/{dist/utils → utils}/browser/analytics/oko.d.ts +0 -0
  126. package/{dist/utils → utils}/browser/analytics/oko.js +0 -0
  127. package/{dist/utils → utils}/browser/analytics/oko.js.map +0 -0
  128. package/{dist/utils → utils}/browser/storage/index.d.ts +0 -0
  129. package/{dist/utils → utils}/browser/storage/index.js +0 -0
  130. package/{dist/utils → utils}/browser/storage/index.js.map +0 -0
  131. package/{dist/utils → utils}/number.d.ts +0 -0
  132. package/{dist/utils → utils}/number.js +0 -0
  133. package/{dist/utils → utils}/number.js.map +0 -0
  134. package/{dist/utils → utils}/react/error-handlers/index.d.ts +0 -0
  135. package/{dist/utils → utils}/react/error-handlers/index.js +0 -0
  136. package/{dist/utils → utils}/react/error-handlers/index.js.map +0 -0
  137. package/{dist/utils → utils}/redux/remote-data.d.ts +0 -0
  138. package/{dist/utils → utils}/redux/remote-data.js +0 -0
  139. package/{dist/utils → utils}/redux/remote-data.js.map +0 -0
  140. package/{dist/utils → utils}/redux-saga/take-chain.d.ts +0 -0
  141. package/{dist/utils → utils}/redux-saga/take-chain.js +0 -0
  142. package/{dist/utils → utils}/redux-saga/take-chain.js.map +0 -0
  143. package/{dist/utils → utils}/webpack/module-federation/index.d.ts +0 -0
  144. package/{dist/utils → utils}/webpack/module-federation/index.js +0 -0
  145. package/{dist/utils → utils}/webpack/module-federation/index.js.map +0 -0
  146. package/{dist/utils → utils}/webpack/module-federation/types.d.ts +0 -0
  147. package/{dist/cache → utils/webpack/module-federation}/types.js +0 -0
  148. package/{dist/utils → utils}/webpack/module-federation/types.js.map +0 -0
  149. package/{dist/utils → utils}/webpack/module-federation/utils.d.ts +0 -0
  150. package/{dist/utils → utils}/webpack/module-federation/utils.js +0 -0
  151. package/{dist/utils → utils}/webpack/module-federation/utils.js.map +0 -0
  152. package/LICENSE +0 -201
  153. package/dist/http-server/utils.js.map +0 -1
  154. package/dist/preset/index.js.map +0 -1
  155. package/dist/preset/node/response.js.map +0 -1
  156. package/dist/saga-runner/index.js.map +0 -1
  157. package/readme.md +0 -23
  158. package/src/cache/types.ts +0 -7
  159. package/src/config/browser.ts +0 -10
  160. package/src/config/index.ts +0 -18
  161. package/src/config/node.ts +0 -18
  162. package/src/config/types.ts +0 -9
  163. package/src/config/utils.ts +0 -7
  164. package/src/container/application.ts +0 -91
  165. package/src/container/index.ts +0 -79
  166. package/src/container/types.ts +0 -17
  167. package/src/error-tracker/browser.ts +0 -14
  168. package/src/error-tracker/node.ts +0 -14
  169. package/src/error-tracker/types.ts +0 -22
  170. package/src/error-tracker/utils.ts +0 -18
  171. package/src/http-client/middleware/cookie.ts +0 -73
  172. package/src/http-client/middleware/tracing.ts +0 -79
  173. package/src/http-client/types.ts +0 -8
  174. package/src/http-client/utils.ts +0 -76
  175. package/src/http-server/constants.ts +0 -4
  176. package/src/http-server/handler/health-check.ts +0 -13
  177. package/src/http-server/middleware/logging.ts +0 -34
  178. package/src/http-server/middleware/metrics.ts +0 -87
  179. package/src/http-server/middleware/tracing.ts +0 -35
  180. package/src/http-server/types.ts +0 -29
  181. package/src/http-server/utils.ts +0 -105
  182. package/src/logger/handler/console.ts +0 -35
  183. package/src/logger/handler/sentry.ts +0 -38
  184. package/src/logger/index.ts +0 -31
  185. package/src/logger/types.ts +0 -28
  186. package/src/metrics/constants.ts +0 -4
  187. package/src/metrics/node.ts +0 -54
  188. package/src/preset/index.ts +0 -24
  189. package/src/preset/node/index.ts +0 -101
  190. package/src/preset/node/response.ts +0 -57
  191. package/src/preset/types.ts +0 -9
  192. package/src/saga-runner/index.ts +0 -59
  193. package/src/saga-runner/types.ts +0 -13
  194. package/src/tokens.ts +0 -54
  195. package/src/tracer/node.ts +0 -40
  196. package/src/tracer/types.ts +0 -3
  197. package/src/utils/browser/analytics/__test__/data-layer.test.ts +0 -50
  198. package/src/utils/browser/analytics/__test__/oko.test.tsx +0 -143
  199. package/src/utils/browser/analytics/data-layer.ts +0 -12
  200. package/src/utils/browser/analytics/oko.ts +0 -44
  201. package/src/utils/browser/storage/index.ts +0 -75
  202. package/src/utils/number.ts +0 -8
  203. package/src/utils/react/error-handlers/__test__/__snapshots__/index.test.tsx.snap +0 -27
  204. package/src/utils/react/error-handlers/__test__/index.test.tsx +0 -64
  205. package/src/utils/react/error-handlers/index.tsx +0 -62
  206. package/src/utils/redux/__test__/remote-data.test.ts +0 -50
  207. package/src/utils/redux/remote-data.ts +0 -34
  208. package/src/utils/redux-saga/__test__/take-chain.test.ts +0 -141
  209. package/src/utils/redux-saga/take-chain.ts +0 -65
  210. package/src/utils/webpack/module-federation/__test__/index.test.ts +0 -246
  211. package/src/utils/webpack/module-federation/index.ts +0 -92
  212. package/src/utils/webpack/module-federation/types.ts +0 -44
  213. package/src/utils/webpack/module-federation/utils.ts +0 -43
@@ -1,22 +0,0 @@
1
- import type { Client, Severity, Context, Extra } from '@sentry/types';
2
- import type { withScope as withScopeBrowser } from '@sentry/browser';
3
- import type { withScope as withScopeNode } from '@sentry/node';
4
-
5
- export interface SentryLib {
6
- client: Client;
7
- withScope: typeof withScopeBrowser | typeof withScopeNode;
8
- }
9
-
10
- export interface SentryErrorData {
11
- level?: Severity;
12
-
13
- context?: {
14
- key: string;
15
- data: Context | null;
16
- };
17
-
18
- extra?: {
19
- key: string;
20
- data: Extra | null;
21
- };
22
- }
@@ -1,18 +0,0 @@
1
- import { SentryErrorData } from './types';
2
-
3
- /**
4
- * Ошибка с данными для Sentry.
5
- */
6
- export class SentryError extends Error {
7
- data: SentryErrorData;
8
-
9
- /**
10
- * @param message Сообщение.
11
- * @param data Данные.
12
- */
13
- constructor(message: string, data: SentryErrorData = {}) {
14
- super(message);
15
- this.data = data;
16
- this.name = 'SentryError';
17
- }
18
- }
@@ -1,73 +0,0 @@
1
- import type { Request, Response } from 'express';
2
- import type { Middleware } from 'middleware-axios';
3
-
4
- export interface CookieStore {
5
- set: (seCookie: string[]) => void;
6
- asHeader: () => string;
7
- }
8
-
9
- /**
10
- * Возвращает новый middleware для работы с cookie на сервере.
11
- * @param request Входящий запрос.
12
- * @param response Исходящий ответ.
13
- * @return Middleware.
14
- */
15
- export function collectCookieMiddleware(request: Request, response: Response): Middleware<any> {
16
- const store = createCookieStore(request.get('cookie'));
17
-
18
- return async function (config, next) {
19
- const result = await next({
20
- ...config,
21
- headers: {
22
- ...config.headers,
23
- Cookie: store.asHeader(),
24
- },
25
- });
26
-
27
- if (result.headers['set-cookie']) {
28
- store.set(result.headers['set-cookie']);
29
- response.setHeader('cookie', store.asHeader());
30
- }
31
- };
32
- }
33
-
34
- /**
35
- * Возвращает новое хранилище cookie.
36
- * @param initialCookie Начальное значение cookie.
37
- * @return Хранилище cookie.
38
- */
39
- export function createCookieStore(initialCookie?: string): CookieStore {
40
- const data: Record<string, { name: string; value: string }> = {};
41
-
42
- // eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
43
- function setItem(cookieItem: string) {
44
- const [cookieName, cookieValue] = cookieItem.split('=').map(item => item.trim());
45
-
46
- if (cookieName && cookieValue) {
47
- data[cookieName] = { name: cookieName, value: cookieValue };
48
- }
49
- }
50
-
51
- if (initialCookie && initialCookie.length) {
52
- for (const item of initialCookie.split(';')) {
53
- setItem(item);
54
- }
55
- }
56
-
57
- // eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
58
- function set(setCookieHeaderValues: string[]): void {
59
- for (const item of setCookieHeaderValues) {
60
- const [cookie] = item.split(';');
61
- setItem(cookie);
62
- }
63
- }
64
-
65
- // eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
66
- function asHeader(): string {
67
- return Object.values(data)
68
- .map(cookie => `${cookie.name}=${cookie.value}`)
69
- .join(';');
70
- }
71
-
72
- return { set, asHeader };
73
- }
@@ -1,79 +0,0 @@
1
- import type { AxiosDefaults, AxiosRequestConfig } from 'axios';
2
- import type { Middleware } from 'middleware-axios';
3
- import { Context, Tracer, SpanStatusCode } from '@opentelemetry/api';
4
- import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
5
-
6
- /**
7
- * Возвращает новый middleware для трассировки исходящих запросов.
8
- * @param tracer Трейсер.
9
- * @param rootContext Контекст.
10
- * @return Middleware.
11
- */
12
- export function tracingMiddleware(tracer: Tracer, rootContext: Context): Middleware<any> {
13
- return async function (config, next, defaults) {
14
- const { method, url, foundId } = getRequestInfo(config, defaults);
15
- const span = tracer.startSpan(`HTTP ${method} ${url}`, undefined, rootContext);
16
-
17
- span.setAttributes({
18
- [SemanticAttributes.HTTP_URL]: url,
19
- [SemanticAttributes.HTTP_METHOD]: method,
20
-
21
- // если нашли id - добавляем в теги
22
- ...(foundId && { 'request.id': foundId }),
23
- });
24
-
25
- try {
26
- await next(config);
27
- } catch (error) {
28
- span.setStatus({
29
- code: SpanStatusCode.ERROR,
30
- message: 'HTTP Request failed',
31
- });
32
-
33
- // не прячем ошибку
34
- throw error;
35
- }
36
-
37
- span.end();
38
- };
39
- }
40
-
41
- /**
42
- * Формирует базовые данные запроса.
43
- * Заменяет первое найденное число в url на "{id}", возвращая его в результате.
44
- * @param config Axios-конфиг запроса.
45
- * @param defaults Базовый конфиг экземпляра Axios.
46
- * @return Базовые данные запроса.
47
- */
48
- export const getRequestInfo = (
49
- config: AxiosRequestConfig,
50
- defaults: AxiosDefaults,
51
- ): {
52
- method: string;
53
- url: string;
54
- foundId?: number;
55
- } => {
56
- const method = (config.method || 'GET').toUpperCase();
57
- const baseURL = config.baseURL || defaults.baseURL || '';
58
-
59
- // ВАЖНО: абстрагируем id только в url игнорируя baseURL
60
- const [url, foundId] = hideFirstId(config.url || defaults.url || '');
61
- const readyUrl = `${baseURL}${url}`;
62
-
63
- return { method, url: readyUrl, foundId };
64
- };
65
-
66
- /**
67
- * Преобразует строку вида:
68
- * "/api/v2/something/123456/some-bff/123456"
69
- * в строку вида:
70
- * "/api/v2/something/{id}/some-bff/123456"
71
- * и возвращает кортеж с этой строкой и вырезанным числом в случае если оно найдено.
72
- * @param url Url.
73
- * @return Кортеж со строкой и результатом поиска числа.
74
- */
75
- export const hideFirstId = (url: string): [string, number | undefined] => {
76
- const found = /\d{2,}/.exec(url);
77
-
78
- return found ? [url.replace(found[0], '{id}'), Number(found[0])] : [url, undefined];
79
- };
@@ -1,8 +0,0 @@
1
- import type { AxiosRequestConfig } from 'axios';
2
- import type { AxiosInstanceWrapper } from 'middleware-axios';
3
-
4
- export type HttpClient = AxiosInstanceWrapper;
5
-
6
- export interface HttpClientFactory {
7
- (config: AxiosRequestConfig): HttpClient;
8
- }
@@ -1,76 +0,0 @@
1
- import { getServiceHeaders, getXClientIp } from '../http-server/utils';
2
- import type { Request } from 'express';
3
- import type { BaseConfig } from '../config/types';
4
- import type { AxiosInstance } from 'axios';
5
- import type { AxiosInstanceWrapper, MethodName } from 'middleware-axios';
6
-
7
- // @todo передавать заголовки
8
- export type SauceResponse<T = any> =
9
- | {
10
- ok: true;
11
- data: T;
12
- }
13
- | {
14
- ok: false;
15
- error: any;
16
- };
17
-
18
- export interface SauceMethod<K extends MethodName> {
19
- <T>(...args: Parameters<AxiosInstanceWrapper[K]>): Promise<SauceResponse<T>>;
20
- }
21
-
22
- export interface Sauce {
23
- readonly get: SauceMethod<'get'>;
24
- readonly delete: SauceMethod<'delete'>;
25
- readonly head: SauceMethod<'head'>;
26
- readonly options: SauceMethod<'options'>;
27
- readonly post: SauceMethod<'post'>;
28
- readonly put: SauceMethod<'put'>;
29
- readonly patch: SauceMethod<'patch'>;
30
- }
31
-
32
- /**
33
- * Оборачивает экземпляр axios. Все методы обертки возвращают promise, который никогда не попадают в состояние rejected.
34
- * @param instance Экземпляр axios или AxiosInstanceWrapper.
35
- * @return Обертка.
36
- */
37
- export function sauce(instance: AxiosInstance | AxiosInstanceWrapper): Sauce {
38
- // eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
39
- function createMethod<Key extends MethodName>(methodName: Key) {
40
- return async function <Data = any>(
41
- ...args: Parameters<AxiosInstance[Key]>
42
- ): Promise<SauceResponse<Data>> {
43
- try {
44
- const response = await instance[methodName](...(args as [any]));
45
- return { ok: true, data: response.data };
46
- } catch (error) {
47
- return { ok: false, error };
48
- }
49
- };
50
- }
51
-
52
- return {
53
- get: createMethod('get'),
54
- delete: createMethod('delete'),
55
- head: createMethod('head'),
56
- options: createMethod('options'),
57
- post: createMethod('post'),
58
- put: createMethod('put'),
59
- patch: createMethod('patch'),
60
- };
61
- }
62
-
63
- /**
64
- * Формирует заголовки для исходящих запросов с сервера по соглашению.
65
- * @param config Конфиг.
66
- * @param request Входящий запрос.
67
- * @return Заголовки для исходящих запросов.
68
- */
69
- export function getRequestHeaders(config: BaseConfig, request: Request): Record<string, string> {
70
- return {
71
- 'X-Client-Ip': getXClientIp(request),
72
- 'User-Agent': `simaland-${config.appName}/${config.appVersion}`,
73
- Cookie: request.get('cookie') || '',
74
- ...getServiceHeaders(request),
75
- };
76
- }
@@ -1,4 +0,0 @@
1
- export const RESPONSE_EVENT = {
2
- renderStart: Symbol('render:start'),
3
- renderFinish: Symbol('render:finish'),
4
- } as const;
@@ -1,13 +0,0 @@
1
- import type { Handler } from 'express';
2
-
3
- /**
4
- * Обработчик, отвечающий данными о времени работы приложения.
5
- * @return Обработчик http-запроса.
6
- */
7
- export function healthCheck(): Handler {
8
- const startTime = Date.now();
9
-
10
- return (req, res) => {
11
- res.json({ uptime: Date.now() - startTime });
12
- };
13
- }
@@ -1,34 +0,0 @@
1
- import type { Handler } from 'express';
2
- import type { BaseConfig } from '../../config/types';
3
- import type { Logger, ConventionalFluentInfo } from '../../logger/types';
4
- import { getXClientIp } from '../utils';
5
- import { toMilliseconds } from '../../utils/number';
6
-
7
- /**
8
- * Возвращает новый middleware для логирования запросов.
9
- * @param config Конфиг.
10
- * @param logger Logger.
11
- * @return Middleware.
12
- */
13
- export function loggingMiddleware(config: BaseConfig, logger: Logger): Handler {
14
- return function (req, res, next) {
15
- const start = process.hrtime.bigint();
16
-
17
- res.once('finish', () => {
18
- const finish = process.hrtime.bigint();
19
-
20
- const message: ConventionalFluentInfo = {
21
- version: config.appVersion,
22
- route: req.originalUrl,
23
- method: req.method,
24
- status: res.statusCode,
25
- remote_ip: getXClientIp(req),
26
- latency: toMilliseconds(finish - start),
27
- };
28
-
29
- logger.info(message);
30
- });
31
-
32
- next();
33
- };
34
- }
@@ -1,87 +0,0 @@
1
- import type { Request, Response, Handler } from 'express';
2
- import type { BaseConfig } from '../../config/types';
3
- import * as PromClient from 'prom-client';
4
- import { toMilliseconds } from '../../utils/number';
5
- import { RESPONSE_EVENT } from '../constants';
6
- import { ConventionalLabels } from '../../metrics/constants';
7
-
8
- /**
9
- * Возвращает новый middleware для формирования метрик входящего запроса.
10
- * @param config Конфиг.
11
- * @param metrics Метрики - счетчик запросов и гистограмма длительности ответа.
12
- * @return Middleware.
13
- */
14
- export function responseMetricsMiddleware(
15
- config: BaseConfig,
16
- metrics: {
17
- counter: PromClient.Counter<typeof ConventionalLabels.HTTP_RESPONSE[number]>;
18
- histogram: PromClient.Histogram<typeof ConventionalLabels.HTTP_RESPONSE[number]>;
19
- },
20
- ): Handler {
21
- // eslint-disable-next-line require-jsdoc, jsdoc/require-jsdoc
22
- function resolveLabels(
23
- req: Request,
24
- res: Response,
25
- ): Record<typeof ConventionalLabels.HTTP_RESPONSE[number], string | number> {
26
- return {
27
- version: config.appVersion,
28
- route: req.baseUrl + req.path,
29
- code: res.statusCode,
30
- method: req.method,
31
- };
32
- }
33
-
34
- return (req, res, next) => {
35
- const start = process.hrtime.bigint();
36
-
37
- metrics.counter.inc(resolveLabels(req, res), 1);
38
-
39
- res.once('finish', () => {
40
- const finish = process.hrtime.bigint();
41
-
42
- metrics.histogram.observe(resolveLabels(req, res), toMilliseconds(finish - start));
43
- });
44
-
45
- next();
46
- };
47
- }
48
-
49
- /**
50
- * Возвращает новый middleware для формирования метрик рендеринга верстки.
51
- * @param config Конфиг.
52
- * @param metrics Метрики - гистограмма длительности рендеринга.
53
- * @return Middleware.
54
- */
55
- export function renderMetricsMiddleware(
56
- config: BaseConfig,
57
- metrics: {
58
- histogram: PromClient.Histogram<typeof ConventionalLabels.SSR[number]>;
59
- },
60
- ): Handler {
61
- return (req, res, next) => {
62
- let start: bigint | undefined;
63
-
64
- res.once(RESPONSE_EVENT.renderStart, () => {
65
- start = process.hrtime.bigint();
66
- });
67
-
68
- res.once(RESPONSE_EVENT.renderFinish, () => {
69
- if (typeof start !== 'bigint') {
70
- throw Error('Looks like "render start" event not emitted');
71
- }
72
-
73
- const finish = process.hrtime.bigint();
74
-
75
- metrics.histogram.observe(
76
- {
77
- version: config.appVersion,
78
- method: req.method,
79
- route: req.baseUrl + req.path,
80
- },
81
- toMilliseconds(finish - start),
82
- );
83
- });
84
-
85
- next();
86
- };
87
- }
@@ -1,35 +0,0 @@
1
- import { RESPONSE_EVENT } from '../constants';
2
- import { propagation, ROOT_CONTEXT } from '@opentelemetry/api';
3
- import type { Tracer } from '../../tracer/types';
4
- import type { Handler } from 'express';
5
-
6
- /**
7
- * Возвращает новый middleware для трассировки стадий входящего запроса.
8
- * @param tracer Tracer.
9
- * @return Middleware.
10
- */
11
- export function tracingMiddleware(tracer: Tracer): Handler {
12
- return (req, res, next) => {
13
- const rootContext = propagation.extract(ROOT_CONTEXT, req.headers);
14
- const rootSpan = tracer.startSpan('response', undefined, rootContext);
15
-
16
- res.locals.tracing = {
17
- rootSpan,
18
- rootContext,
19
- };
20
-
21
- res.once(RESPONSE_EVENT.renderStart, () => {
22
- res.locals.tracing.renderSpan = tracer.startSpan('render', undefined, rootContext);
23
- });
24
-
25
- res.once(RESPONSE_EVENT.renderFinish, () => {
26
- res.locals.tracing.renderSpan.end();
27
- });
28
-
29
- res.once('finish', () => {
30
- rootSpan.end();
31
- });
32
-
33
- next();
34
- };
35
- }
@@ -1,29 +0,0 @@
1
- import type { Request, Response, NextFunction, Handler, ErrorRequestHandler } from 'express';
2
-
3
- export interface ResponseContext {
4
- req: Request;
5
- res: Response;
6
- next: NextFunction;
7
- }
8
-
9
- export interface PageAssets {
10
- js: string;
11
- css: string;
12
- }
13
-
14
- export interface ConventionalJson {
15
- markup: string;
16
- bundle_js: string;
17
- bundle_css: string;
18
- critical_js?: string;
19
- critical_css?: string;
20
- meta?: any;
21
- }
22
-
23
- export interface DefaultMiddleware {
24
- start: Handler[];
25
- logging: Handler[];
26
- tracing: Handler[];
27
- metrics: Handler[];
28
- finish: Array<Handler | ErrorRequestHandler>;
29
- }
@@ -1,105 +0,0 @@
1
- import type { Request, Response } from 'express';
2
- import type { ConventionalJson, PageAssets } from './types';
3
- import { isIP } from 'net';
4
-
5
- /**
6
- * Определяет IP входящего запроса.
7
- * @param req Входящий запрос.
8
- * @return IP.
9
- */
10
- export function getXClientIp(req: Request): string {
11
- const headerValue =
12
- req.get('x-client-ip') || req.get('x-forwarded-for') || req.socket.remoteAddress || '';
13
-
14
- return isIP(headerValue) ? headerValue : '';
15
- }
16
-
17
- /**
18
- * Определяет служебные заголовки по соглашению.
19
- * @param req Входящий запрос.
20
- * @return Служебные заголовки.
21
- */
22
- export function getServiceHeaders(req: Request): Record<string, string | undefined> {
23
- const result: Record<string, string | undefined> = {};
24
-
25
- for (const [key] of Object.entries(req.headers)) {
26
- if (key.toLowerCase().indexOf('simaland-') === 0) {
27
- result[key] = req.header(key);
28
- }
29
- }
30
-
31
- return result;
32
- }
33
-
34
- /* eslint-disable require-jsdoc, jsdoc/require-jsdoc */
35
- export class PageResponse {
36
- private type: 'html' | 'json';
37
- private html: string;
38
- private assets: PageAssets;
39
-
40
- static create() {
41
- return new PageResponse();
42
- }
43
-
44
- static defineFormat(req: Request): PageResponse['type'] {
45
- let result: PageResponse['type'] = 'html';
46
-
47
- if ((req.header('accept') || '').toLowerCase().includes('application/json')) {
48
- result = 'json';
49
- }
50
-
51
- return result;
52
- }
53
-
54
- constructor() {
55
- this.type = 'html';
56
- this.html = '';
57
- this.assets = { js: '', css: '' };
58
- }
59
-
60
- markup(html: string) {
61
- this.html = html;
62
- return this;
63
- }
64
-
65
- script(url: string) {
66
- this.assets.js = url;
67
- return this;
68
- }
69
-
70
- style(url: string) {
71
- this.assets.css = url;
72
- return this;
73
- }
74
-
75
- format(type: PageResponse['type']) {
76
- this.type = type;
77
- return this;
78
- }
79
-
80
- send(res: Response) {
81
- switch (this.type) {
82
- case 'json': {
83
- const result: ConventionalJson = {
84
- markup: this.html,
85
- bundle_js: this.assets.js,
86
- bundle_css: this.assets.css,
87
- };
88
-
89
- res.json(result);
90
- break;
91
- }
92
- case 'html': {
93
- res.setHeader('simaland-bundle-js', this.assets.js);
94
- res.setHeader('simaland-bundle-css', this.assets.css);
95
-
96
- // @todo dev-шаблон?
97
- res.send(this.html);
98
- break;
99
- }
100
- default:
101
- throw Error(`Unknown response format ${String(this.type)}`);
102
- }
103
- }
104
- }
105
- /* eslint-enable require-jsdoc, jsdoc/require-jsdoc */
@@ -1,35 +0,0 @@
1
- import type { BaseConfig } from '../../config/types';
2
- import pino from 'pino';
3
- import pinoPretty from 'pino-pretty';
4
- import { LoggerEventHandler } from '../types';
5
-
6
- /**
7
- * Возвращает новый handler для logger'а для вывода событий в терминал.
8
- * @param config Конфиг.
9
- * @return Handler.
10
- */
11
- export function createConsoleHandler(config: BaseConfig): LoggerEventHandler {
12
- const isProd = config.env === 'production';
13
-
14
- const logger = pino(
15
- isProd
16
- ? {
17
- formatters: {
18
- // ВАЖНО: для Fluent необходимо наличие поля level: string
19
- level: label => ({ level: label }),
20
- },
21
- }
22
- : pinoPretty({ colorize: true }),
23
- );
24
-
25
- return function (event) {
26
- switch (event.type) {
27
- case 'info':
28
- logger.info(event.data);
29
- break;
30
- case 'error':
31
- logger.error(event.data);
32
- break;
33
- }
34
- };
35
- }
@@ -1,38 +0,0 @@
1
- import type { SentryLib } from '../../error-tracker/types';
2
- import type { LoggerEventHandler } from '../types';
3
- import { SentryError } from '../../error-tracker/utils';
4
-
5
- /**
6
- * Возвращает новый handler для logger'а для отправки событий в Sentry.
7
- * @param sentry Набор данных для работы с Sentry.
8
- * @return Handler.
9
- */
10
- export function createSentryHandler(sentry: SentryLib): LoggerEventHandler {
11
- return event => {
12
- if (event.type === 'error') {
13
- const error = event.data;
14
-
15
- if (error instanceof SentryError) {
16
- const { level, context, extra } = error.data;
17
-
18
- sentry.withScope(scope => {
19
- if (level) {
20
- scope.setLevel(level);
21
- }
22
-
23
- if (context) {
24
- scope.setContext(context.key, context.data);
25
- }
26
-
27
- if (extra) {
28
- scope.setExtra(extra.key, extra.data);
29
- }
30
-
31
- sentry.client.captureException(error);
32
- });
33
- } else {
34
- sentry.client.captureException(error);
35
- }
36
- }
37
- };
38
- }