@spinajs/telemetry 2.0.482

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 (214) hide show
  1. package/README.md +482 -0
  2. package/lib/cjs/InMemoryPerfSink.d.ts +51 -0
  3. package/lib/cjs/InMemoryPerfSink.d.ts.map +1 -0
  4. package/lib/cjs/InMemoryPerfSink.js +100 -0
  5. package/lib/cjs/InMemoryPerfSink.js.map +1 -0
  6. package/lib/cjs/PromMetricSink.d.ts +26 -0
  7. package/lib/cjs/PromMetricSink.d.ts.map +1 -0
  8. package/lib/cjs/PromMetricSink.js +68 -0
  9. package/lib/cjs/PromMetricSink.js.map +1 -0
  10. package/lib/cjs/bootstrap.d.ts +13 -0
  11. package/lib/cjs/bootstrap.d.ts.map +1 -0
  12. package/lib/cjs/bootstrap.js +57 -0
  13. package/lib/cjs/bootstrap.js.map +1 -0
  14. package/lib/cjs/config/telemetry.d.ts +63 -0
  15. package/lib/cjs/config/telemetry.d.ts.map +1 -0
  16. package/lib/cjs/config/telemetry.js +78 -0
  17. package/lib/cjs/config/telemetry.js.map +1 -0
  18. package/lib/cjs/controllers/Metrics.d.ts +26 -0
  19. package/lib/cjs/controllers/Metrics.d.ts.map +1 -0
  20. package/lib/cjs/controllers/Metrics.js +63 -0
  21. package/lib/cjs/controllers/Metrics.js.map +1 -0
  22. package/lib/cjs/controllers/Telemetry.d.ts +92 -0
  23. package/lib/cjs/controllers/Telemetry.d.ts.map +1 -0
  24. package/lib/cjs/controllers/Telemetry.js +226 -0
  25. package/lib/cjs/controllers/Telemetry.js.map +1 -0
  26. package/lib/cjs/dto/index.d.ts +21 -0
  27. package/lib/cjs/dto/index.d.ts.map +1 -0
  28. package/lib/cjs/dto/index.js +64 -0
  29. package/lib/cjs/dto/index.js.map +1 -0
  30. package/lib/cjs/endpoints.d.ts +32 -0
  31. package/lib/cjs/endpoints.d.ts.map +1 -0
  32. package/lib/cjs/endpoints.js +38 -0
  33. package/lib/cjs/endpoints.js.map +1 -0
  34. package/lib/cjs/health.d.ts +55 -0
  35. package/lib/cjs/health.d.ts.map +1 -0
  36. package/lib/cjs/health.js +111 -0
  37. package/lib/cjs/health.js.map +1 -0
  38. package/lib/cjs/index.d.ts +16 -0
  39. package/lib/cjs/index.d.ts.map +1 -0
  40. package/lib/cjs/index.js +32 -0
  41. package/lib/cjs/index.js.map +1 -0
  42. package/lib/cjs/metrics.d.ts +16 -0
  43. package/lib/cjs/metrics.d.ts.map +1 -0
  44. package/lib/cjs/metrics.js +32 -0
  45. package/lib/cjs/metrics.js.map +1 -0
  46. package/lib/cjs/middleware.d.ts +81 -0
  47. package/lib/cjs/middleware.d.ts.map +1 -0
  48. package/lib/cjs/middleware.js +210 -0
  49. package/lib/cjs/middleware.js.map +1 -0
  50. package/lib/cjs/package.json +1 -0
  51. package/lib/cjs/policies/PublicPolicy.d.ts +16 -0
  52. package/lib/cjs/policies/PublicPolicy.d.ts.map +1 -0
  53. package/lib/cjs/policies/PublicPolicy.js +34 -0
  54. package/lib/cjs/policies/PublicPolicy.js.map +1 -0
  55. package/lib/cjs/policies/TelemetryTokenPolicy.d.ts +19 -0
  56. package/lib/cjs/policies/TelemetryTokenPolicy.d.ts.map +1 -0
  57. package/lib/cjs/policies/TelemetryTokenPolicy.js +65 -0
  58. package/lib/cjs/policies/TelemetryTokenPolicy.js.map +1 -0
  59. package/lib/cjs/requestStats.d.ts +81 -0
  60. package/lib/cjs/requestStats.d.ts.map +1 -0
  61. package/lib/cjs/requestStats.js +134 -0
  62. package/lib/cjs/requestStats.js.map +1 -0
  63. package/lib/cjs/responses.d.ts +23 -0
  64. package/lib/cjs/responses.d.ts.map +1 -0
  65. package/lib/cjs/responses.js +35 -0
  66. package/lib/cjs/responses.js.map +1 -0
  67. package/lib/cjs/routeStats.d.ts +43 -0
  68. package/lib/cjs/routeStats.d.ts.map +1 -0
  69. package/lib/cjs/routeStats.js +59 -0
  70. package/lib/cjs/routeStats.js.map +1 -0
  71. package/lib/cjs/schemas/HealthResponse.schema.d.ts +30 -0
  72. package/lib/cjs/schemas/HealthResponse.schema.d.ts.map +1 -0
  73. package/lib/cjs/schemas/HealthResponse.schema.js +15 -0
  74. package/lib/cjs/schemas/HealthResponse.schema.js.map +1 -0
  75. package/lib/cjs/schemas/PerfResponse.schema.d.ts +56 -0
  76. package/lib/cjs/schemas/PerfResponse.schema.d.ts.map +1 -0
  77. package/lib/cjs/schemas/PerfResponse.schema.js +36 -0
  78. package/lib/cjs/schemas/PerfResponse.schema.js.map +1 -0
  79. package/lib/cjs/schemas/ReadyResponse.schema.d.ts +36 -0
  80. package/lib/cjs/schemas/ReadyResponse.schema.d.ts.map +1 -0
  81. package/lib/cjs/schemas/ReadyResponse.schema.js +23 -0
  82. package/lib/cjs/schemas/ReadyResponse.schema.js.map +1 -0
  83. package/lib/cjs/schemas/RequestStatsSnapshot.schema.d.ts +79 -0
  84. package/lib/cjs/schemas/RequestStatsSnapshot.schema.d.ts.map +1 -0
  85. package/lib/cjs/schemas/RequestStatsSnapshot.schema.js +30 -0
  86. package/lib/cjs/schemas/RequestStatsSnapshot.schema.js.map +1 -0
  87. package/lib/cjs/schemas/RoutesResponse.schema.d.ts +100 -0
  88. package/lib/cjs/schemas/RoutesResponse.schema.d.ts.map +1 -0
  89. package/lib/cjs/schemas/RoutesResponse.schema.js +25 -0
  90. package/lib/cjs/schemas/RoutesResponse.schema.js.map +1 -0
  91. package/lib/cjs/schemas/StatsResponse.schema.d.ts +158 -0
  92. package/lib/cjs/schemas/StatsResponse.schema.d.ts.map +1 -0
  93. package/lib/cjs/schemas/StatsResponse.schema.js +19 -0
  94. package/lib/cjs/schemas/StatsResponse.schema.js.map +1 -0
  95. package/lib/cjs/schemas/TimelineResponse.schema.d.ts +109 -0
  96. package/lib/cjs/schemas/TimelineResponse.schema.d.ts.map +1 -0
  97. package/lib/cjs/schemas/TimelineResponse.schema.js +28 -0
  98. package/lib/cjs/schemas/TimelineResponse.schema.js.map +1 -0
  99. package/lib/cjs/store.d.ts +58 -0
  100. package/lib/cjs/store.d.ts.map +1 -0
  101. package/lib/cjs/store.js +108 -0
  102. package/lib/cjs/store.js.map +1 -0
  103. package/lib/cjs/timeline.d.ts +48 -0
  104. package/lib/cjs/timeline.d.ts.map +1 -0
  105. package/lib/cjs/timeline.js +70 -0
  106. package/lib/cjs/timeline.js.map +1 -0
  107. package/lib/mjs/InMemoryPerfSink.d.ts +51 -0
  108. package/lib/mjs/InMemoryPerfSink.d.ts.map +1 -0
  109. package/lib/mjs/InMemoryPerfSink.js +97 -0
  110. package/lib/mjs/InMemoryPerfSink.js.map +1 -0
  111. package/lib/mjs/PromMetricSink.d.ts +26 -0
  112. package/lib/mjs/PromMetricSink.d.ts.map +1 -0
  113. package/lib/mjs/PromMetricSink.js +65 -0
  114. package/lib/mjs/PromMetricSink.js.map +1 -0
  115. package/lib/mjs/bootstrap.d.ts +13 -0
  116. package/lib/mjs/bootstrap.d.ts.map +1 -0
  117. package/lib/mjs/bootstrap.js +54 -0
  118. package/lib/mjs/bootstrap.js.map +1 -0
  119. package/lib/mjs/config/telemetry.d.ts +63 -0
  120. package/lib/mjs/config/telemetry.d.ts.map +1 -0
  121. package/lib/mjs/config/telemetry.js +76 -0
  122. package/lib/mjs/config/telemetry.js.map +1 -0
  123. package/lib/mjs/controllers/Metrics.d.ts +26 -0
  124. package/lib/mjs/controllers/Metrics.d.ts.map +1 -0
  125. package/lib/mjs/controllers/Metrics.js +60 -0
  126. package/lib/mjs/controllers/Metrics.js.map +1 -0
  127. package/lib/mjs/controllers/Telemetry.d.ts +92 -0
  128. package/lib/mjs/controllers/Telemetry.d.ts.map +1 -0
  129. package/lib/mjs/controllers/Telemetry.js +223 -0
  130. package/lib/mjs/controllers/Telemetry.js.map +1 -0
  131. package/lib/mjs/dto/index.d.ts +21 -0
  132. package/lib/mjs/dto/index.d.ts.map +1 -0
  133. package/lib/mjs/dto/index.js +58 -0
  134. package/lib/mjs/dto/index.js.map +1 -0
  135. package/lib/mjs/endpoints.d.ts +32 -0
  136. package/lib/mjs/endpoints.d.ts.map +1 -0
  137. package/lib/mjs/endpoints.js +34 -0
  138. package/lib/mjs/endpoints.js.map +1 -0
  139. package/lib/mjs/health.d.ts +55 -0
  140. package/lib/mjs/health.d.ts.map +1 -0
  141. package/lib/mjs/health.js +107 -0
  142. package/lib/mjs/health.js.map +1 -0
  143. package/lib/mjs/index.d.ts +16 -0
  144. package/lib/mjs/index.d.ts.map +1 -0
  145. package/lib/mjs/index.js +16 -0
  146. package/lib/mjs/index.js.map +1 -0
  147. package/lib/mjs/metrics.d.ts +16 -0
  148. package/lib/mjs/metrics.d.ts.map +1 -0
  149. package/lib/mjs/metrics.js +16 -0
  150. package/lib/mjs/metrics.js.map +1 -0
  151. package/lib/mjs/middleware.d.ts +81 -0
  152. package/lib/mjs/middleware.d.ts.map +1 -0
  153. package/lib/mjs/middleware.js +207 -0
  154. package/lib/mjs/middleware.js.map +1 -0
  155. package/lib/mjs/package.json +1 -0
  156. package/lib/mjs/policies/PublicPolicy.d.ts +16 -0
  157. package/lib/mjs/policies/PublicPolicy.d.ts.map +1 -0
  158. package/lib/mjs/policies/PublicPolicy.js +31 -0
  159. package/lib/mjs/policies/PublicPolicy.js.map +1 -0
  160. package/lib/mjs/policies/TelemetryTokenPolicy.d.ts +19 -0
  161. package/lib/mjs/policies/TelemetryTokenPolicy.d.ts.map +1 -0
  162. package/lib/mjs/policies/TelemetryTokenPolicy.js +62 -0
  163. package/lib/mjs/policies/TelemetryTokenPolicy.js.map +1 -0
  164. package/lib/mjs/requestStats.d.ts +81 -0
  165. package/lib/mjs/requestStats.d.ts.map +1 -0
  166. package/lib/mjs/requestStats.js +130 -0
  167. package/lib/mjs/requestStats.js.map +1 -0
  168. package/lib/mjs/responses.d.ts +23 -0
  169. package/lib/mjs/responses.d.ts.map +1 -0
  170. package/lib/mjs/responses.js +30 -0
  171. package/lib/mjs/responses.js.map +1 -0
  172. package/lib/mjs/routeStats.d.ts +43 -0
  173. package/lib/mjs/routeStats.d.ts.map +1 -0
  174. package/lib/mjs/routeStats.js +55 -0
  175. package/lib/mjs/routeStats.js.map +1 -0
  176. package/lib/mjs/schemas/HealthResponse.schema.d.ts +30 -0
  177. package/lib/mjs/schemas/HealthResponse.schema.d.ts.map +1 -0
  178. package/lib/mjs/schemas/HealthResponse.schema.js +13 -0
  179. package/lib/mjs/schemas/HealthResponse.schema.js.map +1 -0
  180. package/lib/mjs/schemas/PerfResponse.schema.d.ts +56 -0
  181. package/lib/mjs/schemas/PerfResponse.schema.d.ts.map +1 -0
  182. package/lib/mjs/schemas/PerfResponse.schema.js +34 -0
  183. package/lib/mjs/schemas/PerfResponse.schema.js.map +1 -0
  184. package/lib/mjs/schemas/ReadyResponse.schema.d.ts +36 -0
  185. package/lib/mjs/schemas/ReadyResponse.schema.d.ts.map +1 -0
  186. package/lib/mjs/schemas/ReadyResponse.schema.js +21 -0
  187. package/lib/mjs/schemas/ReadyResponse.schema.js.map +1 -0
  188. package/lib/mjs/schemas/RequestStatsSnapshot.schema.d.ts +79 -0
  189. package/lib/mjs/schemas/RequestStatsSnapshot.schema.d.ts.map +1 -0
  190. package/lib/mjs/schemas/RequestStatsSnapshot.schema.js +28 -0
  191. package/lib/mjs/schemas/RequestStatsSnapshot.schema.js.map +1 -0
  192. package/lib/mjs/schemas/RoutesResponse.schema.d.ts +100 -0
  193. package/lib/mjs/schemas/RoutesResponse.schema.d.ts.map +1 -0
  194. package/lib/mjs/schemas/RoutesResponse.schema.js +20 -0
  195. package/lib/mjs/schemas/RoutesResponse.schema.js.map +1 -0
  196. package/lib/mjs/schemas/StatsResponse.schema.d.ts +158 -0
  197. package/lib/mjs/schemas/StatsResponse.schema.d.ts.map +1 -0
  198. package/lib/mjs/schemas/StatsResponse.schema.js +14 -0
  199. package/lib/mjs/schemas/StatsResponse.schema.js.map +1 -0
  200. package/lib/mjs/schemas/TimelineResponse.schema.d.ts +109 -0
  201. package/lib/mjs/schemas/TimelineResponse.schema.d.ts.map +1 -0
  202. package/lib/mjs/schemas/TimelineResponse.schema.js +23 -0
  203. package/lib/mjs/schemas/TimelineResponse.schema.js.map +1 -0
  204. package/lib/mjs/store.d.ts +58 -0
  205. package/lib/mjs/store.d.ts.map +1 -0
  206. package/lib/mjs/store.js +105 -0
  207. package/lib/mjs/store.js.map +1 -0
  208. package/lib/mjs/timeline.d.ts +48 -0
  209. package/lib/mjs/timeline.d.ts.map +1 -0
  210. package/lib/mjs/timeline.js +66 -0
  211. package/lib/mjs/timeline.js.map +1 -0
  212. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  213. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  214. package/package.json +69 -0
@@ -0,0 +1,107 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { AsyncService, Autoinject, Injectable, Singleton } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ /**
13
+ * A readiness probe for one dependency.
14
+ *
15
+ * Register a concrete subclass with `@Injectable( HealthCheck )` and it is
16
+ * discovered by {@link HealthCheckRunner} via `Array.ofType( HealthCheck )`.
17
+ * `@spinajs/telemetry` deliberately ships NO concrete checks — a database check
18
+ * belongs where the database dependency already is, not in the observability
19
+ * package.
20
+ *
21
+ * `check()` may throw; a throw counts as `down`.
22
+ */
23
+ export class HealthCheck extends AsyncService {
24
+ }
25
+ const RANK = { up: 0, degraded: 1, down: 2 };
26
+ /**
27
+ * Severity of one check's status, for the reduction in {@link HealthCheckRunner.run}.
28
+ *
29
+ * An unrecognised value ranks as `down`, not as harmless: `HealthStatus` is only
30
+ * enforced at compile time, so a JS consumer ( or a check that forwards a status
31
+ * from somewhere else ) can return `'DOWN'` or `'UNHEALTHY'`. A plain
32
+ * `RANK[status] > RANK[worst]` reads `undefined` for those, and `undefined > n`
33
+ * is false, so a genuinely failing dependency would leave the overall status at
34
+ * `up` and `/telemetry/ready` would answer 200.
35
+ */
36
+ function rank(status) {
37
+ return RANK[status] ?? RANK.down;
38
+ }
39
+ /**
40
+ * Runs every registered {@link HealthCheck} concurrently, each raced against a
41
+ * per-check timeout, and reduces the results to one overall status.
42
+ *
43
+ * The timeout is the point of the class: a readiness endpoint that can hang is
44
+ * worse than no readiness endpoint, because a kubelet probe blocks on it.
45
+ */
46
+ let HealthCheckRunner = class HealthCheckRunner {
47
+ /**
48
+ * True when the overall status should be served as HTTP 503.
49
+ */
50
+ isFailing(status) {
51
+ if (status === 'down')
52
+ return true;
53
+ return status === 'degraded' && this.FailOnDegraded === true;
54
+ }
55
+ async run() {
56
+ const checks = await Promise.all((this.Checks ?? []).map((c) => this.runOne(c)));
57
+ let worst = 'up';
58
+ for (const c of checks) {
59
+ // The unrecognised status is reduced AS `down`, but the check's own line in
60
+ // the report keeps the string the check actually returned — that value is
61
+ // the only clue an operator has that a check is misbehaving, and rewriting
62
+ // it would hide the misconfiguration behind a correct-looking report.
63
+ if (rank(c.status) > rank(worst))
64
+ worst = RANK[c.status] !== undefined ? c.status : 'down';
65
+ }
66
+ return { status: worst, checks };
67
+ }
68
+ async runOne(check) {
69
+ const startedAt = Date.now();
70
+ const timeoutMs = this.TimeoutMs ?? 2000;
71
+ let timer;
72
+ try {
73
+ const result = await Promise.race([
74
+ check.check(),
75
+ new Promise((_, reject) => {
76
+ timer = setTimeout(() => reject(new Error(`health check timed out after ${timeoutMs}ms`)), timeoutMs);
77
+ }),
78
+ ]);
79
+ return { name: check.Name, status: result.status, message: result.message, data: result.data, durationMs: Date.now() - startedAt };
80
+ }
81
+ catch (err) {
82
+ return { name: check.Name, status: 'down', message: err?.message ?? String(err), durationMs: Date.now() - startedAt };
83
+ }
84
+ finally {
85
+ if (timer)
86
+ clearTimeout(timer);
87
+ }
88
+ }
89
+ };
90
+ __decorate([
91
+ Autoinject(HealthCheck),
92
+ __metadata("design:type", Array)
93
+ ], HealthCheckRunner.prototype, "Checks", void 0);
94
+ __decorate([
95
+ Config('telemetry.health.timeoutMs', { defaultValue: 2000 }),
96
+ __metadata("design:type", Number)
97
+ ], HealthCheckRunner.prototype, "TimeoutMs", void 0);
98
+ __decorate([
99
+ Config('telemetry.health.failOnDegraded', { defaultValue: false }),
100
+ __metadata("design:type", Boolean)
101
+ ], HealthCheckRunner.prototype, "FailOnDegraded", void 0);
102
+ HealthCheckRunner = __decorate([
103
+ Singleton(),
104
+ Injectable()
105
+ ], HealthCheckRunner);
106
+ export { HealthCheckRunner };
107
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export * from './metrics.js';
2
+ export * from './bootstrap.js';
3
+ export * from './InMemoryPerfSink.js';
4
+ export * from './requestStats.js';
5
+ export * from './timeline.js';
6
+ export * from './routeStats.js';
7
+ export * from './store.js';
8
+ export * from './middleware.js';
9
+ export * from './endpoints.js';
10
+ export * from './PromMetricSink.js';
11
+ export * from './policies/TelemetryTokenPolicy.js';
12
+ export * from './policies/PublicPolicy.js';
13
+ export * from './responses.js';
14
+ export * from './health.js';
15
+ export * from './dto/index.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export * from './metrics.js';
2
+ export * from './bootstrap.js';
3
+ export * from './InMemoryPerfSink.js';
4
+ export * from './requestStats.js';
5
+ export * from './timeline.js';
6
+ export * from './routeStats.js';
7
+ export * from './store.js';
8
+ export * from './middleware.js';
9
+ export * from './endpoints.js';
10
+ export * from './PromMetricSink.js';
11
+ export * from './policies/TelemetryTokenPolicy.js';
12
+ export * from './policies/PublicPolicy.js';
13
+ export * from './responses.js';
14
+ export * from './health.js';
15
+ export * from './dto/index.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The metric abstraction lives in `@spinajs/telemetry-common`, which depends on nothing but
3
+ * `@spinajs/di` and prom-client.
4
+ *
5
+ * It was extracted for one reason: `@spinajs/orm` publishes connection-pool telemetry, and this
6
+ * package depends on `@spinajs/http`, `@spinajs/log`, `@spinajs/validation` and
7
+ * `@spinajs/configuration`. An ORM that depended on `@spinajs/telemetry` would put the whole HTTP
8
+ * stack underneath every database connection. Same reason `@spinajs/configuration-common` and
9
+ * `@spinajs/log-common` exist.
10
+ *
11
+ * Re-exported here so `import { Metrics } from '@spinajs/telemetry'` keeps working, and so both
12
+ * packages share ONE `Metrics` class identity — DI resolves the singleton by that identity, and a
13
+ * second copy would mean a second, separate registry.
14
+ */
15
+ export * from '@spinajs/telemetry-common';
16
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The metric abstraction lives in `@spinajs/telemetry-common`, which depends on nothing but
3
+ * `@spinajs/di` and prom-client.
4
+ *
5
+ * It was extracted for one reason: `@spinajs/orm` publishes connection-pool telemetry, and this
6
+ * package depends on `@spinajs/http`, `@spinajs/log`, `@spinajs/validation` and
7
+ * `@spinajs/configuration`. An ORM that depended on `@spinajs/telemetry` would put the whole HTTP
8
+ * stack underneath every database connection. Same reason `@spinajs/configuration-common` and
9
+ * `@spinajs/log-common` exist.
10
+ *
11
+ * Re-exported here so `import { Metrics } from '@spinajs/telemetry'` keeps working, and so both
12
+ * packages share ONE `Metrics` class identity — DI resolves the singleton by that identity, and a
13
+ * second copy would mean a second, separate registry.
14
+ */
15
+ export * from '@spinajs/telemetry-common';
16
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,81 @@
1
+ import * as express from 'express';
2
+ import { Log } from '@spinajs/log';
3
+ import { ServerMiddleware, Request as sRequest } from '@spinajs/http';
4
+ import { Counter, Gauge, Histogram } from 'prom-client';
5
+ import { Metrics } from './metrics.js';
6
+ import { TelemetryStore } from './store.js';
7
+ /**
8
+ * Default metric-name prefix for the HTTP telemetry metrics.
9
+ */
10
+ export declare const DEFAULT_PREFIX = "http";
11
+ /**
12
+ * Histogram bucket boundaries ( ms ) for request duration.
13
+ */
14
+ export declare const DURATION_BUCKETS_MS: number[];
15
+ /**
16
+ * HTTP request-timing / metrics middleware.
17
+ *
18
+ * Times every request and records:
19
+ * - `${prefix}_requests_total{method,route,status}` — a Counter,
20
+ * - `${prefix}_request_duration_ms{method,route,status}` — a Histogram,
21
+ * - `${prefix}_requests_in_flight` — a Gauge,
22
+ * against the DI-resolved {@link Metrics} registry, and feeds the shared
23
+ * {@link TelemetryStore} that backs the JSON stats endpoints.
24
+ *
25
+ * All of the end-of-request work runs from a `res.on( 'finish' )` handler
26
+ * registered in `before()` — `ServerMiddleware.after()` is never reached for a
27
+ * normal matched route, the same reason http's own `AccessLog` / `PerfRollup`
28
+ * middlewares work this way. A `res.on( 'close' )` handler balances the in-flight
29
+ * gauge — and only the gauge — for requests the client aborted, where `'finish'`
30
+ * never fires. Every bit of it is guarded so telemetry can never break a request.
31
+ */
32
+ export declare class TelemetryMiddleware extends ServerMiddleware {
33
+ protected Log: Log;
34
+ /**
35
+ * The shared aggregates. This middleware is the only writer.
36
+ */
37
+ protected Store: TelemetryStore;
38
+ /**
39
+ * Metric-name prefix. Set it with the `telemetry.prefix` configuration key —
40
+ * that is the supported way to re-prefix, and it needs no subclass.
41
+ *
42
+ * The precedence implemented in {@link ensureMetrics} is: a value assigned to
43
+ * this field that differs from {@link DEFAULT_PREFIX} wins, otherwise
44
+ * `telemetry.prefix` is used, otherwise {@link DEFAULT_PREFIX}. That override
45
+ * exists for subclasses that are replacing the middleware wholesale — see the
46
+ * README's "Replacing the middleware" section, which also covers the
47
+ * double-registration hazard of subclassing. Do NOT subclass merely to change
48
+ * the prefix.
49
+ */
50
+ protected Prefix: string;
51
+ protected ConfiguredPrefix: string;
52
+ protected Buckets: number[];
53
+ protected metrics: Metrics;
54
+ protected requestsTotal: Counter<string>;
55
+ protected requestDuration: Histogram<string>;
56
+ protected inFlight: Gauge<string>;
57
+ private defined;
58
+ constructor();
59
+ /**
60
+ * Lazily resolve {@link Metrics} and define the metric set on first use.
61
+ * Idempotent — {@link Metrics.defineMetrics} removes+recreates duplicates.
62
+ */
63
+ protected ensureMetrics(): void;
64
+ /**
65
+ * Derive a stable, low-cardinality route label. Prefers the matched route
66
+ * path ( `req.route.path` or `req.storage.route` ) over the raw request path.
67
+ */
68
+ protected routeLabel(req: sRequest): string;
69
+ /**
70
+ * Do the end-of-request accounting. Called from the response `finish` event,
71
+ * never from `after()`.
72
+ */
73
+ protected onFinish(req: sRequest, res: express.Response): void;
74
+ before(): (req: sRequest, res: express.Response, next: express.NextFunction) => void;
75
+ /**
76
+ * Nothing to do after the controllers — express does not run this for a
77
+ * matched route. See {@link onFinish}.
78
+ */
79
+ after(): null;
80
+ }
81
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAU,GAAG,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,cAAc,SAAS,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,mBAAmB,UAA0D,CAAC;AAO3F;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,mBAAoB,SAAQ,gBAAgB;IAEvD,SAAS,CAAC,GAAG,EAAG,GAAG,CAAC;IAEpB;;OAEG;IAEH,SAAS,CAAC,KAAK,EAAG,cAAc,CAAC;IAEjC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,MAAM,SAAkB;IAGlC,SAAS,CAAC,gBAAgB,EAAG,MAAM,CAAC;IAGpC,SAAS,CAAC,OAAO,EAAG,MAAM,EAAE,CAAC;IAE7B,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,aAAa,EAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,SAAS,CAAC,eAAe,EAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9C,SAAS,CAAC,QAAQ,EAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAEnC,OAAO,CAAC,OAAO,CAAS;;IASxB;;;OAGG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAmC/B;;;OAGG;IACH,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM;IAO3C;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,GAAG,IAAI;IA0BvD,MAAM,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,YAAY,KAAK,IAAI;IA0C3F;;;OAGG;IACI,KAAK,IAAI,IAAI;CAGrB"}
@@ -0,0 +1,207 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Autoinject, DI, Injectable } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ import { Logger, Log } from '@spinajs/log';
13
+ import { ServerMiddleware } from '@spinajs/http';
14
+ import { Metrics } from './metrics.js';
15
+ import { TelemetryStore } from './store.js';
16
+ /**
17
+ * Default metric-name prefix for the HTTP telemetry metrics.
18
+ */
19
+ export const DEFAULT_PREFIX = 'http';
20
+ /**
21
+ * Histogram bucket boundaries ( ms ) for request duration.
22
+ */
23
+ export const DURATION_BUCKETS_MS = [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];
24
+ /**
25
+ * Storage key under `req.storage` holding the per-request start time.
26
+ */
27
+ const START_KEY = '__telemetryStart';
28
+ /**
29
+ * HTTP request-timing / metrics middleware.
30
+ *
31
+ * Times every request and records:
32
+ * - `${prefix}_requests_total{method,route,status}` — a Counter,
33
+ * - `${prefix}_request_duration_ms{method,route,status}` — a Histogram,
34
+ * - `${prefix}_requests_in_flight` — a Gauge,
35
+ * against the DI-resolved {@link Metrics} registry, and feeds the shared
36
+ * {@link TelemetryStore} that backs the JSON stats endpoints.
37
+ *
38
+ * All of the end-of-request work runs from a `res.on( 'finish' )` handler
39
+ * registered in `before()` — `ServerMiddleware.after()` is never reached for a
40
+ * normal matched route, the same reason http's own `AccessLog` / `PerfRollup`
41
+ * middlewares work this way. A `res.on( 'close' )` handler balances the in-flight
42
+ * gauge — and only the gauge — for requests the client aborted, where `'finish'`
43
+ * never fires. Every bit of it is guarded so telemetry can never break a request.
44
+ */
45
+ let TelemetryMiddleware = class TelemetryMiddleware extends ServerMiddleware {
46
+ constructor() {
47
+ super();
48
+ /**
49
+ * Metric-name prefix. Set it with the `telemetry.prefix` configuration key —
50
+ * that is the supported way to re-prefix, and it needs no subclass.
51
+ *
52
+ * The precedence implemented in {@link ensureMetrics} is: a value assigned to
53
+ * this field that differs from {@link DEFAULT_PREFIX} wins, otherwise
54
+ * `telemetry.prefix` is used, otherwise {@link DEFAULT_PREFIX}. That override
55
+ * exists for subclasses that are replacing the middleware wholesale — see the
56
+ * README's "Replacing the middleware" section, which also covers the
57
+ * double-registration hazard of subclassing. Do NOT subclass merely to change
58
+ * the prefix.
59
+ */
60
+ this.Prefix = DEFAULT_PREFIX;
61
+ this.defined = false;
62
+ // Needs req.storage ( ReqStorage = -2 ) and sits alongside RequestId /
63
+ // AccessLog ( Order 2 ).
64
+ this.Order = 2;
65
+ }
66
+ /**
67
+ * Lazily resolve {@link Metrics} and define the metric set on first use.
68
+ * Idempotent — {@link Metrics.defineMetrics} removes+recreates duplicates.
69
+ */
70
+ ensureMetrics() {
71
+ if (this.defined)
72
+ return;
73
+ this.metrics = DI.get(Metrics) ?? DI.resolve(Metrics);
74
+ // A subclass that overrode Prefix keeps it; otherwise configuration wins.
75
+ const prefix = this.Prefix !== DEFAULT_PREFIX ? this.Prefix : this.ConfiguredPrefix ?? DEFAULT_PREFIX;
76
+ const map = this.metrics.defineMetrics(prefix, [
77
+ {
78
+ name: 'requests_total',
79
+ help: 'Total number of HTTP requests',
80
+ type: 'counter',
81
+ labelNames: ['method', 'route', 'status'],
82
+ },
83
+ {
84
+ name: 'request_duration_ms',
85
+ help: 'HTTP request duration in milliseconds',
86
+ type: 'histogram',
87
+ labelNames: ['method', 'route', 'status'],
88
+ buckets: this.Buckets ?? DURATION_BUCKETS_MS,
89
+ },
90
+ {
91
+ name: 'requests_in_flight',
92
+ help: 'Number of HTTP requests currently in flight',
93
+ type: 'gauge',
94
+ },
95
+ ]);
96
+ this.requestsTotal = map['requests_total'];
97
+ this.requestDuration = map['request_duration_ms'];
98
+ this.inFlight = map['requests_in_flight'];
99
+ this.defined = true;
100
+ }
101
+ /**
102
+ * Derive a stable, low-cardinality route label. Prefers the matched route
103
+ * path ( `req.route.path` or `req.storage.route` ) over the raw request path.
104
+ */
105
+ routeLabel(req) {
106
+ const anyReq = req;
107
+ const matched = anyReq.route?.path ?? req.storage?.route;
108
+ if (typeof matched === 'string' && matched.length > 0)
109
+ return matched;
110
+ return req.path ?? anyReq.originalUrl ?? 'unknown';
111
+ }
112
+ /**
113
+ * Do the end-of-request accounting. Called from the response `finish` event,
114
+ * never from `after()`.
115
+ */
116
+ onFinish(req, res) {
117
+ try {
118
+ const start = req.storage?.[START_KEY];
119
+ const durationMs = start !== undefined ? Number(process.hrtime.bigint() - start) / 1e6 : 0;
120
+ const method = req.method ?? 'GET';
121
+ // Read the route label HERE, not in before(): `req.route` is only
122
+ // populated once the router has matched.
123
+ const route = this.routeLabel(req);
124
+ const status = res.statusCode;
125
+ const labels = { method, route, status: String(status) };
126
+ // Balance before()'s inc() FIRST: a throw from anything below would
127
+ // otherwise strand the gauge one higher for the rest of the process.
128
+ this.inFlight.dec();
129
+ this.requestDuration.observe(labels, durationMs);
130
+ this.requestsTotal.inc(labels);
131
+ this.Store.record(method, route, status, durationMs);
132
+ }
133
+ catch (err) {
134
+ this.Log?.warn(err, 'telemetry finish handler failed');
135
+ }
136
+ }
137
+ before() {
138
+ return (req, res, next) => {
139
+ try {
140
+ this.ensureMetrics();
141
+ req.storage[START_KEY] = process.hrtime.bigint();
142
+ this.inFlight.inc();
143
+ // The inc() above must be balanced exactly once, whichever event wins.
144
+ // 'finish' does NOT fire when the client disconnects mid-response, only
145
+ // 'close' does — without the 'close' arm the gauge drifts monotonically
146
+ // upward for the life of the process behind a load balancer with client
147
+ // timeouts. On a normal request both fire, 'finish' first, so the flag
148
+ // is what keeps the gauge from being decremented twice.
149
+ let settled = false;
150
+ res.on('finish', () => {
151
+ if (settled)
152
+ return;
153
+ settled = true;
154
+ this.onFinish(req, res);
155
+ });
156
+ res.on('close', () => {
157
+ if (settled)
158
+ return;
159
+ settled = true;
160
+ // Aborted request: balance the gauge and NOTHING else. `res.statusCode`
161
+ // is still the un-sent default here, so recording it would pollute the
162
+ // status-class counters and the route stats with a response that was
163
+ // never sent.
164
+ try {
165
+ this.inFlight.dec();
166
+ }
167
+ catch (err) {
168
+ this.Log?.warn(err, 'telemetry close handler failed');
169
+ }
170
+ });
171
+ }
172
+ catch (err) {
173
+ this.Log?.warn(err, 'telemetry before() failed');
174
+ }
175
+ next();
176
+ };
177
+ }
178
+ /**
179
+ * Nothing to do after the controllers — express does not run this for a
180
+ * matched route. See {@link onFinish}.
181
+ */
182
+ after() {
183
+ return null;
184
+ }
185
+ };
186
+ __decorate([
187
+ Logger('telemetry'),
188
+ __metadata("design:type", Log)
189
+ ], TelemetryMiddleware.prototype, "Log", void 0);
190
+ __decorate([
191
+ Autoinject(TelemetryStore),
192
+ __metadata("design:type", TelemetryStore)
193
+ ], TelemetryMiddleware.prototype, "Store", void 0);
194
+ __decorate([
195
+ Config('telemetry.prefix', { defaultValue: DEFAULT_PREFIX }),
196
+ __metadata("design:type", String)
197
+ ], TelemetryMiddleware.prototype, "ConfiguredPrefix", void 0);
198
+ __decorate([
199
+ Config('telemetry.buckets', { defaultValue: DURATION_BUCKETS_MS }),
200
+ __metadata("design:type", Array)
201
+ ], TelemetryMiddleware.prototype, "Buckets", void 0);
202
+ TelemetryMiddleware = __decorate([
203
+ Injectable(ServerMiddleware),
204
+ __metadata("design:paramtypes", [])
205
+ ], TelemetryMiddleware);
206
+ export { TelemetryMiddleware };
207
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,16 @@
1
+ import { BasePolicy, IController, IRoute, Request } from '@spinajs/http';
2
+ /**
3
+ * A policy that permits everything. Used as the explicit default for the
4
+ * liveness / readiness endpoints, which must be reachable by kubelet probes and
5
+ * load balancers that cannot carry a token.
6
+ *
7
+ * This exists so the config can name a real class. Leaving the policy config
8
+ * key empty would work, but the http layer logs `No policy named ... is
9
+ * registered` on every boot for an unresolvable value, which reads like a
10
+ * misconfiguration.
11
+ */
12
+ export declare class PublicPolicy extends BasePolicy {
13
+ isEnabled(_action: IRoute, _instance: IController): boolean;
14
+ execute(_req: Request): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=PublicPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PublicPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/PublicPolicy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEzE;;;;;;;;;GASG;AACH,qBACa,YAAa,SAAQ,UAAU;IACnC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,GAAG,OAAO;IAI3D,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7C"}
@@ -0,0 +1,31 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Injectable } from '@spinajs/di';
8
+ import { BasePolicy } from '@spinajs/http';
9
+ /**
10
+ * A policy that permits everything. Used as the explicit default for the
11
+ * liveness / readiness endpoints, which must be reachable by kubelet probes and
12
+ * load balancers that cannot carry a token.
13
+ *
14
+ * This exists so the config can name a real class. Leaving the policy config
15
+ * key empty would work, but the http layer logs `No policy named ... is
16
+ * registered` on every boot for an unresolvable value, which reads like a
17
+ * misconfiguration.
18
+ */
19
+ let PublicPolicy = class PublicPolicy extends BasePolicy {
20
+ isEnabled(_action, _instance) {
21
+ return true;
22
+ }
23
+ execute(_req) {
24
+ return Promise.resolve();
25
+ }
26
+ };
27
+ PublicPolicy = __decorate([
28
+ Injectable(BasePolicy)
29
+ ], PublicPolicy);
30
+ export { PublicPolicy };
31
+ //# sourceMappingURL=PublicPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PublicPolicy.js","sourceRoot":"","sources":["../../../src/policies/PublicPolicy.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAgC,MAAM,eAAe,CAAC;AAEzE;;;;;;;;;GASG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IACnC,SAAS,CAAC,OAAe,EAAE,SAAsB;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,OAAO,CAAC,IAAa;QAC1B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AARY,YAAY;IADxB,UAAU,CAAC,UAAU,CAAC;GACV,YAAY,CAQxB"}
@@ -0,0 +1,19 @@
1
+ import { BasePolicy, IController, IRoute, Request } from '@spinajs/http';
2
+ import { Log } from '@spinajs/log';
3
+ /**
4
+ * Shared-token guard for the telemetry endpoints. Reads the expected token from
5
+ * `telemetry.auth.token` and compares it against the `x-metrics-token` header.
6
+ * The header name is deliberately unchanged from the retired
7
+ * `@spinajs/metrics` package so existing scrape configs keep working.
8
+ *
9
+ * Bypassed entirely in development.
10
+ */
11
+ export declare class TelemetryTokenPolicy extends BasePolicy {
12
+ protected Log: Log;
13
+ protected Token: string;
14
+ protected isDev: boolean;
15
+ protected HEADER_TOKEN_FIELD: string;
16
+ isEnabled(_action: IRoute, _instance: IController): boolean;
17
+ execute(req: Request): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=TelemetryTokenPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelemetryTokenPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/TelemetryTokenPolicy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAG3C;;;;;;;GAOG;AACH,qBACa,oBAAqB,SAAQ,UAAU;IAElD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;IAGxB,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC;IAEzB,SAAS,CAAC,kBAAkB,SAAqB;IAE1C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,GAAG,OAAO;IAIrD,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBlD"}
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Config } from '@spinajs/configuration';
11
+ import { BasePolicy } from '@spinajs/http';
12
+ import { Forbidden } from '@spinajs/exceptions';
13
+ import { Log, Logger } from '@spinajs/log';
14
+ import { Injectable } from '@spinajs/di';
15
+ /**
16
+ * Shared-token guard for the telemetry endpoints. Reads the expected token from
17
+ * `telemetry.auth.token` and compares it against the `x-metrics-token` header.
18
+ * The header name is deliberately unchanged from the retired
19
+ * `@spinajs/metrics` package so existing scrape configs keep working.
20
+ *
21
+ * Bypassed entirely in development.
22
+ */
23
+ let TelemetryTokenPolicy = class TelemetryTokenPolicy extends BasePolicy {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.HEADER_TOKEN_FIELD = 'x-metrics-token';
27
+ }
28
+ isEnabled(_action, _instance) {
29
+ return true;
30
+ }
31
+ async execute(req) {
32
+ if (this.isDev) {
33
+ return;
34
+ }
35
+ const token = req.headers[this.HEADER_TOKEN_FIELD];
36
+ if (!token) {
37
+ this.Log.warn(`No token is set for restricted area, header field: ${this.HEADER_TOKEN_FIELD}, policy: TelemetryTokenPolicy, ip: ${req.storage.realIp}`);
38
+ throw new Forbidden('access token is not set');
39
+ }
40
+ if (token !== this.Token) {
41
+ this.Log.warn(`Invalid access token received, header field: ${this.HEADER_TOKEN_FIELD}, policy: TelemetryTokenPolicy, ip: ${req.storage.realIp}`);
42
+ throw new Forbidden('invalid access token');
43
+ }
44
+ }
45
+ };
46
+ __decorate([
47
+ Logger('Security'),
48
+ __metadata("design:type", Log)
49
+ ], TelemetryTokenPolicy.prototype, "Log", void 0);
50
+ __decorate([
51
+ Config('telemetry.auth.token'),
52
+ __metadata("design:type", String)
53
+ ], TelemetryTokenPolicy.prototype, "Token", void 0);
54
+ __decorate([
55
+ Config('configuration.isDevelopment'),
56
+ __metadata("design:type", Boolean)
57
+ ], TelemetryTokenPolicy.prototype, "isDev", void 0);
58
+ TelemetryTokenPolicy = __decorate([
59
+ Injectable(BasePolicy)
60
+ ], TelemetryTokenPolicy);
61
+ export { TelemetryTokenPolicy };
62
+ //# sourceMappingURL=TelemetryTokenPolicy.js.map