apm-optima 1.0.5 → 2.0.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 (177) hide show
  1. package/README.md +54 -23
  2. package/dashboard-out/404/index.html +1 -1
  3. package/dashboard-out/404.html +1 -1
  4. package/dashboard-out/__next.__PAGE__.txt +4 -4
  5. package/dashboard-out/__next._full.txt +17 -17
  6. package/dashboard-out/__next._head.txt +4 -4
  7. package/dashboard-out/__next._index.txt +10 -10
  8. package/dashboard-out/__next._tree.txt +2 -2
  9. package/dashboard-out/_next/static/chunks/{2xjcsu4pgp14_.js → 062oipeclh9bq.js} +1 -1
  10. package/dashboard-out/_next/static/chunks/0ncbimuip0-o7.css +3 -0
  11. package/dashboard-out/_next/static/chunks/0xtgenoch3q77.js +1 -0
  12. package/dashboard-out/_next/static/chunks/1xln1-s87x5yp.js +27 -0
  13. package/dashboard-out/_not-found/__next._full.txt +15 -15
  14. package/dashboard-out/_not-found/__next._head.txt +4 -4
  15. package/dashboard-out/_not-found/__next._index.txt +10 -10
  16. package/dashboard-out/_not-found/__next._not-found.__PAGE__.txt +2 -2
  17. package/dashboard-out/_not-found/__next._not-found.txt +3 -3
  18. package/dashboard-out/_not-found/__next._tree.txt +2 -2
  19. package/dashboard-out/_not-found/index.html +1 -1
  20. package/dashboard-out/_not-found/index.txt +15 -15
  21. package/dashboard-out/index.html +1 -1
  22. package/dashboard-out/index.txt +17 -17
  23. package/dist/adapters/session-export.handler.d.ts +4 -0
  24. package/dist/adapters/session-export.handler.js +29 -0
  25. package/dist/adapters/socket.options.d.ts +3 -0
  26. package/dist/adapters/socket.options.js +16 -0
  27. package/dist/config/config.manager.d.ts +80 -3
  28. package/dist/config/config.manager.js +269 -89
  29. package/dist/config/config.types.d.ts +89 -13
  30. package/dist/core/delivery/buckets-request.d.ts +2 -0
  31. package/dist/core/delivery/buckets-request.js +18 -0
  32. package/dist/core/delivery/index.d.ts +1 -0
  33. package/dist/core/delivery/index.js +1 -0
  34. package/dist/core/delivery/metrics.publisher.d.ts +23 -10
  35. package/dist/core/delivery/metrics.publisher.js +22 -22
  36. package/dist/core/delivery/websocket.events.d.ts +14 -3
  37. package/dist/core/delivery/websocket.events.js +13 -2
  38. package/dist/core/domain/correlation.types.d.ts +37 -0
  39. package/dist/core/domain/correlation.types.js +2 -0
  40. package/dist/core/domain/dashboard.types.d.ts +16 -69
  41. package/dist/core/domain/dashboard.types.js +29 -0
  42. package/dist/core/domain/endpoints.types.d.ts +3 -0
  43. package/dist/core/domain/event.types.d.ts +14 -0
  44. package/dist/core/domain/event.types.js +2 -0
  45. package/dist/core/domain/incident.types.d.ts +50 -0
  46. package/dist/core/domain/incident.types.js +2 -0
  47. package/dist/core/domain/index.d.ts +5 -0
  48. package/dist/core/domain/index.js +5 -0
  49. package/dist/core/domain/live-bucket.types.d.ts +86 -0
  50. package/dist/core/domain/live-bucket.types.js +2 -0
  51. package/dist/core/domain/metrics.types.d.ts +41 -11
  52. package/dist/core/domain/session.types.d.ts +93 -0
  53. package/dist/core/domain/session.types.js +2 -0
  54. package/dist/core/domain/telemetry.types.d.ts +1 -0
  55. package/dist/core/organizers/event.manager.d.ts +19 -0
  56. package/dist/core/organizers/event.manager.js +73 -0
  57. package/dist/core/organizers/index.d.ts +2 -0
  58. package/dist/core/organizers/index.js +18 -0
  59. package/dist/core/organizers/interval.manager.d.ts +18 -0
  60. package/dist/core/organizers/interval.manager.js +54 -0
  61. package/dist/core/storage/index.d.ts +1 -0
  62. package/dist/core/storage/index.js +1 -0
  63. package/dist/core/storage/local.repository.d.ts +12 -12
  64. package/dist/core/storage/local.repository.js +38 -38
  65. package/dist/core/storage/persistence/persistence-writer.d.ts +48 -0
  66. package/dist/core/storage/persistence/persistence-writer.js +191 -0
  67. package/dist/core/storage/persistence/segment-index.d.ts +27 -0
  68. package/dist/core/storage/persistence/segment-index.js +206 -0
  69. package/dist/core/storage/persistence/session-registry.d.ts +28 -0
  70. package/dist/core/storage/persistence/session-registry.js +127 -0
  71. package/dist/core/storage/persistence/session-summary.d.ts +3 -0
  72. package/dist/core/storage/persistence/session-summary.js +112 -0
  73. package/dist/core/storage/persistence.layer.d.ts +69 -0
  74. package/dist/core/storage/persistence.layer.js +404 -0
  75. package/dist/core/storage/runtime/anomaly-detector.d.ts +11 -0
  76. package/dist/core/storage/runtime/anomaly-detector.js +42 -0
  77. package/dist/core/storage/stores/analytics.store.d.ts +5 -5
  78. package/dist/core/storage/stores/analytics.store.js +39 -12
  79. package/dist/core/storage/stores/bucket-metric.d.ts +85 -0
  80. package/dist/core/storage/stores/bucket-metric.js +168 -0
  81. package/dist/core/storage/stores/bucket-view.d.ts +44 -0
  82. package/dist/core/storage/stores/bucket-view.js +63 -0
  83. package/dist/core/storage/stores/bucket.store.d.ts +39 -36
  84. package/dist/core/storage/stores/bucket.store.js +112 -60
  85. package/dist/core/storage/stores/dashboard.store.d.ts +11 -4
  86. package/dist/core/storage/stores/dashboard.store.js +179 -47
  87. package/dist/core/storage/stores/endpoint.store.d.ts +1 -0
  88. package/dist/core/storage/stores/endpoint.store.js +21 -5
  89. package/dist/core/storage/stores/index.d.ts +0 -7
  90. package/dist/core/storage/stores/index.js +0 -7
  91. package/dist/core/storage/stores/metrics.store.d.ts +1 -1
  92. package/dist/core/storage/stores/metrics.store.js +1 -0
  93. package/dist/core/storage/stores/runtime.store.d.ts +77 -0
  94. package/dist/core/storage/stores/runtime.store.js +222 -0
  95. package/dist/core/storage/utility/common.d.ts +1 -0
  96. package/dist/core/storage/utility/common.js +11 -0
  97. package/dist/core/storage/utility/file-buffer.d.ts +31 -0
  98. package/dist/core/storage/utility/file-buffer.js +238 -0
  99. package/dist/core/storage/utility/histogram.d.ts +1 -2
  100. package/dist/core/storage/utility/histogram.js +1 -2
  101. package/dist/core/storage/utility/index.d.ts +2 -0
  102. package/dist/core/storage/utility/index.js +2 -0
  103. package/dist/core/storage/utility/persistence-files.d.ts +3 -0
  104. package/dist/core/storage/utility/persistence-files.js +34 -0
  105. package/dist/core/storage/utility/persistence-writer.d.ts +39 -0
  106. package/dist/core/storage/utility/persistence-writer.js +183 -0
  107. package/dist/core/storage/utility/session-export.d.ts +3 -0
  108. package/dist/core/storage/utility/session-export.js +31 -0
  109. package/dist/core/storage/utility/session-registry.d.ts +21 -0
  110. package/dist/core/storage/utility/session-registry.js +91 -0
  111. package/dist/core/storage/utility/session-window.d.ts +8 -0
  112. package/dist/core/storage/utility/session-window.js +43 -0
  113. package/dist/core/telemetry/analytics.service.d.ts +18 -0
  114. package/dist/core/telemetry/analytics.service.js +100 -0
  115. package/dist/core/telemetry/collector.service.d.ts +17 -15
  116. package/dist/core/telemetry/collector.service.js +23 -80
  117. package/dist/core/telemetry/correlation.service.d.ts +57 -9
  118. package/dist/core/telemetry/correlation.service.js +246 -54
  119. package/dist/core/telemetry/dashboard-live.service.d.ts +10 -0
  120. package/dist/core/telemetry/dashboard-live.service.js +110 -0
  121. package/dist/core/telemetry/dashboard.service.d.ts +20 -0
  122. package/dist/core/telemetry/dashboard.service.js +140 -0
  123. package/dist/core/telemetry/incident.service.d.ts +71 -0
  124. package/dist/core/telemetry/incident.service.js +239 -0
  125. package/dist/core/telemetry/logger.d.ts +4 -0
  126. package/dist/core/telemetry/logger.js +5 -2
  127. package/dist/core/telemetry/runtime.service.d.ts +14 -0
  128. package/dist/core/telemetry/runtime.service.js +56 -0
  129. package/dist/core/telemetry/telemetry-query.service.d.ts +82 -0
  130. package/dist/core/telemetry/telemetry-query.service.js +231 -0
  131. package/dist/core/telemetry/telemetry.service.d.ts +10 -4
  132. package/dist/core/telemetry/telemetry.service.js +60 -10
  133. package/dist/core/telemetry/utility/correlation-analysis.d.ts +9 -0
  134. package/dist/core/telemetry/utility/correlation-analysis.js +143 -0
  135. package/dist/core/telemetry/utility/correlation-finding.d.ts +70 -0
  136. package/dist/core/telemetry/utility/correlation-finding.js +41 -0
  137. package/dist/core/telemetry/utility/correlation-input.d.ts +59 -0
  138. package/dist/core/telemetry/utility/correlation-input.js +139 -0
  139. package/dist/core/telemetry/utility/correlation-replay.d.ts +24 -0
  140. package/dist/core/telemetry/utility/correlation-replay.js +46 -0
  141. package/dist/core/utility/correlation.analysis.d.ts +9 -0
  142. package/dist/core/utility/correlation.analysis.js +144 -0
  143. package/dist/core/utility/statistics.d.ts +65 -0
  144. package/dist/core/utility/statistics.js +141 -0
  145. package/dist/express/index.d.ts +1 -1
  146. package/dist/express/index.js +7 -5
  147. package/dist/express/metrics-websocket.adapter.d.ts +8 -2
  148. package/dist/express/metrics-websocket.adapter.js +52 -19
  149. package/dist/express/metrics.adapter.d.ts +1 -0
  150. package/dist/express/metrics.adapter.js +8 -1
  151. package/dist/express/metrics.bootstrap.d.ts +6 -1
  152. package/dist/express/metrics.bootstrap.js +48 -22
  153. package/dist/express/metrics.dashboard.d.ts +2 -1
  154. package/dist/express/metrics.dashboard.js +4 -1
  155. package/dist/express/metrics.middleware.d.ts +2 -1
  156. package/dist/express/metrics.middleware.js +23 -20
  157. package/dist/nest/metrics-websocket.adapter.d.ts +19 -3
  158. package/dist/nest/metrics-websocket.adapter.js +101 -21
  159. package/dist/nest/metrics.adapter.d.ts +4 -1
  160. package/dist/nest/metrics.adapter.js +24 -1
  161. package/dist/nest/metrics.bootstrap.service.d.ts +7 -3
  162. package/dist/nest/metrics.bootstrap.service.js +56 -21
  163. package/dist/nest/metrics.interceptor.d.ts +3 -3
  164. package/dist/nest/metrics.interceptor.js +11 -8
  165. package/dist/nest/metrics.module.d.ts +3 -0
  166. package/dist/nest/metrics.module.js +27 -9
  167. package/dist/runtime/index.d.ts +32 -0
  168. package/dist/runtime/index.js +104 -0
  169. package/dist/simulation/simulation.d.ts +5 -16
  170. package/dist/simulation/simulation.js +5 -8
  171. package/package.json +2 -1
  172. package/dashboard-out/_next/static/chunks/23soo6qkun-yv.js +0 -1
  173. package/dashboard-out/_next/static/chunks/3xoopocxi2vi8.css +0 -3
  174. package/dashboard-out/_next/static/chunks/3z-nzyp9z8vih.js +0 -3
  175. /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 17egwqgk36_DSRF55LJZG}/_buildManifest.js +0 -0
  176. /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 17egwqgk36_DSRF55LJZG}/_clientMiddlewareManifest.js +0 -0
  177. /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 17egwqgk36_DSRF55LJZG}/_ssgManifest.js +0 -0
@@ -5,35 +5,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.expressMetricsBootstrap = expressMetricsBootstrap;
7
7
  const metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
8
- const collector_service_1 = require("../core/telemetry/collector.service");
9
8
  const simulation_1 = require("../simulation/simulation");
10
9
  const delivery_1 = require("../core/delivery");
11
- const correlation_service_1 = require("../core/telemetry/correlation.service");
12
- const config_1 = require("../config");
13
10
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
14
- function expressMetricsBootstrap(server) {
15
- const config = (0, config_1.getConfig)();
11
+ const organizers_1 = require("../core/organizers");
12
+ const runtime_1 = require("../runtime");
13
+ let started = false;
14
+ function expressMetricsBootstrap(server, dependencies) {
15
+ if (started)
16
+ return async () => { };
17
+ started = true;
18
+ const config = dependencies.config;
16
19
  let simulator = null;
17
20
  if (config.simulation) {
18
- simulator = new simulation_1.TrafficSimulator();
19
- simulator.start({
20
- intervalMs: config.simulation.intervalMs,
21
- requestsPerTick: config.simulation.requestsPerTick,
22
- });
21
+ simulator = new simulation_1.TrafficSimulator(dependencies.storage);
22
+ simulator.start(config.simulation);
23
23
  }
24
- const websocket = new metrics_websocket_adapter_1.ExpressWebSocketAdapter(server, collector_service_1.collectorService);
24
+ const websocket = new metrics_websocket_adapter_1.ExpressWebSocketAdapter(server, dependencies.collector, dependencies.persistence, dependencies.correlation, dependencies.incidents, config);
25
25
  websocket.init();
26
- const publisher = new delivery_1.MetricsPublisher(collector_service_1.collectorService, websocket, config.publisher.intervalMs);
27
- publisher.start();
28
- const tickInterval = setInterval(() => {
29
- collector_service_1.collectorService.tick();
30
- correlation_service_1.correlationService.tick();
31
- }, config.tickIntervalMs);
26
+ const eventManager = new organizers_1.ApplicationEventManager(dependencies.persistence, config.applicationVersion);
27
+ eventManager.start();
28
+ const publisher = new delivery_1.MetricsPublisher(dependencies.collector, dependencies.persistence, dependencies.correlation, dependencies.incidents, websocket);
29
+ const intervalManager = new organizers_1.IntervalManager({
30
+ tick: () => { dependencies.collector.tick(); dependencies.correlation.tick(); dependencies.incidents.tick(); },
31
+ publisher: () => { publisher.publish(); },
32
+ persistence: () => { dependencies.persistence.archiveAllCategories(); }
33
+ }, config);
34
+ intervalManager.startIntervals();
32
35
  logger_1.default.debug('Metrics bootstrap initialized successfully.');
33
- return () => {
34
- simulator?.stop();
35
- publisher.stop();
36
- clearInterval(tickInterval);
37
- websocket.disconnect();
36
+ void organizers_1.ApplicationEventManager.instance?.emit({
37
+ type: 'STARTUP',
38
+ reason: 'Express metrics module initialized',
39
+ });
40
+ let stopping = null;
41
+ const stop = (options = {}) => {
42
+ if (stopping)
43
+ return stopping;
44
+ logger_1.default.debug('Metrics bootstrap shutdown initiated.');
45
+ stopping = (0, runtime_1.shutdownOptimaRuntime)(dependencies, {
46
+ stopIntake: () => {
47
+ simulator?.stop();
48
+ if (options.closeServer && server.listening)
49
+ server.close();
50
+ },
51
+ stopProducers: () => intervalManager.stopIntervals(),
52
+ emitShutdownEvent: async () => {
53
+ await organizers_1.ApplicationEventManager.instance?.emit({
54
+ type: 'SHUTDOWN',
55
+ reason: 'Express metrics module shutting down',
56
+ });
57
+ eventManager.stop();
58
+ },
59
+ closeTransport: () => websocket.disconnect(),
60
+ drainTimeoutMs: options.drainTimeoutMs,
61
+ }).finally(() => { started = false; });
62
+ return stopping;
38
63
  };
64
+ return stop;
39
65
  }
@@ -1,2 +1,3 @@
1
1
  import express from 'express';
2
- export declare function attachDashboard(app: express.Express, routePath?: string): void;
2
+ import type { PersistenceRepository } from '../core/storage';
3
+ export declare function attachDashboard(app: express.Express, routePath: string, persistence: PersistenceRepository): void;
@@ -8,13 +8,16 @@ const express_1 = __importDefault(require("express"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
11
- function attachDashboard(app, routePath = '/dashboard') {
11
+ const session_export_handler_1 = require("../adapters/session-export.handler");
12
+ function attachDashboard(app, routePath, persistence) {
12
13
  const dashboardDir = path_1.default.join(__dirname, '../../dashboard-out');
13
14
  const indexHtmlPath = path_1.default.join(dashboardDir, 'index.html');
14
15
  if (!fs_1.default.existsSync(indexHtmlPath)) {
15
16
  logger_1.default.error(`Dashboard not found at ${indexHtmlPath}. Please build the dashboard first.`);
16
17
  return;
17
18
  }
19
+ const exportSession = (0, session_export_handler_1.createSessionExportHandler)(persistence);
20
+ app.get((0, session_export_handler_1.sessionExportRoute)(routePath), (req, res) => { void exportSession(req, res); });
18
21
  app.use(routePath, express_1.default.static(dashboardDir));
19
22
  app.get(`${routePath}*`, (req, res) => {
20
23
  res.sendFile(indexHtmlPath);
@@ -1,2 +1,3 @@
1
1
  import type { RequestHandler } from 'express';
2
- export declare const expressMetricsMiddleware: RequestHandler;
2
+ import type { OptimaRuntimeDependencies } from '../runtime';
3
+ export declare const createExpressMetricsMiddleware: (dependencies: OptimaRuntimeDependencies) => RequestHandler;
@@ -3,27 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.expressMetricsMiddleware = void 0;
7
- const telemetry_service_1 = __importDefault(require("../core/telemetry/telemetry.service"));
6
+ exports.createExpressMetricsMiddleware = void 0;
8
7
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
9
8
  const metrics_adapter_1 = require("./metrics.adapter");
10
- const telemetryService = new telemetry_service_1.default();
11
9
  const adapter = new metrics_adapter_1.ExpressAdapter();
12
- const expressMetricsMiddleware = (req, res, next) => {
13
- const startHrTime = process.hrtime.bigint();
14
- res.on('finish', () => {
15
- const requestData = adapter.getRequest(req);
16
- const responseData = adapter.getResponse(res);
17
- const telemetryRequest = telemetryService.record({
18
- endpoint: requestData.endpoint,
19
- method: requestData.method,
20
- statusCode: responseData.statusCode,
21
- clientIp: requestData.clientIp
22
- }, startHrTime);
23
- if (telemetryRequest !== null) {
24
- logger_1.default.log(req, res, telemetryRequest.responseTime);
25
- }
26
- });
27
- next();
10
+ const createExpressMetricsMiddleware = (dependencies) => {
11
+ return (req, res, next) => {
12
+ const startHrTime = process.hrtime.bigint();
13
+ const done = dependencies.telemetry.track();
14
+ res.on('close', done);
15
+ res.on('finish', () => {
16
+ const requestData = adapter.getRequest(req);
17
+ const responseData = adapter.getResponse(res);
18
+ const telemetryRequest = dependencies.telemetry.record({
19
+ endpoint: requestData.endpoint,
20
+ method: requestData.method,
21
+ statusCode: responseData.statusCode,
22
+ clientIp: requestData.clientIp
23
+ }, startHrTime);
24
+ if (telemetryRequest !== null) {
25
+ logger_1.default.log(req, res, telemetryRequest.responseTime);
26
+ }
27
+ done();
28
+ });
29
+ next();
30
+ };
28
31
  };
29
- exports.expressMetricsMiddleware = expressMetricsMiddleware;
32
+ exports.createExpressMetricsMiddleware = createExpressMetricsMiddleware;
@@ -1,15 +1,31 @@
1
1
  import { OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
2
2
  import type { Socket } from 'socket.io';
3
3
  import type { WebSocketAdapter } from '../adapters/websocket.adapter';
4
+ import type { AnalyticsFilterSettings } from '../core/domain';
5
+ import type { OptimaRuntimeDependencies } from '../runtime';
4
6
  export declare class NestWebSocketAdapter implements WebSocketAdapter, OnGatewayConnection, OnGatewayDisconnect {
7
+ private readonly dependencies;
5
8
  private server;
9
+ constructor(dependencies: OptimaRuntimeDependencies);
6
10
  init(): void;
7
- handleConnection(socket: Socket): void;
11
+ handleConnection(socket: Socket): Promise<void>;
8
12
  handleDisconnect(socket: Socket): void;
13
+ handleSessionMetadata(socket: Socket): void;
14
+ handleSessionSummary(socket: Socket, payload: {
15
+ sessionNumber: number;
16
+ }): Promise<void>;
9
17
  handleSystemData(socket: Socket): void;
10
- handleDashboardData(socket: Socket): void;
11
- handleAnalyticsData(socket: Socket): void;
18
+ handleAnalyticsData(socket: Socket, payload: {
19
+ filters: AnalyticsFilterSettings;
20
+ }): void;
12
21
  handleHealthData(socket: Socket): void;
22
+ handleCorrelationData(socket: Socket): void;
23
+ handleConfiguration(socket: Socket): void;
24
+ handleIncidents(socket: Socket): void;
25
+ handleDashboardBuckets(socket: Socket, payload: unknown): Promise<void>;
26
+ handleCorrelationReplay(socket: Socket, payload: {
27
+ findingId: string;
28
+ }): Promise<void>;
13
29
  broadcast(event: string, data: unknown): void;
14
30
  disconnect(): void;
15
31
  }
@@ -18,33 +18,71 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.NestWebSocketAdapter = void 0;
19
19
  const websockets_1 = require("@nestjs/websockets");
20
20
  const delivery_1 = require("../core/delivery");
21
- const collector_service_1 = require("../core/telemetry/collector.service");
22
21
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
22
+ const common_1 = require("@nestjs/common");
23
+ const config_1 = require("../config");
24
+ const socket_options_1 = require("../adapters/socket.options");
23
25
  let NestWebSocketAdapter = class NestWebSocketAdapter {
26
+ dependencies;
24
27
  server;
28
+ constructor(dependencies) {
29
+ this.dependencies = dependencies;
30
+ }
25
31
  init() { }
26
- handleConnection(socket) {
32
+ async handleConnection(socket) {
27
33
  logger_1.default.debug('Dashboard client connected.', socket.id);
34
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_SESSION_METADATA, await this.dependencies.persistence.getSessionManifest());
28
35
  }
29
36
  handleDisconnect(socket) {
30
37
  logger_1.default.debug('Dashboard client disconnected.', socket.id);
31
38
  }
32
- handleSystemData(socket) {
33
- socket.emit(delivery_1.WebSocketEvents.RESPONSE_SYSTEM_DATA, collector_service_1.collectorService.getSystemStaticInfo());
39
+ handleSessionMetadata(socket) {
40
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_SESSION_METADATA, this.dependencies.persistence.getSessionManifest());
34
41
  }
35
- handleDashboardData(socket) {
36
- socket.emit(delivery_1.WebSocketEvents.RESPONSE_DASHBOARD_DATA, collector_service_1.collectorService.getDashboardData());
42
+ async handleSessionSummary(socket, payload) {
43
+ const sessionNumber = Number(payload?.sessionNumber);
44
+ const summary = await this.dependencies.persistence.getSessionSummary(sessionNumber);
45
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_SESSION_SUMMARY, summary);
37
46
  }
38
- handleAnalyticsData(socket) {
39
- socket.emit(delivery_1.WebSocketEvents.RESPONSE_ANALYTICS_DATA, collector_service_1.collectorService.getAnalyticsData());
47
+ handleSystemData(socket) {
48
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_SYSTEM_DATA, this.dependencies.collector.getSystemStaticInfo());
49
+ }
50
+ handleAnalyticsData(socket, payload) {
51
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_ANALYTICS_DATA, this.dependencies.collector.getAnalyticsData(payload?.filters ?? undefined));
40
52
  }
41
53
  handleHealthData(socket) {
42
- socket.emit(delivery_1.WebSocketEvents.RESPONSE_HEALTH_DATA, collector_service_1.collectorService.getHealthData());
54
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_HEALTH_DATA, this.dependencies.collector.getHealthData());
55
+ }
56
+ handleCorrelationData(socket) {
57
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_CORRELATION_DATA, this.dependencies.correlation.pack());
58
+ }
59
+ handleConfiguration(socket) {
60
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_CONFIGURATION, (0, config_1.toClientConfig)(this.dependencies.config));
61
+ }
62
+ handleIncidents(socket) {
63
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_INCIDENTS, this.dependencies.incidents.snapshot());
64
+ }
65
+ async handleDashboardBuckets(socket, payload) {
66
+ const req = (0, delivery_1.parseBucketsRequest)(payload);
67
+ if (!req)
68
+ return;
69
+ try {
70
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_DASHBOARD_BUCKETS, await this.dependencies.dashboard.getBackFill(req));
71
+ }
72
+ catch (err) {
73
+ logger_1.default.error('Dashboard backfill failed:', err);
74
+ }
75
+ }
76
+ async handleCorrelationReplay(socket, payload) {
77
+ const findingId = String(payload?.findingId);
78
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_CORRELATION_REPLAY, { findingId, outcome: await this.dependencies.correlation.replay(findingId) });
43
79
  }
44
80
  broadcast(event, data) {
45
81
  this.server.emit(event, data);
46
82
  }
47
83
  disconnect() {
84
+ if (!this.server)
85
+ return;
48
86
  this.server?.disconnectSockets(true);
49
87
  }
50
88
  };
@@ -54,24 +92,33 @@ __decorate([
54
92
  __metadata("design:type", Function)
55
93
  ], NestWebSocketAdapter.prototype, "server", void 0);
56
94
  __decorate([
57
- (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_SYSTEM_DATA),
95
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_SESSION_METADATA),
58
96
  __param(0, (0, websockets_1.ConnectedSocket)()),
59
97
  __metadata("design:type", Function),
60
98
  __metadata("design:paramtypes", [Function]),
61
99
  __metadata("design:returntype", void 0)
62
- ], NestWebSocketAdapter.prototype, "handleSystemData", null);
100
+ ], NestWebSocketAdapter.prototype, "handleSessionMetadata", null);
63
101
  __decorate([
64
- (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_DASHBOARD_DATA),
102
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_SESSION_SUMMARY),
103
+ __param(0, (0, websockets_1.ConnectedSocket)()),
104
+ __param(1, (0, websockets_1.MessageBody)()),
105
+ __metadata("design:type", Function),
106
+ __metadata("design:paramtypes", [Function, Object]),
107
+ __metadata("design:returntype", Promise)
108
+ ], NestWebSocketAdapter.prototype, "handleSessionSummary", null);
109
+ __decorate([
110
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_SYSTEM_DATA),
65
111
  __param(0, (0, websockets_1.ConnectedSocket)()),
66
112
  __metadata("design:type", Function),
67
113
  __metadata("design:paramtypes", [Function]),
68
114
  __metadata("design:returntype", void 0)
69
- ], NestWebSocketAdapter.prototype, "handleDashboardData", null);
115
+ ], NestWebSocketAdapter.prototype, "handleSystemData", null);
70
116
  __decorate([
71
117
  (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_ANALYTICS_DATA),
72
118
  __param(0, (0, websockets_1.ConnectedSocket)()),
119
+ __param(1, (0, websockets_1.MessageBody)()),
73
120
  __metadata("design:type", Function),
74
- __metadata("design:paramtypes", [Function]),
121
+ __metadata("design:paramtypes", [Function, Object]),
75
122
  __metadata("design:returntype", void 0)
76
123
  ], NestWebSocketAdapter.prototype, "handleAnalyticsData", null);
77
124
  __decorate([
@@ -81,12 +128,45 @@ __decorate([
81
128
  __metadata("design:paramtypes", [Function]),
82
129
  __metadata("design:returntype", void 0)
83
130
  ], NestWebSocketAdapter.prototype, "handleHealthData", null);
131
+ __decorate([
132
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_CORRELATION_DATA),
133
+ __param(0, (0, websockets_1.ConnectedSocket)()),
134
+ __metadata("design:type", Function),
135
+ __metadata("design:paramtypes", [Function]),
136
+ __metadata("design:returntype", void 0)
137
+ ], NestWebSocketAdapter.prototype, "handleCorrelationData", null);
138
+ __decorate([
139
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_CONFIGURATION),
140
+ __param(0, (0, websockets_1.ConnectedSocket)()),
141
+ __metadata("design:type", Function),
142
+ __metadata("design:paramtypes", [Function]),
143
+ __metadata("design:returntype", void 0)
144
+ ], NestWebSocketAdapter.prototype, "handleConfiguration", null);
145
+ __decorate([
146
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_INCIDENTS),
147
+ __param(0, (0, websockets_1.ConnectedSocket)()),
148
+ __metadata("design:type", Function),
149
+ __metadata("design:paramtypes", [Function]),
150
+ __metadata("design:returntype", void 0)
151
+ ], NestWebSocketAdapter.prototype, "handleIncidents", null);
152
+ __decorate([
153
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_DASHBOARD_BUCKETS),
154
+ __param(0, (0, websockets_1.ConnectedSocket)()),
155
+ __param(1, (0, websockets_1.MessageBody)()),
156
+ __metadata("design:type", Function),
157
+ __metadata("design:paramtypes", [Function, Object]),
158
+ __metadata("design:returntype", Promise)
159
+ ], NestWebSocketAdapter.prototype, "handleDashboardBuckets", null);
160
+ __decorate([
161
+ (0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_CORRELATION_REPLAY),
162
+ __param(0, (0, websockets_1.ConnectedSocket)()),
163
+ __param(1, (0, websockets_1.MessageBody)()),
164
+ __metadata("design:type", Function),
165
+ __metadata("design:paramtypes", [Function, Object]),
166
+ __metadata("design:returntype", Promise)
167
+ ], NestWebSocketAdapter.prototype, "handleCorrelationReplay", null);
84
168
  exports.NestWebSocketAdapter = NestWebSocketAdapter = __decorate([
85
- (0, websockets_1.WebSocketGateway)({
86
- transports: ['websocket'],
87
- cors: {
88
- origin: '*',
89
- methods: ['GET', 'POST'],
90
- },
91
- })
169
+ (0, websockets_1.WebSocketGateway)((0, socket_options_1.socketServerOptions)(config_1.DEFAULT_CONFIG.transport)),
170
+ __param(0, (0, common_1.Inject)('OPTIMA_RUNTIME_DEPENDENCIES')),
171
+ __metadata("design:paramtypes", [Object])
92
172
  ], NestWebSocketAdapter);
@@ -1,9 +1,12 @@
1
1
  import type { ExecutionContext } from '@nestjs/common';
2
2
  import type { HttpAdapter } from '../adapters/http.adapter';
3
3
  export declare class NestAdapter implements HttpAdapter<ExecutionContext, ExecutionContext> {
4
+ private getEndpoint;
5
+ private normalizePath;
6
+ private joinPaths;
4
7
  getRequest(context: ExecutionContext): {
5
8
  method: any;
6
- endpoint: any;
9
+ endpoint: string;
7
10
  clientIp: any;
8
11
  };
9
12
  getResponse(context: ExecutionContext): {
@@ -1,7 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NestAdapter = void 0;
4
+ const constants_1 = require("@nestjs/common/constants");
4
5
  class NestAdapter {
6
+ getEndpoint(context) {
7
+ const controller = context.getClass();
8
+ const handler = context.getHandler();
9
+ const controllerPath = Reflect.getMetadata(constants_1.PATH_METADATA, controller);
10
+ const handlerPath = Reflect.getMetadata(constants_1.PATH_METADATA, handler);
11
+ const controllerRoute = this.normalizePath(controllerPath);
12
+ const route = this.normalizePath(handlerPath);
13
+ return this.joinPaths(controllerRoute, route);
14
+ }
15
+ normalizePath(path) {
16
+ if (!path) {
17
+ return '';
18
+ }
19
+ if (Array.isArray(path)) {
20
+ return path[0] ?? '';
21
+ }
22
+ return path;
23
+ }
24
+ joinPaths(...paths) {
25
+ const result = paths.filter(Boolean).join('/');
26
+ return result.startsWith('/') ? result : `/${result}`;
27
+ }
5
28
  getRequest(context) {
6
29
  const request = context.switchToHttp().getRequest();
7
30
  const { body, // Parsed JSON or form data
@@ -17,7 +40,7 @@ class NestAdapter {
17
40
  } = request;
18
41
  return {
19
42
  method,
20
- endpoint: path,
43
+ endpoint: this.getEndpoint(context),
21
44
  clientIp: ip,
22
45
  };
23
46
  }
@@ -1,13 +1,17 @@
1
1
  import { OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
2
2
  import { NestWebSocketAdapter } from './metrics-websocket.adapter';
3
3
  import { type ReadonlyConfig } from '../config';
4
+ import { type OptimaRuntimeDependencies } from '../runtime';
4
5
  export declare class MetricsBootstrapService implements OnApplicationBootstrap, OnApplicationShutdown {
5
6
  private readonly websocket;
6
7
  private readonly config;
8
+ private readonly dependencies;
9
+ private started;
7
10
  private simulator;
8
11
  private publisher;
9
- private tickInterval;
10
- constructor(websocket: NestWebSocketAdapter, config: ReadonlyConfig);
12
+ private intervalManager;
13
+ private eventManager;
14
+ constructor(websocket: NestWebSocketAdapter, config: ReadonlyConfig, dependencies: OptimaRuntimeDependencies);
11
15
  onApplicationBootstrap(): void;
12
- onApplicationShutdown(): void;
16
+ onApplicationShutdown(): Promise<void>;
13
17
  }
@@ -17,54 +17,89 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.MetricsBootstrapService = void 0;
19
19
  const common_1 = require("@nestjs/common");
20
- const collector_service_1 = require("../core/telemetry/collector.service");
21
- const correlation_service_1 = require("../core/telemetry/correlation.service");
22
20
  const delivery_1 = require("../core/delivery");
23
21
  const simulation_1 = require("../simulation/simulation");
24
22
  const metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
25
23
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
24
+ const organizers_1 = require("../core/organizers");
25
+ const runtime_1 = require("../runtime");
26
26
  let MetricsBootstrapService = class MetricsBootstrapService {
27
27
  websocket;
28
28
  config;
29
+ dependencies;
30
+ started = false;
29
31
  simulator = null;
30
32
  publisher = null;
31
- tickInterval = null;
32
- constructor(websocket, config) {
33
+ intervalManager = null;
34
+ eventManager = null;
35
+ constructor(websocket, config, dependencies) {
33
36
  this.websocket = websocket;
34
37
  this.config = config;
38
+ this.dependencies = dependencies;
35
39
  }
36
40
  onApplicationBootstrap() {
41
+ if (this.started) {
42
+ return;
43
+ }
44
+ this.started = true;
45
+ if (!this.dependencies) {
46
+ logger_1.default.error('Failed to create Optima runtime dependencies.');
47
+ return;
48
+ }
37
49
  const simulationConfig = this.config.simulation === false
38
50
  ? null
39
51
  : this.config.simulation;
40
52
  if (simulationConfig) {
41
- this.simulator = new simulation_1.TrafficSimulator();
53
+ this.simulator = new simulation_1.TrafficSimulator(this.dependencies.storage);
42
54
  this.simulator.start(simulationConfig);
43
55
  }
44
56
  this.websocket.init();
45
- this.publisher = new delivery_1.MetricsPublisher(collector_service_1.collectorService, this.websocket, this.config.publisher.intervalMs);
46
- this.publisher.start();
47
- this.tickInterval = setInterval(() => {
48
- collector_service_1.collectorService.tick();
49
- correlation_service_1.correlationService.tick();
50
- }, this.config.tickIntervalMs);
57
+ this.eventManager = new organizers_1.ApplicationEventManager(this.dependencies.persistence, this.config.applicationVersion);
58
+ this.eventManager.start();
59
+ this.publisher = new delivery_1.MetricsPublisher(this.dependencies.collector, this.dependencies.persistence, this.dependencies.correlation, this.dependencies.incidents, this.websocket);
60
+ this.intervalManager = new organizers_1.IntervalManager({
61
+ tick: () => { this.dependencies.collector.tick(); this.dependencies.correlation.tick(); this.dependencies.incidents.tick(); },
62
+ publisher: () => { this.publisher?.publish(); },
63
+ persistence: () => { this.dependencies.persistence.archiveAllCategories(); }
64
+ }, this.config);
65
+ this.intervalManager.startIntervals();
51
66
  logger_1.default.debug('Nest metrics bootstrap initialized.');
67
+ void organizers_1.ApplicationEventManager.instance?.emit({
68
+ type: 'STARTUP',
69
+ reason: 'Nest metrics module initialized',
70
+ });
52
71
  }
53
- onApplicationShutdown() {
54
- this.simulator?.stop();
55
- this.simulator = null;
56
- this.publisher?.stop();
57
- this.publisher = null;
58
- if (this.tickInterval) {
59
- clearInterval(this.tickInterval);
60
- this.tickInterval = null;
72
+ async onApplicationShutdown() {
73
+ if (!this.started) {
74
+ return;
61
75
  }
62
- this.websocket.disconnect();
76
+ this.started = false;
77
+ await (0, runtime_1.shutdownOptimaRuntime)(this.dependencies, {
78
+ stopIntake: () => {
79
+ this.simulator?.stop();
80
+ this.simulator = null;
81
+ },
82
+ stopProducers: () => {
83
+ this.intervalManager?.stopIntervals();
84
+ this.intervalManager = null;
85
+ this.publisher = null;
86
+ },
87
+ emitShutdownEvent: async () => {
88
+ await organizers_1.ApplicationEventManager.instance?.emit({
89
+ type: 'SHUTDOWN',
90
+ reason: 'Nest metrics module shutting down',
91
+ });
92
+ this.eventManager?.stop();
93
+ this.eventManager = null;
94
+ },
95
+ closeTransport: () => this.websocket.disconnect(),
96
+ });
63
97
  }
64
98
  };
65
99
  exports.MetricsBootstrapService = MetricsBootstrapService;
66
100
  exports.MetricsBootstrapService = MetricsBootstrapService = __decorate([
67
101
  (0, common_1.Injectable)(),
68
102
  __param(1, (0, common_1.Inject)('METRICS_CONFIG')),
69
- __metadata("design:paramtypes", [metrics_websocket_adapter_1.NestWebSocketAdapter, Object])
103
+ __param(2, (0, common_1.Inject)('OPTIMA_RUNTIME_DEPENDENCIES')),
104
+ __metadata("design:paramtypes", [metrics_websocket_adapter_1.NestWebSocketAdapter, Object, Object])
70
105
  ], MetricsBootstrapService);
@@ -1,11 +1,11 @@
1
1
  import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
2
2
  import { Observable } from 'rxjs';
3
- import TelemetryService from '../core/telemetry/telemetry.service';
4
3
  import { NestAdapter } from './metrics.adapter';
4
+ import type { OptimaRuntimeDependencies } from '../runtime';
5
5
  export declare class MetricsInterceptor implements NestInterceptor {
6
6
  private readonly adapter;
7
- private readonly telemetryService;
8
- constructor(adapter: NestAdapter, telemetryService: TelemetryService);
7
+ private readonly dependencies;
8
+ constructor(adapter: NestAdapter, dependencies: OptimaRuntimeDependencies);
9
9
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
10
10
  private record;
11
11
  }
@@ -8,6 +8,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
11
14
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
15
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
16
  };
@@ -15,30 +18,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
18
  exports.MetricsInterceptor = void 0;
16
19
  const common_1 = require("@nestjs/common");
17
20
  const operators_1 = require("rxjs/operators");
18
- const telemetry_service_1 = __importDefault(require("../core/telemetry/telemetry.service"));
19
21
  const metrics_adapter_1 = require("./metrics.adapter");
20
22
  const logger_1 = __importDefault(require("../core/telemetry/logger"));
21
23
  let MetricsInterceptor = class MetricsInterceptor {
22
24
  adapter;
23
- telemetryService;
24
- constructor(adapter, telemetryService) {
25
+ dependencies;
26
+ constructor(adapter, dependencies) {
25
27
  this.adapter = adapter;
26
- this.telemetryService = telemetryService;
28
+ this.dependencies = dependencies;
27
29
  }
28
30
  intercept(context, next) {
29
31
  if (context.getType() !== 'http') {
30
32
  return next.handle();
31
33
  }
32
34
  const startHrTime = process.hrtime.bigint();
35
+ const done = this.dependencies.telemetry.track();
33
36
  return next.handle().pipe((0, operators_1.tap)({
34
37
  next: () => this.record(context, startHrTime),
35
38
  error: () => this.record(context, startHrTime),
36
- }));
39
+ }), (0, operators_1.finalize)(done));
37
40
  }
38
41
  record(context, startHrTime) {
39
42
  const requestData = this.adapter.getRequest(context);
40
43
  const responseData = this.adapter.getResponse(context);
41
- const telemetryRequest = this.telemetryService.record({
44
+ const telemetryRequest = this.dependencies.telemetry.record({
42
45
  endpoint: requestData.endpoint,
43
46
  method: requestData.method,
44
47
  statusCode: responseData.statusCode,
@@ -52,6 +55,6 @@ let MetricsInterceptor = class MetricsInterceptor {
52
55
  exports.MetricsInterceptor = MetricsInterceptor;
53
56
  exports.MetricsInterceptor = MetricsInterceptor = __decorate([
54
57
  (0, common_1.Injectable)(),
55
- __metadata("design:paramtypes", [metrics_adapter_1.NestAdapter,
56
- telemetry_service_1.default])
58
+ __param(1, (0, common_1.Inject)('OPTIMA_RUNTIME_DEPENDENCIES')),
59
+ __metadata("design:paramtypes", [metrics_adapter_1.NestAdapter, Object])
57
60
  ], MetricsInterceptor);
@@ -1,6 +1,9 @@
1
1
  import { DynamicModule, NestModule, MiddlewareConsumer } from "@nestjs/common";
2
2
  import { ConfigOptions } from '../config';
3
+ import { type OptimaRuntimeDependencies } from '../runtime';
3
4
  export declare class MetricsModule implements NestModule {
5
+ private readonly dependencies;
6
+ constructor(dependencies: OptimaRuntimeDependencies);
4
7
  static forRoot(options?: ConfigOptions): DynamicModule;
5
8
  configure(consumer: MiddlewareConsumer): void;
6
9
  }