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
@@ -1,12 +1,89 @@
1
- import { ConfigOptions, ReadonlyConfig } from './config.types';
1
+ import type { ClientConfig, ConfigOptions, ReadonlyConfig } from './config.types';
2
+ export declare const DEFAULT_CONFIG: {
3
+ readonly applicationVersion: "1.0.0";
4
+ readonly logging: {
5
+ readonly consoleLog: true;
6
+ };
7
+ readonly collection: {
8
+ readonly excludePaths: readonly string[];
9
+ readonly includeDefaultExcludes: true;
10
+ readonly bucketIntervalMs: 1000;
11
+ readonly maxEndpointsPerBucket: 200;
12
+ readonly eventLoopResolutionMs: 20;
13
+ };
14
+ readonly thresholds: {
15
+ readonly slowLatencyMs: 500;
16
+ readonly eventLoopLagMs: 100;
17
+ };
18
+ readonly cache: {
19
+ readonly liveBuckets: 300;
20
+ readonly viewWindowBuckets: 60;
21
+ };
22
+ readonly persistence: {
23
+ readonly baseDir: "./metrics_data";
24
+ readonly persistRawRequests: true;
25
+ readonly maxBufferSize: 1000;
26
+ readonly archiveIntervalMs: number;
27
+ readonly heartbeatIntervalMs: 30000;
28
+ readonly shutdownDrainTimeoutMs: 5000;
29
+ readonly writer: {
30
+ readonly maxQueue: 1000;
31
+ readonly maxRetries: 3;
32
+ readonly retryDelayMs: 100;
33
+ };
34
+ };
35
+ readonly incidents: {
36
+ readonly windowIntervals: 60;
37
+ readonly minRequests: 100;
38
+ readonly serverErrorRate: 0.05;
39
+ readonly recoveryRatio: 0.5;
40
+ readonly pendingForMs: 30000;
41
+ readonly recoveryForMs: 60000;
42
+ readonly resolvedHoldMs: 30000;
43
+ readonly historySize: 100;
44
+ };
45
+ readonly correlation: {
46
+ readonly minCorrelation: 0.5;
47
+ readonly alpha: 0.05;
48
+ readonly power: 0.8;
49
+ readonly strongThreshold: 0.7;
50
+ readonly maxLag: 10;
51
+ readonly maxWindow: 60;
52
+ readonly minCoverage: 0.5;
53
+ readonly evaluateEveryIntervals: 10;
54
+ };
55
+ readonly dashboard: {
56
+ readonly path: "/optima-metrics";
57
+ readonly liveWindow: 60;
58
+ readonly backfillLimit: 1000;
59
+ readonly maxBackfillAgeMs: number;
60
+ readonly topImpactRoutes: 10;
61
+ readonly analyticsPageSize: 50;
62
+ readonly sessionSummaryWindowHours: 24;
63
+ };
64
+ readonly transport: {
65
+ readonly socketPath: "/socket.io/";
66
+ readonly cors: string | boolean;
67
+ readonly pingTimeoutMs: 5000;
68
+ readonly maxHttpBufferSize: number;
69
+ };
70
+ readonly publisher: {
71
+ readonly intervalMs: 1000;
72
+ };
73
+ readonly tickIntervalMs: 250;
74
+ readonly simulation: {
75
+ readonly intervalMs: 100;
76
+ readonly requestsPerTick: 20;
77
+ };
78
+ };
79
+ export declare function toClientConfig(config: ReadonlyConfig): ClientConfig;
2
80
  export declare class ConfigManager {
3
81
  private static instance;
4
82
  private config;
5
- private readonly defaultConfig;
83
+ private initialized;
6
84
  private constructor();
7
85
  static getInstance(): ConfigManager;
8
86
  initialize(userOptions?: ConfigOptions): ReadonlyConfig;
9
87
  get(): ReadonlyConfig;
10
- private validateAndSanitize;
11
88
  }
12
89
  export declare const getConfig: () => ReadonlyConfig;
@@ -1,41 +1,269 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getConfig = exports.ConfigManager = void 0;
4
- class ConfigManager {
5
- static instance;
6
- config;
7
- defaultConfig = Object.freeze({
8
- dashboardPath: '/optima-metrics',
9
- simulation: {
10
- intervalMs: 100,
11
- requestsPerTick: 20,
6
+ exports.getConfig = exports.ConfigManager = exports.DEFAULT_CONFIG = void 0;
7
+ exports.toClientConfig = toClientConfig;
8
+ const logger_1 = __importDefault(require("../core/telemetry/logger"));
9
+ const DEFAULT_EXCLUDE_PATHS = [
10
+ '/_next/**',
11
+ '**/*.map',
12
+ '**/*.js',
13
+ '**/*.css',
14
+ '/favicon.ico',
15
+ ];
16
+ exports.DEFAULT_CONFIG = {
17
+ applicationVersion: '1.0.0',
18
+ logging: { consoleLog: true },
19
+ collection: {
20
+ excludePaths: [],
21
+ includeDefaultExcludes: true,
22
+ bucketIntervalMs: 1000,
23
+ maxEndpointsPerBucket: 200,
24
+ eventLoopResolutionMs: 20,
25
+ },
26
+ thresholds: {
27
+ slowLatencyMs: 500,
28
+ eventLoopLagMs: 100
29
+ },
30
+ cache: {
31
+ liveBuckets: 300,
32
+ viewWindowBuckets: 60
33
+ },
34
+ persistence: {
35
+ baseDir: './metrics_data',
36
+ persistRawRequests: true,
37
+ maxBufferSize: 1000,
38
+ archiveIntervalMs: 24 * 60 * 60 * 1000,
39
+ heartbeatIntervalMs: 30000,
40
+ shutdownDrainTimeoutMs: 5000,
41
+ writer: {
42
+ maxQueue: 1000,
43
+ maxRetries: 3,
44
+ retryDelayMs: 100
45
+ }
46
+ },
47
+ incidents: {
48
+ windowIntervals: 60,
49
+ minRequests: 100,
50
+ serverErrorRate: 0.05,
51
+ recoveryRatio: 0.5,
52
+ pendingForMs: 30000,
53
+ recoveryForMs: 60000,
54
+ resolvedHoldMs: 30000,
55
+ historySize: 100
56
+ },
57
+ correlation: {
58
+ minCorrelation: 0.5,
59
+ alpha: 0.05,
60
+ power: 0.8,
61
+ strongThreshold: 0.7,
62
+ maxLag: 10,
63
+ maxWindow: 60,
64
+ minCoverage: 0.5,
65
+ evaluateEveryIntervals: 10
66
+ },
67
+ dashboard: {
68
+ path: '/optima-metrics',
69
+ liveWindow: 60,
70
+ backfillLimit: 1000,
71
+ maxBackfillAgeMs: 24 * 60 * 60 * 1000,
72
+ topImpactRoutes: 10,
73
+ analyticsPageSize: 50,
74
+ sessionSummaryWindowHours: 24
75
+ },
76
+ transport: {
77
+ socketPath: '/socket.io/',
78
+ cors: '*',
79
+ pingTimeoutMs: 5000,
80
+ maxHttpBufferSize: 1 * 1024 * 1024
81
+ },
82
+ publisher: {
83
+ intervalMs: 1000
84
+ },
85
+ tickIntervalMs: 250,
86
+ simulation: {
87
+ intervalMs: 100,
88
+ requestsPerTick: 20
89
+ },
90
+ };
91
+ function num(value, fallback, min, max = Number.POSITIVE_INFINITY) {
92
+ if (typeof value !== 'number' || Number.isNaN(value)) {
93
+ return fallback;
94
+ }
95
+ return Math.min(Math.max(value, min), max);
96
+ }
97
+ function bool(value, fallback) {
98
+ if (typeof value !== 'boolean') {
99
+ return fallback;
100
+ }
101
+ return value;
102
+ }
103
+ function str(value, fallback) {
104
+ if (typeof value !== 'string' || value.length === 0) {
105
+ return fallback;
106
+ }
107
+ return value;
108
+ }
109
+ function enabled(value, enabledByDefault) {
110
+ if (value === undefined)
111
+ return enabledByDefault ? {} : false;
112
+ if (value === false)
113
+ return false;
114
+ if (value === true)
115
+ return {};
116
+ if (typeof value === 'object' && value !== null)
117
+ return value;
118
+ return enabledByDefault ? {} : false;
119
+ }
120
+ function normalizePath(path) {
121
+ const withSlash = path.startsWith('/') ? path : `/${path}`;
122
+ return withSlash.length > 1 ? withSlash.replace(/\/+$/, '') : withSlash;
123
+ }
124
+ function deepFreeze(value) {
125
+ if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
126
+ Object.freeze(value);
127
+ for (const v of Object.values(value))
128
+ deepFreeze(v);
129
+ }
130
+ return value;
131
+ }
132
+ function resolve(o = {}) {
133
+ const d = exports.DEFAULT_CONFIG;
134
+ const dashboardOptions = enabled(o.dashboard, true);
135
+ const dashboard = dashboardOptions === false ? false : {
136
+ path: normalizePath(str(dashboardOptions.path, d.dashboard.path)),
137
+ liveWindow: num(dashboardOptions.liveWindow, d.dashboard.liveWindow, 1),
138
+ backfillLimit: num(dashboardOptions.backfillLimit, d.dashboard.backfillLimit, 1),
139
+ maxBackfillAgeMs: num(dashboardOptions.maxBackfillAgeMs, d.dashboard.maxBackfillAgeMs, 1),
140
+ topImpactRoutes: num(dashboardOptions.topImpactRoutes, d.dashboard.topImpactRoutes, 1),
141
+ analyticsPageSize: num(dashboardOptions.analyticsPageSize, d.dashboard.analyticsPageSize, 1),
142
+ sessionSummaryWindowHours: num(dashboardOptions.sessionSummaryWindowHours, d.dashboard.sessionSummaryWindowHours, 1),
143
+ };
144
+ const collection = o.collection ?? {};
145
+ const includeDefaultExcludes = bool(collection.includeDefaultExcludes, d.collection.includeDefaultExcludes);
146
+ const userExcludes = Array.isArray(collection.excludePaths)
147
+ ? collection.excludePaths.filter((p) => typeof p === 'string' && p.length > 0)
148
+ : [...d.collection.excludePaths];
149
+ const excludePaths = [...new Set([
150
+ ...(includeDefaultExcludes ? DEFAULT_EXCLUDE_PATHS : []),
151
+ ...(dashboard !== false ? [dashboard.path, `${dashboard.path}/**`] : []),
152
+ ...userExcludes,
153
+ ])];
154
+ const persistenceOptions = enabled(o.persistence, true);
155
+ const writer = persistenceOptions === false ? undefined : persistenceOptions.writer ?? {};
156
+ const persistence = persistenceOptions === false ? false : {
157
+ baseDir: str(persistenceOptions.baseDir, d.persistence.baseDir),
158
+ persistRawRequests: bool(persistenceOptions.persistRawRequests, d.persistence.persistRawRequests),
159
+ maxBufferSize: num(persistenceOptions.maxBufferSize, d.persistence.maxBufferSize, 1),
160
+ archiveIntervalMs: num(persistenceOptions.archiveIntervalMs, d.persistence.archiveIntervalMs, 1000),
161
+ heartbeatIntervalMs: num(persistenceOptions.heartbeatIntervalMs, d.persistence.heartbeatIntervalMs, 1000),
162
+ shutdownDrainTimeoutMs: num(persistenceOptions.shutdownDrainTimeoutMs, d.persistence.shutdownDrainTimeoutMs, 0),
163
+ writer: {
164
+ maxQueue: num(writer?.maxQueue, d.persistence.writer.maxQueue, 1),
165
+ maxRetries: num(writer?.maxRetries, d.persistence.writer.maxRetries, 0),
166
+ retryDelayMs: num(writer?.retryDelayMs, d.persistence.writer.retryDelayMs, 1),
167
+ },
168
+ };
169
+ const simulationOptions = enabled(o.simulation, false);
170
+ const simulation = simulationOptions === false ? false : {
171
+ intervalMs: num(simulationOptions.intervalMs, d.simulation.intervalMs, 1),
172
+ requestsPerTick: num(simulationOptions.requestsPerTick, d.simulation.requestsPerTick, 1),
173
+ };
174
+ const thresholds = o.thresholds ?? {};
175
+ const cache = o.cache ?? {};
176
+ const incidents = o.incidents ?? {};
177
+ const correlation = o.correlation ?? {};
178
+ const transport = o.transport ?? {};
179
+ const viewWindowBuckets = num(cache.viewWindowBuckets, d.cache.viewWindowBuckets, 1);
180
+ const correlationMaxWindow = num(correlation.maxWindow, d.correlation.maxWindow, 1);
181
+ const incidentWindow = num(incidents.windowIntervals, d.incidents.windowIntervals, 1);
182
+ return {
183
+ applicationVersion: str(o.applicationVersion, d.applicationVersion),
184
+ logging: {
185
+ consoleLog: bool(o.logging?.consoleLog, d.logging.consoleLog),
186
+ },
187
+ collection: {
188
+ excludePaths,
189
+ includeDefaultExcludes,
190
+ bucketIntervalMs: num(collection.bucketIntervalMs, d.collection.bucketIntervalMs, 100),
191
+ maxEndpointsPerBucket: num(collection.maxEndpointsPerBucket, d.collection.maxEndpointsPerBucket, 1),
192
+ eventLoopResolutionMs: num(collection.eventLoopResolutionMs, d.collection.eventLoopResolutionMs, 1),
193
+ },
194
+ thresholds: {
195
+ slowLatencyMs: num(thresholds.slowLatencyMs, d.thresholds.slowLatencyMs, 1),
196
+ eventLoopLagMs: num(thresholds.eventLoopLagMs, d.thresholds.eventLoopLagMs, 1),
197
+ },
198
+ cache: {
199
+ liveBuckets: Math.max(num(cache.liveBuckets, d.cache.liveBuckets, 1), viewWindowBuckets, correlationMaxWindow, incidentWindow),
200
+ viewWindowBuckets,
201
+ },
202
+ persistence,
203
+ incidents: {
204
+ windowIntervals: incidentWindow,
205
+ minRequests: num(incidents.minRequests, d.incidents.minRequests, 1),
206
+ serverErrorRate: num(incidents.serverErrorRate, d.incidents.serverErrorRate, 0, 1),
207
+ recoveryRatio: num(incidents.recoveryRatio, d.incidents.recoveryRatio, 0, 1),
208
+ pendingForMs: num(incidents.pendingForMs, d.incidents.pendingForMs, 0),
209
+ recoveryForMs: num(incidents.recoveryForMs, d.incidents.recoveryForMs, 0),
210
+ resolvedHoldMs: num(incidents.resolvedHoldMs, d.incidents.resolvedHoldMs, 0),
211
+ historySize: num(incidents.historySize, d.incidents.historySize, 1),
212
+ },
213
+ correlation: {
214
+ minCorrelation: num(correlation.minCorrelation, d.correlation.minCorrelation, 0.01, 0.99),
215
+ alpha: num(correlation.alpha, d.correlation.alpha, 0.0001, 0.5),
216
+ power: num(correlation.power, d.correlation.power, 0.5, 0.9999),
217
+ strongThreshold: num(correlation.strongThreshold, d.correlation.strongThreshold, 0, 1),
218
+ maxLag: num(correlation.maxLag, d.correlation.maxLag, 0),
219
+ maxWindow: correlationMaxWindow,
220
+ minCoverage: num(correlation.minCoverage, d.correlation.minCoverage, 0, 1),
221
+ evaluateEveryIntervals: num(correlation.evaluateEveryIntervals, d.correlation.evaluateEveryIntervals, 1),
222
+ },
223
+ dashboard,
224
+ transport: {
225
+ socketPath: normalizePath(str(transport.socketPath, d.transport.socketPath)) + '/',
226
+ cors: typeof transport.cors === 'string' || typeof transport.cors === 'boolean' ? transport.cors : d.transport.cors,
227
+ pingTimeoutMs: num(transport.pingTimeoutMs, d.transport.pingTimeoutMs, 1000),
228
+ maxHttpBufferSize: num(transport.maxHttpBufferSize, d.transport.maxHttpBufferSize, 1024),
12
229
  },
13
230
  publisher: {
14
- intervalMs: 1000,
15
- slowLatencyThresholdMs: 500,
16
- eventLoopLagThresholdMs: 100,
17
- eventLoopResolutionMs: 20,
231
+ intervalMs: num(o.publisher?.intervalMs, d.publisher.intervalMs, 100),
18
232
  },
19
- tickIntervalMs: 250,
20
- excludePaths: [
21
- '/_next/*',
22
- '/_next/**',
23
- '*.map',
24
- '*.js',
25
- '*.css',
26
- '/favicon.ico',
27
- '/metrics_pack',
28
- '/health',
29
- '/optima-metrics/**',
30
- '/optima-metrics/*',
31
- ], //! OPTIMIZE THIS
32
- consoleLog: true,
33
- ringBufferSize: 60,
34
- alertBufferSize: 100,
35
- });
36
- constructor() {
37
- this.config = this.defaultConfig;
38
- }
233
+ tickIntervalMs: num(o.tickIntervalMs, d.tickIntervalMs, 10),
234
+ simulation,
235
+ };
236
+ }
237
+ function toClientConfig(config) {
238
+ const persistence = config.persistence === false ? false : {
239
+ persistRawRequests: config.persistence.persistRawRequests,
240
+ maxBufferSize: config.persistence.maxBufferSize,
241
+ archiveIntervalMs: config.persistence.archiveIntervalMs,
242
+ heartbeatIntervalMs: config.persistence.heartbeatIntervalMs,
243
+ shutdownDrainTimeoutMs: config.persistence.shutdownDrainTimeoutMs,
244
+ };
245
+ return {
246
+ applicationVersion: config.applicationVersion,
247
+ collection: {
248
+ bucketIntervalMs: config.collection.bucketIntervalMs,
249
+ excludePaths: config.collection.excludePaths,
250
+ },
251
+ thresholds: config.thresholds,
252
+ cache: { viewWindowBuckets: config.cache.viewWindowBuckets },
253
+ persistence,
254
+ incidents: config.incidents,
255
+ correlation: config.correlation,
256
+ dashboard: config.dashboard,
257
+ publisher: config.publisher,
258
+ tickIntervalMs: config.tickIntervalMs,
259
+ simulation: config.simulation,
260
+ };
261
+ }
262
+ class ConfigManager {
263
+ static instance;
264
+ config = deepFreeze(resolve());
265
+ initialized = false;
266
+ constructor() { }
39
267
  static getInstance() {
40
268
  if (!ConfigManager.instance) {
41
269
  ConfigManager.instance = new ConfigManager();
@@ -43,67 +271,19 @@ class ConfigManager {
43
271
  return ConfigManager.instance;
44
272
  }
45
273
  initialize(userOptions) {
46
- const validated = this.validateAndSanitize(userOptions);
47
- this.config = Object.freeze({
48
- ...this.defaultConfig,
49
- ...validated
50
- });
274
+ if (this.initialized) {
275
+ if (userOptions !== undefined) {
276
+ logger_1.default.error('ConfigManager: already initialized, new options are ignored.');
277
+ }
278
+ return this.config;
279
+ }
280
+ this.config = deepFreeze(resolve(userOptions));
281
+ this.initialized = true;
51
282
  return this.config;
52
283
  }
53
284
  get() {
54
285
  return this.config;
55
286
  }
56
- validateAndSanitize(options) {
57
- if (!options) {
58
- return {};
59
- }
60
- const sanitized = {};
61
- if (options.dashboardPath !== undefined) {
62
- if (options.dashboardPath === false) {
63
- sanitized.dashboardPath = false;
64
- }
65
- else {
66
- sanitized.dashboardPath = String(options.dashboardPath);
67
- }
68
- }
69
- if (options.simulation !== undefined) {
70
- if (typeof options.simulation === 'boolean') {
71
- sanitized.simulation = options.simulation;
72
- }
73
- else {
74
- sanitized.simulation = {
75
- intervalMs: Math.max(1, options.simulation.intervalMs),
76
- requestsPerTick: Math.max(1, options.simulation.requestsPerTick),
77
- };
78
- }
79
- }
80
- if (options.publisher !== undefined) {
81
- sanitized.publisher = {
82
- intervalMs: Math.max(1, options.publisher.intervalMs),
83
- slowLatencyThresholdMs: Math.max(1, options.publisher.slowLatencyThresholdMs),
84
- eventLoopLagThresholdMs: Math.max(1, options.publisher.eventLoopLagThresholdMs),
85
- eventLoopResolutionMs: options.publisher.eventLoopResolutionMs !== undefined
86
- ? Math.max(1, options.publisher.eventLoopResolutionMs)
87
- : undefined,
88
- };
89
- }
90
- if (options.tickIntervalMs !== undefined) {
91
- sanitized.tickIntervalMs = Math.max(1, options.tickIntervalMs);
92
- }
93
- if (Array.isArray(options.excludePaths)) {
94
- sanitized.excludePaths = options.excludePaths.filter(path => typeof path === 'string');
95
- }
96
- if (options.consoleLog !== undefined) {
97
- sanitized.consoleLog = Boolean(options.consoleLog);
98
- }
99
- if (options.ringBufferSize !== undefined) {
100
- sanitized.ringBufferSize = Math.max(1, options.ringBufferSize);
101
- }
102
- if (options.alertBufferSize !== undefined) {
103
- sanitized.alertBufferSize = Math.max(1, options.alertBufferSize);
104
- }
105
- return sanitized;
106
- }
107
287
  }
108
288
  exports.ConfigManager = ConfigManager;
109
289
  const getConfig = () => ConfigManager.getInstance().get();
@@ -1,19 +1,95 @@
1
1
  export interface ConfigOptions {
2
- dashboardPath?: string | false;
3
- simulation?: false | {
4
- intervalMs: number;
5
- requestsPerTick: number;
2
+ applicationVersion?: string;
3
+ logging?: {
4
+ consoleLog?: boolean;
6
5
  };
7
- publisher?: {
8
- intervalMs: number;
9
- slowLatencyThresholdMs: number;
10
- eventLoopLagThresholdMs: number;
6
+ collection?: {
7
+ excludePaths?: string[];
8
+ includeDefaultExcludes?: boolean;
9
+ bucketIntervalMs?: number;
10
+ maxEndpointsPerBucket?: number;
11
11
  eventLoopResolutionMs?: number;
12
12
  };
13
+ thresholds?: {
14
+ slowLatencyMs?: number;
15
+ eventLoopLagMs?: number;
16
+ };
17
+ cache?: {
18
+ liveBuckets?: number;
19
+ viewWindowBuckets?: number;
20
+ };
21
+ persistence?: false | {
22
+ baseDir?: string;
23
+ persistRawRequests?: boolean;
24
+ maxBufferSize?: number;
25
+ archiveIntervalMs?: number;
26
+ heartbeatIntervalMs?: number;
27
+ shutdownDrainTimeoutMs?: number;
28
+ writer?: {
29
+ maxQueue?: number;
30
+ maxRetries?: number;
31
+ retryDelayMs?: number;
32
+ };
33
+ };
34
+ incidents?: {
35
+ windowIntervals?: number;
36
+ minRequests?: number;
37
+ serverErrorRate?: number;
38
+ recoveryRatio?: number;
39
+ pendingForMs?: number;
40
+ recoveryForMs?: number;
41
+ resolvedHoldMs?: number;
42
+ historySize?: number;
43
+ };
44
+ correlation?: {
45
+ minCorrelation?: number;
46
+ alpha?: number;
47
+ power?: number;
48
+ strongThreshold?: number;
49
+ maxLag?: number;
50
+ maxWindow?: number;
51
+ minCoverage?: number;
52
+ evaluateEveryIntervals?: number;
53
+ };
54
+ dashboard?: false | {
55
+ path?: string;
56
+ liveWindow?: number;
57
+ backfillLimit?: number;
58
+ maxBackfillAgeMs?: number;
59
+ topImpactRoutes?: number;
60
+ analyticsPageSize?: number;
61
+ sessionSummaryWindowHours?: number;
62
+ };
63
+ transport?: {
64
+ socketPath?: string;
65
+ cors?: string | boolean;
66
+ pingTimeoutMs?: number;
67
+ maxHttpBufferSize?: number;
68
+ };
69
+ publisher?: {
70
+ intervalMs?: number;
71
+ };
13
72
  tickIntervalMs?: number;
14
- excludePaths?: string[];
15
- consoleLog?: boolean;
16
- ringBufferSize?: number;
17
- alertBufferSize?: number;
73
+ simulation?: false | {
74
+ intervalMs?: number;
75
+ requestsPerTick?: number;
76
+ };
18
77
  }
19
- export type ReadonlyConfig = Readonly<Required<ConfigOptions>>;
78
+ type Resolved<T> = T extends false ? false : T extends readonly (infer U)[] ? readonly U[] : T extends object ? {
79
+ readonly [K in keyof T]-?: Resolved<Exclude<T[K], undefined>>;
80
+ } : T;
81
+ export type ReadonlyConfig = Resolved<ConfigOptions>;
82
+ export type ClientConfig = {
83
+ applicationVersion: string;
84
+ collection: Pick<ReadonlyConfig['collection'], 'bucketIntervalMs' | 'excludePaths'>;
85
+ thresholds: ReadonlyConfig['thresholds'];
86
+ cache: Pick<ReadonlyConfig['cache'], 'viewWindowBuckets'>;
87
+ persistence: false | Omit<Exclude<ReadonlyConfig['persistence'], false>, 'baseDir' | 'writer'>;
88
+ incidents: ReadonlyConfig['incidents'];
89
+ correlation: ReadonlyConfig['correlation'];
90
+ dashboard: ReadonlyConfig['dashboard'];
91
+ publisher: ReadonlyConfig['publisher'];
92
+ tickIntervalMs: number;
93
+ simulation: ReadonlyConfig['simulation'];
94
+ };
95
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { BucketsRequest } from '../domain';
2
+ export declare function parseBucketsRequest(raw: unknown): BucketsRequest | null;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseBucketsRequest = parseBucketsRequest;
4
+ const MAX_ID_LENGTH = 128;
5
+ function parseBucketsRequest(raw) {
6
+ if (!raw || typeof raw !== 'object')
7
+ return null;
8
+ const r = raw;
9
+ if (typeof r.subscriptionId !== 'string' || r.subscriptionId.length === 0 || r.subscriptionId.length > MAX_ID_LENGTH)
10
+ return null;
11
+ const sessionId = typeof r.sessionId === 'string' && r.sessionId.length <= MAX_ID_LENGTH ? r.sessionId : null;
12
+ const afterSequence = typeof r.afterSequence === 'number' && Number.isInteger(r.afterSequence) && r.afterSequence >= 0
13
+ ? r.afterSequence : null;
14
+ const afterEndTime = typeof r.afterEndTime === 'string' && !Number.isNaN(Date.parse(r.afterEndTime))
15
+ ? r.afterEndTime : null;
16
+ const limit = typeof r.limit === 'number' && Number.isFinite(r.limit) ? r.limit : undefined;
17
+ return { subscriptionId: r.subscriptionId, sessionId, afterSequence, afterEndTime, limit };
18
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './metrics.publisher';
2
2
  export * from './websocket.events';
3
+ export * from './buckets-request';
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./metrics.publisher"), exports);
18
18
  __exportStar(require("./websocket.events"), exports);
19
+ __exportStar(require("./buckets-request"), exports);
@@ -1,18 +1,31 @@
1
1
  import type { WebSocketAdapter } from "../../adapters/websocket.adapter";
2
- import type { SystemStaticInfo, AnalyticsData, DashboardData, HealthData } from "../domain";
2
+ import type { SystemStaticInfo, AnalyticsData, HealthDetails, SessionRecord, SessionManifest, SessionSummary, AnalyticsFilterSettings, CorrelationData, BucketsMessage, BucketsRequest, IncidentsSnapshot } from "../domain";
3
3
  export interface MetricsDataProvider {
4
4
  getSystemStaticInfo(): SystemStaticInfo;
5
- getDashboardData(): DashboardData;
6
- getAnalyticsData(): AnalyticsData;
7
- getHealthData(): HealthData;
5
+ getLiveBuckets(): BucketsMessage | null;
6
+ getBackFill(req: BucketsRequest): Promise<BucketsMessage>;
7
+ getAnalyticsData(filters?: AnalyticsFilterSettings): AnalyticsData;
8
+ getHealthData(): HealthDetails;
9
+ }
10
+ export interface SessionDataProvider {
11
+ getSessionRecord(): SessionRecord | null;
12
+ getSessionManifest(): Promise<SessionManifest>;
13
+ getSessionSummary(sessionNumber: number): Promise<SessionSummary | null>;
14
+ }
15
+ export interface IncidentDataProvider {
16
+ snapshot(): IncidentsSnapshot;
17
+ }
18
+ export interface CorrelationDataProvider {
19
+ pack(): CorrelationData;
20
+ replay(findingId: string): Promise<unknown>;
8
21
  }
9
22
  export declare class MetricsPublisher {
10
23
  private readonly provider;
24
+ private readonly sessionProvider;
25
+ private readonly correlationProvider;
26
+ private readonly incidentProvider;
11
27
  private readonly websocket;
12
- private readonly intervalMs;
13
- private interval?;
14
- constructor(provider: MetricsDataProvider, websocket: WebSocketAdapter, intervalMs?: number);
15
- start(): void;
16
- stop(): void;
17
- private publish;
28
+ private publishData;
29
+ constructor(provider: MetricsDataProvider, sessionProvider: SessionDataProvider, correlationProvider: CorrelationDataProvider, incidentProvider: IncidentDataProvider, websocket: WebSocketAdapter);
30
+ publish(): void;
18
31
  }