@application-kit/observability 0.1.0 → 0.3.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 (155) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +98 -17
  3. package/dist/cjs/cqrs/cqrs-logger.d.ts +12 -0
  4. package/dist/cjs/cqrs/cqrs-logger.js +72 -0
  5. package/dist/cjs/cqrs/cqrs-logger.module.d.ts +2 -0
  6. package/dist/cjs/cqrs/cqrs-logger.module.js +22 -0
  7. package/dist/cjs/cqrs/index.d.ts +2 -0
  8. package/dist/cjs/cqrs/index.js +18 -0
  9. package/dist/cjs/health/cli/health-cli-options.interface.d.ts +3 -0
  10. package/dist/cjs/health/cli/health-cli-options.interface.js +2 -0
  11. package/dist/cjs/health/cli/health-cli.d.ts +13 -0
  12. package/dist/cjs/health/cli/health-cli.js +56 -0
  13. package/dist/cjs/health/cli/health-cli.module.d.ts +5 -0
  14. package/dist/cjs/health/cli/health-cli.module.js +23 -0
  15. package/dist/cjs/health/cli/index.d.ts +3 -0
  16. package/dist/cjs/health/cli/index.js +19 -0
  17. package/dist/cjs/health/graphql/health-check.type.d.ts +3 -0
  18. package/dist/cjs/health/graphql/health-check.type.js +24 -0
  19. package/dist/cjs/health/graphql/health-graphql.module.d.ts +5 -0
  20. package/dist/cjs/health/graphql/health-graphql.module.js +26 -0
  21. package/dist/cjs/health/graphql/health.resolver.d.ts +11 -0
  22. package/dist/cjs/health/graphql/health.resolver.js +55 -0
  23. package/dist/cjs/health/graphql/index.d.ts +3 -0
  24. package/dist/cjs/health/graphql/index.js +19 -0
  25. package/dist/cjs/health/health-checks.d.ts +10 -0
  26. package/dist/cjs/health/health-checks.js +53 -0
  27. package/dist/cjs/health/health-http.module.d.ts +5 -0
  28. package/dist/cjs/health/health-http.module.js +26 -0
  29. package/dist/cjs/health/health-module-options.interface.d.ts +9 -0
  30. package/dist/cjs/health/health-module-options.interface.js +2 -0
  31. package/dist/cjs/health/health.config.d.ts +8 -0
  32. package/dist/cjs/health/health.config.js +39 -0
  33. package/dist/cjs/health/health.controller.d.ts +14 -0
  34. package/dist/cjs/health/health.controller.js +78 -0
  35. package/dist/cjs/health/health.environment.d.ts +5 -0
  36. package/dist/cjs/health/health.environment.js +38 -0
  37. package/dist/cjs/health/health.module.d.ts +5 -0
  38. package/dist/cjs/health/health.module.js +28 -0
  39. package/dist/cjs/health/index.d.ts +8 -0
  40. package/dist/cjs/health/index.js +24 -0
  41. package/dist/cjs/health/migrations.health-indicator.d.ts +9 -0
  42. package/dist/cjs/health/migrations.health-indicator.js +40 -0
  43. package/dist/cjs/http/client-ip-options.interface.d.ts +3 -0
  44. package/dist/cjs/http/client-ip-options.interface.js +2 -0
  45. package/dist/cjs/http/index.d.ts +2 -0
  46. package/dist/cjs/http/index.js +18 -0
  47. package/dist/cjs/http/resolve-client-ip.d.ts +14 -0
  48. package/dist/cjs/http/resolve-client-ip.js +22 -0
  49. package/dist/cjs/logging/constants.d.ts +1 -0
  50. package/dist/cjs/logging/constants.js +4 -0
  51. package/dist/cjs/logging/index.d.ts +8 -0
  52. package/dist/cjs/logging/index.js +24 -0
  53. package/dist/cjs/logging/infrastructure-paths.d.ts +4 -0
  54. package/dist/cjs/logging/infrastructure-paths.js +9 -0
  55. package/dist/cjs/logging/logger.environment.d.ts +4 -0
  56. package/dist/cjs/logging/logger.environment.js +24 -0
  57. package/dist/cjs/logging/observability-logger.interface.d.ts +4 -0
  58. package/dist/cjs/logging/observability-logger.interface.js +2 -0
  59. package/dist/cjs/logging/pino-logger-options.interface.d.ts +5 -0
  60. package/dist/cjs/logging/pino-logger-options.interface.js +2 -0
  61. package/dist/cjs/logging/pino-logger.config.d.ts +15 -0
  62. package/dist/cjs/logging/pino-logger.config.js +104 -0
  63. package/dist/cjs/logging/resolve-request-id.d.ts +4 -0
  64. package/dist/cjs/logging/resolve-request-id.js +10 -0
  65. package/dist/cjs/logging/resolve-support-id.d.ts +3 -0
  66. package/dist/cjs/logging/resolve-support-id.js +8 -0
  67. package/dist/cjs/metrics/index.d.ts +3 -0
  68. package/dist/cjs/metrics/index.js +3 -0
  69. package/dist/cjs/metrics/metrics-hooks.d.ts +2 -0
  70. package/dist/cjs/metrics/metrics-hooks.js +37 -0
  71. package/dist/cjs/metrics/metrics-http.module.d.ts +5 -0
  72. package/dist/cjs/metrics/metrics-http.module.js +29 -0
  73. package/dist/cjs/metrics/metrics.controller.d.ts +7 -0
  74. package/dist/cjs/metrics/metrics.controller.js +42 -0
  75. package/dist/cjs/shared/active-span-context.d.ts +2 -0
  76. package/dist/cjs/shared/active-span-context.js +9 -0
  77. package/dist/cjs/shared/with-class-decorator.d.ts +2 -0
  78. package/dist/cjs/shared/with-class-decorator.js +14 -0
  79. package/dist/esm/cqrs/cqrs-logger.d.ts +12 -0
  80. package/dist/esm/cqrs/cqrs-logger.js +69 -0
  81. package/dist/esm/cqrs/cqrs-logger.module.d.ts +2 -0
  82. package/dist/esm/cqrs/cqrs-logger.module.js +19 -0
  83. package/dist/esm/cqrs/index.d.ts +2 -0
  84. package/dist/esm/cqrs/index.js +2 -0
  85. package/dist/esm/health/cli/health-cli-options.interface.d.ts +3 -0
  86. package/dist/esm/health/cli/health-cli-options.interface.js +1 -0
  87. package/dist/esm/health/cli/health-cli.d.ts +13 -0
  88. package/dist/esm/health/cli/health-cli.js +52 -0
  89. package/dist/esm/health/cli/health-cli.module.d.ts +5 -0
  90. package/dist/esm/health/cli/health-cli.module.js +20 -0
  91. package/dist/esm/health/cli/index.d.ts +3 -0
  92. package/dist/esm/health/cli/index.js +3 -0
  93. package/dist/esm/health/graphql/health-check.type.d.ts +3 -0
  94. package/dist/esm/health/graphql/health-check.type.js +21 -0
  95. package/dist/esm/health/graphql/health-graphql.module.d.ts +5 -0
  96. package/dist/esm/health/graphql/health-graphql.module.js +23 -0
  97. package/dist/esm/health/graphql/health.resolver.d.ts +11 -0
  98. package/dist/esm/health/graphql/health.resolver.js +52 -0
  99. package/dist/esm/health/graphql/index.d.ts +3 -0
  100. package/dist/esm/health/graphql/index.js +3 -0
  101. package/dist/esm/health/health-checks.d.ts +10 -0
  102. package/dist/esm/health/health-checks.js +50 -0
  103. package/dist/esm/health/health-http.module.d.ts +5 -0
  104. package/dist/esm/health/health-http.module.js +23 -0
  105. package/dist/esm/health/health-module-options.interface.d.ts +9 -0
  106. package/dist/esm/health/health-module-options.interface.js +1 -0
  107. package/dist/esm/health/health.config.d.ts +8 -0
  108. package/dist/esm/health/health.config.js +36 -0
  109. package/dist/esm/health/health.controller.d.ts +14 -0
  110. package/dist/esm/health/health.controller.js +75 -0
  111. package/dist/esm/health/health.environment.d.ts +5 -0
  112. package/dist/esm/health/health.environment.js +34 -0
  113. package/dist/esm/health/health.module.d.ts +5 -0
  114. package/dist/esm/health/health.module.js +25 -0
  115. package/dist/esm/health/index.d.ts +8 -0
  116. package/dist/esm/health/index.js +8 -0
  117. package/dist/esm/health/migrations.health-indicator.d.ts +9 -0
  118. package/dist/esm/health/migrations.health-indicator.js +37 -0
  119. package/dist/esm/http/client-ip-options.interface.d.ts +3 -0
  120. package/dist/esm/http/client-ip-options.interface.js +1 -0
  121. package/dist/esm/http/index.d.ts +2 -0
  122. package/dist/esm/http/index.js +2 -0
  123. package/dist/esm/http/resolve-client-ip.d.ts +14 -0
  124. package/dist/esm/http/resolve-client-ip.js +18 -0
  125. package/dist/esm/logging/constants.d.ts +1 -0
  126. package/dist/esm/logging/constants.js +1 -0
  127. package/dist/esm/logging/index.d.ts +8 -0
  128. package/dist/esm/logging/index.js +8 -0
  129. package/dist/esm/logging/infrastructure-paths.d.ts +4 -0
  130. package/dist/esm/logging/infrastructure-paths.js +5 -0
  131. package/dist/esm/logging/logger.environment.d.ts +4 -0
  132. package/dist/esm/logging/logger.environment.js +20 -0
  133. package/dist/esm/logging/observability-logger.interface.d.ts +4 -0
  134. package/dist/esm/logging/observability-logger.interface.js +1 -0
  135. package/dist/esm/logging/pino-logger-options.interface.d.ts +5 -0
  136. package/dist/esm/logging/pino-logger-options.interface.js +1 -0
  137. package/dist/esm/logging/pino-logger.config.d.ts +15 -0
  138. package/dist/esm/logging/pino-logger.config.js +99 -0
  139. package/dist/esm/logging/resolve-request-id.d.ts +4 -0
  140. package/dist/esm/logging/resolve-request-id.js +6 -0
  141. package/dist/esm/logging/resolve-support-id.d.ts +3 -0
  142. package/dist/esm/logging/resolve-support-id.js +4 -0
  143. package/dist/esm/metrics/index.d.ts +3 -0
  144. package/dist/esm/metrics/index.js +3 -0
  145. package/dist/esm/metrics/metrics-hooks.d.ts +2 -0
  146. package/dist/esm/metrics/metrics-hooks.js +33 -0
  147. package/dist/esm/metrics/metrics-http.module.d.ts +5 -0
  148. package/dist/esm/metrics/metrics-http.module.js +26 -0
  149. package/dist/esm/metrics/metrics.controller.d.ts +7 -0
  150. package/dist/esm/metrics/metrics.controller.js +39 -0
  151. package/dist/esm/shared/active-span-context.d.ts +2 -0
  152. package/dist/esm/shared/active-span-context.js +5 -0
  153. package/dist/esm/shared/with-class-decorator.d.ts +2 -0
  154. package/dist/esm/shared/with-class-decorator.js +10 -0
  155. package/package.json +140 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @application-kit/observability
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5311ebc: Входы `/logging`, `/health` (+ `/health/graphql`, `/health/cli`) и веб-часть `/metrics`.
8
+
9
+ - `/logging`: `PinoLoggerConfig` и `LoggerEnvironment` — опции nestjs-pino (уровень по исходу ответа, severity,
10
+ trace-миксин, redact, IP клиента через `resolveClientIp`), `resolveRequestId`/`REQUEST_ID_HEADER`, `resolveSupportId`,
11
+ `INFRASTRUCTURE_PATHS`/`isInfrastructurePath`.
12
+ - `/health`: `HealthModule.forRoot` (terminus + состав чека), `HealthHttpModule.forRoot` (`/health`, `/health/live`,
13
+ `/health/ready`), `HealthConfig`/`HealthEnvironment`, `MigrationsHealthIndicator`; носители GraphQL и CLI — подвходами.
14
+ - `/metrics`: `MetricsHttpModule.forRoot` с `GET /metrics` и `setupMetricsHooks(app)` — хуки Fastify и mercurius.
15
+
16
+ **Ломающее:** токен `OBSERVABILITY_LOGGER` и `ObservabilityLoggerInterface` переехали из `/cqrs` во вход `/logging` —
17
+ импорт потребителя меняется на `@application-kit/observability/logging`.
18
+
19
+ ## 0.2.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 06c0229: Вход `/cqrs`: `CqrsLoggerModule` и `CqrsLogger` — старт, длительность и исход каждой команды и запроса на шинах
24
+ `@nestjs/cqrs` (имя, а не полезная нагрузка); логгер приходит токеном `OBSERVABILITY_LOGGER` по контракту
25
+ `ObservabilityLoggerInterface`, `@nestjs/cqrs` — optional peer. Вход `/http`: `resolveClientIp(request, { trustedHeaders })` —
26
+ реальный IP клиента за прокси: доверенные заголовки по порядку, затем `request.ip` и адрес сокета; по умолчанию заголовкам
27
+ не доверяет.
28
+
3
29
  ## 0.1.0
4
30
 
5
31
  ### Minor Changes
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # @application-kit/observability
2
2
 
3
- Наблюдаемость NestJS-процесса. Первый вход — `/metrics`: реестр Prometheus с метриками процесса Node, RED-гистограммы
4
- HTTP и GraphQL и HTTP-сервер экспозиции для процессов без своего веб-слоя. Пакет не знает ни маршрутов, ни схемы,
5
- ни портов приложения: ярлыки и порт приходят параметрами, а хуки веб-сервера и контроллер скрейпа остаются у потребителя.
3
+ Наблюдаемость NestJS-процесса: метрики Prometheus и контроллер скрейпа (`/metrics`), health-чек и пробы оркестратора
4
+ (`/health`), опции pino с request-id и trace-контекстом (`/logging`), логирование команд и запросов CQRS-шин (`/cqrs`)
5
+ и реальный IP клиента за прокси (`/http`). Пакет не знает ни продукта, ни guard'ов, ни прокси приложения: имя
6
+ CLI-команды, декоратор публичного маршрута и доверенные заголовки приходят параметрами.
6
7
 
7
8
  ## Установка
8
9
 
@@ -10,14 +11,19 @@ HTTP и GraphQL и HTTP-сервер экспозиции для процесс
10
11
  yarn add @application-kit/observability
11
12
  ```
12
13
 
13
- Peer-зависимости: `@nestjs/common`, `@prometheus-io/client`; `graphql` — optional, нужен только GraphQL-гистограмме
14
- (из него берутся типы документа, сам вход грузится и без него).
14
+ Peer-зависимости: `@nestjs/common`, `@prometheus-io/client`; остальные optional и нужны только своему входу — см. таблицу.
15
15
 
16
16
  ## Входы
17
17
 
18
18
  | Вход | Для чего | Тянет |
19
19
  |------|----------|-------|
20
- | `@application-kit/observability/metrics` | реестр, гистограммы HTTP и GraphQL, сервер `/metrics` | `@nestjs/common`, `@prometheus-io/client` |
20
+ | `@application-kit/observability/cqrs` | логирование команд и запросов обеих шин | `@nestjs/common`, `@nestjs/cqrs` |
21
+ | `@application-kit/observability/health` | состав чека, пробы `/health/live` и `/health/ready`, `GET /health` | `@nestjs/terminus`, `@nestjs/typeorm`, `typeorm`, `@application-kit/typeorm`, `class-validator`, `class-transformer` |
22
+ | `@application-kit/observability/health/graphql` | `query { health { status } }` | `/health` + `@nestjs/graphql` |
23
+ | `@application-kit/observability/health/cli` | CLI-команда `<группа> health` | `/health` + `nestjs-console` |
24
+ | `@application-kit/observability/http` | `resolveClientIp` — IP клиента за прокси | ничего |
25
+ | `@application-kit/observability/logging` | опции nestjs-pino, request-id, support-id, служебные пути, токен логгера | `@opentelemetry/api`, `class-validator`, `class-transformer`; типы — `nestjs-pino`, `pino` |
26
+ | `@application-kit/observability/metrics` | реестр, гистограммы HTTP и GraphQL, `GET /metrics`, хуки Fastify, сервер `/metrics` | `@nestjs/common`, `@prometheus-io/client`; типы — `fastify`, `@nestjs/platform-fastify` |
21
27
 
22
28
  Корневого входа нет: каждый вход несёт свои peer-зависимости, и лишнего потребитель не ставит.
23
29
 
@@ -33,18 +39,16 @@ Peer-зависимости: `@nestjs/common`, `@prometheus-io/client`; `graphql
33
39
  `asMercuriusHook` оборачивает синхронный обработчик в async-хук Mercurius.
34
40
  - `DURATION_BUCKETS_SECONDS` — общие границы гистограмм, от 5 мс до 10 с.
35
41
 
42
+ Web-процесс подключает `MetricsHttpModule.forRoot({ publicRoute })` — реестр, обе гистограммы и `GET /metrics`
43
+ (путь — `METRICS_ROUTE` входа `/logging`), — и вешает хуки после создания приложения: HTTP — `onResponse` Fastify
44
+ (видит и 404, и ошибки парсинга, которых не видит интерцептор Nest), GraphQL — хуки mercurius в `onReady`.
45
+
36
46
  ```ts
37
- app.register(async (instance) => {
38
- instance.addHook('onResponse', (request, reply, done) => {
39
- httpMetrics.observe({
40
- durationSeconds: reply.elapsedTime / 1000,
41
- method: request.method,
42
- route: resolveRouteLabel(request.routeOptions.url),
43
- status: reply.statusCode,
44
- })
45
- done()
46
- })
47
- })
47
+ @Module({ imports: [MetricsHttpModule.forRoot({ publicRoute: Public() })] })
48
+ export class WebModule {}
49
+
50
+ const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter())
51
+ setupMetricsHooks(app)
48
52
  ```
49
53
 
50
54
  ## Сервер `/metrics` без веб-слоя
@@ -56,3 +60,80 @@ app.register(async (instance) => {
56
60
  ```ts
57
61
  const server = startMetricsServer({ onError: (error) => logger.error(error), port: 9464, registry })
58
62
  ```
63
+
64
+ ## Логирование CQRS-шин
65
+
66
+ `CqrsLoggerModule` подключается корневым модулем процесса один раз. На каждую команду и запрос — запись о старте
67
+ (подпиской на шину: видит все отправки) и о завершении с `durationMs` и `outcome` (обёрткой `execute` экземпляра шины:
68
+ длительность и исход шина не публикует). В лог идёт ИМЯ класса, не полезная нагрузка; ошибка хендлера пишется на `error`
69
+ и пробрасывается дальше.
70
+
71
+ Логгер приложение приносит глобально токеном `OBSERVABILITY_LOGGER` (вход `/logging`; им же пишут носители health-чека)
72
+ — подходит любой логгер с `info(payload, message)`
73
+ и `error(payload, message)`, например `PinoLogger` из `nestjs-pino`:
74
+
75
+ ```ts
76
+ @Global()
77
+ @Module({
78
+ exports: [OBSERVABILITY_LOGGER],
79
+ providers: [AppLogger, { provide: OBSERVABILITY_LOGGER, useExisting: AppLogger }],
80
+ })
81
+ export class CommonModule {}
82
+
83
+ @Module({ imports: [CommonModule, CqrsLoggerModule] })
84
+ export class AppModule {}
85
+ ```
86
+
87
+ ## Логирование HTTP (`/logging`)
88
+
89
+ - `PinoLoggerConfig.createOptions({ resolveClientIp })` — опции `LoggerModule` из nestjs-pino: уровень из
90
+ `LoggerEnvironment.LOG_LEVEL` (дефолт `warn`), уровень строки ответа по исходу (`responseLogLevel`: 5xx и исключение —
91
+ `error`, 4xx — `warn`, успешный служебный запрос — `debug`), `severity` для бэкенда логов, `trace_id`/`span_id` в каждой
92
+ строке (`traceContextMixin`), redact паролей и заголовков `authorization`/`cookie`, адрес клиента в `req.remoteAddress`.
93
+ Без `resolveClientIp` заголовкам не верят — см. «IP клиента за прокси».
94
+ - `REQUEST_ID_HEADER` и `resolveRequestId` — `genReqId` Fastify: `x-request-id` от прокси либо свой UUID.
95
+ - `resolveSupportId(request)` — идентификатор для пользователя и поддержки: trace_id активного спана, вне трассы — `request.id`.
96
+ - `INFRASTRUCTURE_PATHS`, `isInfrastructurePath` — служебные маршруты (`/health`, `/metrics`) для тишины логов и трасс;
97
+ контроллеры входов `/health` и `/metrics` берут путь отсюда же.
98
+
99
+ `LoggerEnvironment` и `HealthEnvironment` регистрирует приложение своим загрузчиком конфигов, как `DatabaseEnvironment`
100
+ из `@application-kit/typeorm/nest`.
101
+
102
+ ## Health-чек (`/health`)
103
+
104
+ `HealthModule.forRoot({ imports, logger })` — глобальное ядро процесса: terminus и `HealthChecks` (ping БД, heap, RSS,
105
+ диск по корню; пороги — `HealthConfig`/`HealthEnvironment`). Носители подключаются там, где нужны, и берут состав
106
+ отсюда — вердикт не зависит от того, каким путём спросили:
107
+
108
+ - `HealthHttpModule.forRoot({ publicRoute })` — `GET /health` (полный чек), `/health/live` (пустая, без зависимостей) и
109
+ `/health/ready` (ping БД и применённые миграции). SQL проб идёт в области `runAsInfrastructureQuery` и логируется на `debug`.
110
+ - `HealthGraphqlModule.forRoot({ publicRoute })` (вход `/health/graphql`) — `query { health { status } }`; отказ —
111
+ `status: "error"` и запись в лог.
112
+ - `HealthCliModule.forRoot({ command })` (вход `/health/cli`) — `<command> health`, вердикт в лог.
113
+
114
+ `publicRoute` — декоратор класса потребителя (например `Public()` его guard'а); он ложится на подкласс носителя,
115
+ классы пакета не мутируются.
116
+
117
+ ```ts
118
+ @Module({
119
+ imports: [
120
+ HealthModule.forRoot({ imports: [healthConfigsModule], logger: Logger }),
121
+ HealthHttpModule.forRoot({ publicRoute: Public() }),
122
+ HealthGraphqlModule.forRoot({ publicRoute: Public() }),
123
+ ],
124
+ })
125
+ export class WebModule {}
126
+ ```
127
+
128
+ ## IP клиента за прокси
129
+
130
+ `resolveClientIp(request, { trustedHeaders })` принимает `IncomingMessage`, `FastifyRequest` или его обёртку из
131
+ сериалайзера pino. Порядок: доверенные заголовки по порядку списка (первый непустой), затем `request.ip` (у Fastify —
132
+ с учётом `trustProxy`), затем адрес сокета; источника нет — пустая строка.
133
+
134
+ По умолчанию заголовкам не доверяет: в список кладётся только заголовок, который прокси перед процессом ставит и
135
+ перезаписывает сам, — иначе клиент подставит в логи любой адрес.
136
+
137
+ ```ts
138
+ const clientIp = resolveClientIp(request, { trustedHeaders: ['cf-connecting-ip'] })
139
+ ```
@@ -0,0 +1,12 @@
1
+ import { OnApplicationBootstrap } from '@nestjs/common';
2
+ import { CommandBus, QueryBus } from '@nestjs/cqrs';
3
+ import type { ObservabilityLoggerInterface } from '../logging/observability-logger.interface.js';
4
+ export declare class CqrsLogger implements OnApplicationBootstrap {
5
+ private readonly commandBus;
6
+ private readonly queryBus;
7
+ private readonly logger;
8
+ private instrumented;
9
+ constructor(commandBus: CommandBus, queryBus: QueryBus, logger: ObservabilityLoggerInterface);
10
+ onApplicationBootstrap(): void;
11
+ private instrumentCompletion;
12
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.CqrsLogger = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const cqrs_1 = require("@nestjs/cqrs");
18
+ const node_perf_hooks_1 = require("node:perf_hooks");
19
+ const constants_js_1 = require("../logging/constants.js");
20
+ const KIND_COMMAND = 'command';
21
+ const KIND_QUERY = 'query';
22
+ let CqrsLogger = class CqrsLogger {
23
+ commandBus;
24
+ queryBus;
25
+ logger;
26
+ instrumented = false;
27
+ constructor(commandBus, queryBus, logger) {
28
+ this.commandBus = commandBus;
29
+ this.queryBus = queryBus;
30
+ this.logger = logger;
31
+ }
32
+ onApplicationBootstrap() {
33
+ if (this.instrumented) {
34
+ return;
35
+ }
36
+ this.instrumented = true;
37
+ this.commandBus.subscribe((command) => {
38
+ this.logger.info({ [KIND_COMMAND]: command.constructor.name }, 'command started');
39
+ });
40
+ this.queryBus.subscribe((query) => {
41
+ this.logger.info({ [KIND_QUERY]: query.constructor.name }, 'query started');
42
+ });
43
+ this.instrumentCompletion(this.commandBus, KIND_COMMAND);
44
+ this.instrumentCompletion(this.queryBus, KIND_QUERY);
45
+ }
46
+ instrumentCompletion(bus, kind) {
47
+ const target = bus;
48
+ const original = target.execute.bind(target);
49
+ target.execute = async (payload, context) => {
50
+ const startedAt = node_perf_hooks_1.performance.now();
51
+ const { name } = payload.constructor;
52
+ try {
53
+ const result = await original(payload, context);
54
+ this.logger.info({ durationMs: node_perf_hooks_1.performance.now() - startedAt, [kind]: name, outcome: 'ok' }, `${kind} finished`);
55
+ return result;
56
+ }
57
+ catch (error) {
58
+ this.logger.error({ durationMs: node_perf_hooks_1.performance.now() - startedAt, err: error, [kind]: name, outcome: 'error' }, `${kind} failed`);
59
+ throw error;
60
+ }
61
+ };
62
+ }
63
+ };
64
+ exports.CqrsLogger = CqrsLogger;
65
+ exports.CqrsLogger = CqrsLogger = __decorate([
66
+ (0, common_1.Injectable)(),
67
+ __param(0, (0, common_1.Inject)(cqrs_1.CommandBus)),
68
+ __param(1, (0, common_1.Inject)(cqrs_1.QueryBus)),
69
+ __param(2, (0, common_1.Inject)(constants_js_1.OBSERVABILITY_LOGGER)),
70
+ __metadata("design:paramtypes", [cqrs_1.CommandBus,
71
+ cqrs_1.QueryBus, Object])
72
+ ], CqrsLogger);
@@ -0,0 +1,2 @@
1
+ export declare class CqrsLoggerModule {
2
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.CqrsLoggerModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const cqrs_1 = require("@nestjs/cqrs");
12
+ const cqrs_logger_js_1 = require("./cqrs-logger.js");
13
+ let CqrsLoggerModule = class CqrsLoggerModule {
14
+ };
15
+ exports.CqrsLoggerModule = CqrsLoggerModule;
16
+ exports.CqrsLoggerModule = CqrsLoggerModule = __decorate([
17
+ (0, common_1.Module)({
18
+ exports: [cqrs_logger_js_1.CqrsLogger],
19
+ imports: [cqrs_1.CqrsModule],
20
+ providers: [cqrs_logger_js_1.CqrsLogger],
21
+ })
22
+ ], CqrsLoggerModule);
@@ -0,0 +1,2 @@
1
+ export * from './cqrs-logger.js';
2
+ export * from './cqrs-logger.module.js';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./cqrs-logger.js"), exports);
18
+ __exportStar(require("./cqrs-logger.module.js"), exports);
@@ -0,0 +1,3 @@
1
+ export interface HealthCliOptionsInterface {
2
+ readonly command: string;
3
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import type { Type } from '@nestjs/common';
2
+ import { HealthCheckService } from '@nestjs/terminus';
3
+ import type { ObservabilityLoggerInterface } from '../../logging/observability-logger.interface.js';
4
+ import type { HealthCliOptionsInterface } from './health-cli-options.interface.js';
5
+ import { HealthChecks } from '../health-checks.js';
6
+ export declare class HealthCliCommands {
7
+ private readonly health;
8
+ private readonly logger;
9
+ private readonly healthChecks;
10
+ constructor(health: HealthCheckService, logger: ObservabilityLoggerInterface, healthChecks: HealthChecks);
11
+ getHealth(): Promise<void>;
12
+ }
13
+ export declare const createHealthCli: (options: HealthCliOptionsInterface) => Type<HealthCliCommands>;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createHealthCli = exports.HealthCliCommands = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const terminus_1 = require("@nestjs/terminus");
18
+ const nestjs_console_1 = require("nestjs-console");
19
+ const constants_js_1 = require("../../logging/constants.js");
20
+ const with_class_decorator_js_1 = require("../../shared/with-class-decorator.js");
21
+ const health_checks_js_1 = require("../health-checks.js");
22
+ let HealthCliCommands = class HealthCliCommands {
23
+ health;
24
+ logger;
25
+ healthChecks;
26
+ constructor(health, logger, healthChecks) {
27
+ this.health = health;
28
+ this.logger = logger;
29
+ this.healthChecks = healthChecks;
30
+ }
31
+ async getHealth() {
32
+ try {
33
+ const healthResult = await this.health.check(this.healthChecks.build());
34
+ this.logger.info({ healthResult }, healthResult.status);
35
+ }
36
+ catch (error) {
37
+ const healthResult = error instanceof common_1.ServiceUnavailableException ? error.getResponse() : 'unknown';
38
+ this.logger.error({ healthResult }, 'error');
39
+ }
40
+ }
41
+ };
42
+ exports.HealthCliCommands = HealthCliCommands;
43
+ __decorate([
44
+ (0, nestjs_console_1.Command)({ command: 'health' }),
45
+ __metadata("design:type", Function),
46
+ __metadata("design:paramtypes", []),
47
+ __metadata("design:returntype", Promise)
48
+ ], HealthCliCommands.prototype, "getHealth", null);
49
+ exports.HealthCliCommands = HealthCliCommands = __decorate([
50
+ __param(0, (0, common_1.Inject)(terminus_1.HealthCheckService)),
51
+ __param(1, (0, common_1.Inject)(constants_js_1.OBSERVABILITY_LOGGER)),
52
+ __param(2, (0, common_1.Inject)(health_checks_js_1.HealthChecks)),
53
+ __metadata("design:paramtypes", [terminus_1.HealthCheckService, Object, health_checks_js_1.HealthChecks])
54
+ ], HealthCliCommands);
55
+ const createHealthCli = (options) => (0, with_class_decorator_js_1.withClassDecorator)(HealthCliCommands, (0, nestjs_console_1.Console)({ command: options.command }));
56
+ exports.createHealthCli = createHealthCli;
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { HealthCliOptionsInterface } from './health-cli-options.interface.js';
3
+ export declare class HealthCliModule {
4
+ static forRoot(options: HealthCliOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.HealthCliModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const health_cli_js_1 = require("./health-cli.js");
12
+ let HealthCliModule = class HealthCliModule {
13
+ static forRoot(options) {
14
+ return {
15
+ module: this,
16
+ providers: [(0, health_cli_js_1.createHealthCli)(options)],
17
+ };
18
+ }
19
+ };
20
+ exports.HealthCliModule = HealthCliModule;
21
+ exports.HealthCliModule = HealthCliModule = __decorate([
22
+ (0, common_1.Module)({})
23
+ ], HealthCliModule);
@@ -0,0 +1,3 @@
1
+ export * from './health-cli.js';
2
+ export * from './health-cli-options.interface.js';
3
+ export * from './health-cli.module.js';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./health-cli.js"), exports);
18
+ __exportStar(require("./health-cli-options.interface.js"), exports);
19
+ __exportStar(require("./health-cli.module.js"), exports);
@@ -0,0 +1,3 @@
1
+ export declare class HealthCheckType {
2
+ status: string;
3
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.HealthCheckType = void 0;
13
+ const graphql_1 = require("@nestjs/graphql");
14
+ let HealthCheckType = class HealthCheckType {
15
+ status;
16
+ };
17
+ exports.HealthCheckType = HealthCheckType;
18
+ __decorate([
19
+ (0, graphql_1.Field)(() => String),
20
+ __metadata("design:type", String)
21
+ ], HealthCheckType.prototype, "status", void 0);
22
+ exports.HealthCheckType = HealthCheckType = __decorate([
23
+ (0, graphql_1.ObjectType)('HealthCheck')
24
+ ], HealthCheckType);
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { HealthCarrierOptionsInterface } from '../health-module-options.interface.js';
3
+ export declare class HealthGraphqlModule {
4
+ static forRoot(options?: HealthCarrierOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.HealthGraphqlModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const graphql_1 = require("@nestjs/graphql");
12
+ const with_class_decorator_js_1 = require("../../shared/with-class-decorator.js");
13
+ const health_resolver_js_1 = require("./health.resolver.js");
14
+ let HealthGraphqlModule = class HealthGraphqlModule {
15
+ static forRoot(options = {}) {
16
+ const consumerDecorators = options.publicRoute === undefined ? [] : [options.publicRoute];
17
+ return {
18
+ module: this,
19
+ providers: [(0, with_class_decorator_js_1.withClassDecorator)(health_resolver_js_1.HealthResolver, (0, common_1.applyDecorators)((0, graphql_1.Resolver)(), ...consumerDecorators))],
20
+ };
21
+ }
22
+ };
23
+ exports.HealthGraphqlModule = HealthGraphqlModule;
24
+ exports.HealthGraphqlModule = HealthGraphqlModule = __decorate([
25
+ (0, common_1.Module)({})
26
+ ], HealthGraphqlModule);
@@ -0,0 +1,11 @@
1
+ import { HealthCheckService } from '@nestjs/terminus';
2
+ import type { ObservabilityLoggerInterface } from '../../logging/observability-logger.interface.js';
3
+ import { HealthChecks } from '../health-checks.js';
4
+ import { HealthCheckType } from './health-check.type.js';
5
+ export declare class HealthResolver {
6
+ private readonly healthCheck;
7
+ private readonly logger;
8
+ private readonly healthChecks;
9
+ constructor(healthCheck: HealthCheckService, logger: ObservabilityLoggerInterface, healthChecks: HealthChecks);
10
+ health(): Promise<HealthCheckType>;
11
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.HealthResolver = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const graphql_1 = require("@nestjs/graphql");
18
+ const terminus_1 = require("@nestjs/terminus");
19
+ const constants_js_1 = require("../../logging/constants.js");
20
+ const health_checks_js_1 = require("../health-checks.js");
21
+ const health_check_type_js_1 = require("./health-check.type.js");
22
+ let HealthResolver = class HealthResolver {
23
+ healthCheck;
24
+ logger;
25
+ healthChecks;
26
+ constructor(healthCheck, logger, healthChecks) {
27
+ this.healthCheck = healthCheck;
28
+ this.logger = logger;
29
+ this.healthChecks = healthChecks;
30
+ }
31
+ async health() {
32
+ try {
33
+ const health = await this.healthCheck.check(this.healthChecks.build());
34
+ return { status: health.status };
35
+ }
36
+ catch (error) {
37
+ this.logger.error({ err: error }, 'GraphQL health check failed');
38
+ return { status: 'error' };
39
+ }
40
+ }
41
+ };
42
+ exports.HealthResolver = HealthResolver;
43
+ __decorate([
44
+ (0, graphql_1.Query)(() => health_check_type_js_1.HealthCheckType),
45
+ __metadata("design:type", Function),
46
+ __metadata("design:paramtypes", []),
47
+ __metadata("design:returntype", Promise)
48
+ ], HealthResolver.prototype, "health", null);
49
+ exports.HealthResolver = HealthResolver = __decorate([
50
+ (0, graphql_1.Resolver)({ isAbstract: true }),
51
+ __param(0, (0, common_1.Inject)(terminus_1.HealthCheckService)),
52
+ __param(1, (0, common_1.Inject)(constants_js_1.OBSERVABILITY_LOGGER)),
53
+ __param(2, (0, common_1.Inject)(health_checks_js_1.HealthChecks)),
54
+ __metadata("design:paramtypes", [terminus_1.HealthCheckService, Object, health_checks_js_1.HealthChecks])
55
+ ], HealthResolver);
@@ -0,0 +1,3 @@
1
+ export * from './health-check.type.js';
2
+ export * from './health-graphql.module.js';
3
+ export * from './health.resolver.js';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./health-check.type.js"), exports);
18
+ __exportStar(require("./health-graphql.module.js"), exports);
19
+ __exportStar(require("./health.resolver.js"), exports);
@@ -0,0 +1,10 @@
1
+ import { DiskHealthIndicator, HealthIndicatorFunction, MemoryHealthIndicator, TypeOrmHealthIndicator } from '@nestjs/terminus';
2
+ import { HealthConfig } from './health.config.js';
3
+ export declare class HealthChecks {
4
+ private readonly database;
5
+ private readonly memory;
6
+ private readonly disk;
7
+ private readonly config;
8
+ constructor(database: TypeOrmHealthIndicator, memory: MemoryHealthIndicator, disk: DiskHealthIndicator, config: HealthConfig);
9
+ build(): HealthIndicatorFunction[];
10
+ }