flow-debugger 1.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 (131) hide show
  1. package/PORTFOLIO_README_SECTION.md +177 -0
  2. package/README.md +251 -0
  3. package/dashboard/app.js +339 -0
  4. package/dashboard/index.html +168 -0
  5. package/dashboard/style.css +846 -0
  6. package/dist/cjs/core/Analytics.js +174 -0
  7. package/dist/cjs/core/Analytics.js.map +1 -0
  8. package/dist/cjs/core/Classifier.js +66 -0
  9. package/dist/cjs/core/Classifier.js.map +1 -0
  10. package/dist/cjs/core/HealthMonitor.js +79 -0
  11. package/dist/cjs/core/HealthMonitor.js.map +1 -0
  12. package/dist/cjs/core/RootCause.js +89 -0
  13. package/dist/cjs/core/RootCause.js.map +1 -0
  14. package/dist/cjs/core/Sampler.js +34 -0
  15. package/dist/cjs/core/Sampler.js.map +1 -0
  16. package/dist/cjs/core/Timeline.js +90 -0
  17. package/dist/cjs/core/Timeline.js.map +1 -0
  18. package/dist/cjs/core/TraceEngine.js +222 -0
  19. package/dist/cjs/core/TraceEngine.js.map +1 -0
  20. package/dist/cjs/core/types.js +21 -0
  21. package/dist/cjs/core/types.js.map +1 -0
  22. package/dist/cjs/index.js +46 -0
  23. package/dist/cjs/index.js.map +1 -0
  24. package/dist/cjs/integrations/axios.js +136 -0
  25. package/dist/cjs/integrations/axios.js.map +1 -0
  26. package/dist/cjs/integrations/fetch.js +153 -0
  27. package/dist/cjs/integrations/fetch.js.map +1 -0
  28. package/dist/cjs/integrations/mongo.js +111 -0
  29. package/dist/cjs/integrations/mongo.js.map +1 -0
  30. package/dist/cjs/integrations/mysql.js +212 -0
  31. package/dist/cjs/integrations/mysql.js.map +1 -0
  32. package/dist/cjs/integrations/postgres.js +182 -0
  33. package/dist/cjs/integrations/postgres.js.map +1 -0
  34. package/dist/cjs/integrations/redis.js +105 -0
  35. package/dist/cjs/integrations/redis.js.map +1 -0
  36. package/dist/cjs/middleware/express.js +255 -0
  37. package/dist/cjs/middleware/express.js.map +1 -0
  38. package/dist/esm/core/Analytics.js +170 -0
  39. package/dist/esm/core/Analytics.js.map +1 -0
  40. package/dist/esm/core/Classifier.js +61 -0
  41. package/dist/esm/core/Classifier.js.map +1 -0
  42. package/dist/esm/core/HealthMonitor.js +75 -0
  43. package/dist/esm/core/HealthMonitor.js.map +1 -0
  44. package/dist/esm/core/RootCause.js +86 -0
  45. package/dist/esm/core/RootCause.js.map +1 -0
  46. package/dist/esm/core/Sampler.js +30 -0
  47. package/dist/esm/core/Sampler.js.map +1 -0
  48. package/dist/esm/core/Timeline.js +86 -0
  49. package/dist/esm/core/Timeline.js.map +1 -0
  50. package/dist/esm/core/TraceEngine.js +217 -0
  51. package/dist/esm/core/TraceEngine.js.map +1 -0
  52. package/dist/esm/core/types.js +18 -0
  53. package/dist/esm/core/types.js.map +1 -0
  54. package/dist/esm/index.js +22 -0
  55. package/dist/esm/index.js.map +1 -0
  56. package/dist/esm/integrations/axios.js +133 -0
  57. package/dist/esm/integrations/axios.js.map +1 -0
  58. package/dist/esm/integrations/fetch.js +149 -0
  59. package/dist/esm/integrations/fetch.js.map +1 -0
  60. package/dist/esm/integrations/mongo.js +107 -0
  61. package/dist/esm/integrations/mongo.js.map +1 -0
  62. package/dist/esm/integrations/mysql.js +209 -0
  63. package/dist/esm/integrations/mysql.js.map +1 -0
  64. package/dist/esm/integrations/postgres.js +179 -0
  65. package/dist/esm/integrations/postgres.js.map +1 -0
  66. package/dist/esm/integrations/redis.js +102 -0
  67. package/dist/esm/integrations/redis.js.map +1 -0
  68. package/dist/esm/middleware/express.js +219 -0
  69. package/dist/esm/middleware/express.js.map +1 -0
  70. package/dist/types/core/Analytics.d.ts +35 -0
  71. package/dist/types/core/Analytics.d.ts.map +1 -0
  72. package/dist/types/core/Classifier.d.ts +21 -0
  73. package/dist/types/core/Classifier.d.ts.map +1 -0
  74. package/dist/types/core/HealthMonitor.d.ts +14 -0
  75. package/dist/types/core/HealthMonitor.d.ts.map +1 -0
  76. package/dist/types/core/RootCause.d.ts +12 -0
  77. package/dist/types/core/RootCause.d.ts.map +1 -0
  78. package/dist/types/core/Sampler.d.ts +13 -0
  79. package/dist/types/core/Sampler.d.ts.map +1 -0
  80. package/dist/types/core/Timeline.d.ts +22 -0
  81. package/dist/types/core/Timeline.d.ts.map +1 -0
  82. package/dist/types/core/TraceEngine.d.ts +47 -0
  83. package/dist/types/core/TraceEngine.d.ts.map +1 -0
  84. package/dist/types/core/types.d.ts +118 -0
  85. package/dist/types/core/types.d.ts.map +1 -0
  86. package/dist/types/index.d.ts +18 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/integrations/axios.d.ts +22 -0
  89. package/dist/types/integrations/axios.d.ts.map +1 -0
  90. package/dist/types/integrations/fetch.d.ts +25 -0
  91. package/dist/types/integrations/fetch.d.ts.map +1 -0
  92. package/dist/types/integrations/mongo.d.ts +26 -0
  93. package/dist/types/integrations/mongo.d.ts.map +1 -0
  94. package/dist/types/integrations/mysql.d.ts +20 -0
  95. package/dist/types/integrations/mysql.d.ts.map +1 -0
  96. package/dist/types/integrations/postgres.d.ts +20 -0
  97. package/dist/types/integrations/postgres.d.ts.map +1 -0
  98. package/dist/types/integrations/redis.d.ts +20 -0
  99. package/dist/types/integrations/redis.d.ts.map +1 -0
  100. package/dist/types/middleware/express.d.ts +39 -0
  101. package/dist/types/middleware/express.d.ts.map +1 -0
  102. package/example/server.ts +234 -0
  103. package/jest.config.js +8 -0
  104. package/package.json +110 -0
  105. package/portfolio-repo/APIRESPONSE DASH.png +0 -0
  106. package/portfolio-repo/PAYLOAD.png +0 -0
  107. package/portfolio-repo/README.md +182 -0
  108. package/src/core/Analytics.ts +209 -0
  109. package/src/core/Classifier.ts +82 -0
  110. package/src/core/HealthMonitor.ts +92 -0
  111. package/src/core/RootCause.ts +105 -0
  112. package/src/core/Sampler.ts +35 -0
  113. package/src/core/Timeline.ts +108 -0
  114. package/src/core/TraceEngine.ts +266 -0
  115. package/src/core/types.ts +170 -0
  116. package/src/index.ts +42 -0
  117. package/src/integrations/axios.ts +164 -0
  118. package/src/integrations/fetch.ts +172 -0
  119. package/src/integrations/mongo.ts +130 -0
  120. package/src/integrations/mysql.ts +239 -0
  121. package/src/integrations/postgres.ts +217 -0
  122. package/src/integrations/redis.ts +122 -0
  123. package/src/middleware/express.ts +264 -0
  124. package/tests/Analytics.test.ts +136 -0
  125. package/tests/Classifier.test.ts +57 -0
  126. package/tests/RootCause.test.ts +69 -0
  127. package/tests/TraceEngine.test.ts +110 -0
  128. package/tsconfig.cjs.json +9 -0
  129. package/tsconfig.esm.json +9 -0
  130. package/tsconfig.json +31 -0
  131. package/tsconfig.types.json +8 -0
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────────────────────
3
+ // flow-debugger — Express Middleware
4
+ // Auto-traces every request, provides /__debugger API + dashboard
5
+ // ─────────────────────────────────────────────────────────────
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.flowDebugger = flowDebugger;
41
+ const TraceEngine_1 = require("../core/TraceEngine");
42
+ const Analytics_1 = require("../core/Analytics");
43
+ const Sampler_1 = require("../core/Sampler");
44
+ const types_1 = require("../core/types");
45
+ const path = __importStar(require("path"));
46
+ const fs = __importStar(require("fs"));
47
+ // AsyncLocalStorage for automatic tracer context propagation
48
+ let asyncLocalStorage;
49
+ try {
50
+ const { AsyncLocalStorage } = require('async_hooks');
51
+ asyncLocalStorage = new AsyncLocalStorage();
52
+ }
53
+ catch (_) {
54
+ // Fallback for environments without async_hooks
55
+ asyncLocalStorage = null;
56
+ }
57
+ /**
58
+ * Create the flow-debugger Express middleware.
59
+ *
60
+ * Usage:
61
+ * const debugger = flowDebugger({ slowThreshold: 500 });
62
+ * app.use(debugger.middleware);
63
+ *
64
+ * // Auto-instrument databases
65
+ * mongoTracer(mongoose, { getTracer: debugger.getTracer });
66
+ * mysqlTracer(pool, { getTracer: debugger.getTracer });
67
+ *
68
+ * // Dashboard at: GET /__debugger/dashboard
69
+ * // API at: GET /__debugger
70
+ */
71
+ function flowDebugger(config) {
72
+ const mergedConfig = { ...types_1.DEFAULT_CONFIG, ...config };
73
+ const engine = new TraceEngine_1.TraceEngine(mergedConfig);
74
+ const analytics = new Analytics_1.Analytics(mergedConfig.maxTraces);
75
+ const sampler = new Sampler_1.Sampler(mergedConfig.samplingRate, mergedConfig.alwaysSampleErrors);
76
+ // Current tracer per async context
77
+ let fallbackTracer = null;
78
+ const getTracer = () => {
79
+ if (asyncLocalStorage) {
80
+ try {
81
+ const store = asyncLocalStorage.getStore();
82
+ return store?.tracer || null;
83
+ }
84
+ catch (_) { }
85
+ }
86
+ return fallbackTracer;
87
+ };
88
+ const middleware = (req, res, next) => {
89
+ try {
90
+ // Skip debugger endpoints
91
+ if (req.path?.startsWith('/__debugger')) {
92
+ return handleDebuggerRoute(req, res, next, analytics, mergedConfig);
93
+ }
94
+ if (!mergedConfig.enabled)
95
+ return next();
96
+ // Sampling
97
+ if (!sampler.shouldSample())
98
+ return next();
99
+ const tracer = engine.startTrace(req.path || req.url, req.method);
100
+ req.tracer = tracer;
101
+ req.traceId = tracer.getTraceId();
102
+ // Set header for client correlation
103
+ res.setHeader('X-Trace-Id', tracer.getTraceId());
104
+ const run = () => {
105
+ fallbackTracer = tracer;
106
+ // Calculate payload size if body exists
107
+ let payloadSize;
108
+ try {
109
+ if (req.body) {
110
+ const bodyStr = JSON.stringify(req.body);
111
+ payloadSize = Buffer.byteLength(bodyStr, 'utf8');
112
+ }
113
+ }
114
+ catch (_) {
115
+ // ignore
116
+ }
117
+ // Hook into response finish
118
+ const originalEnd = res.end;
119
+ res.end = function (...args) {
120
+ try {
121
+ const trace = tracer.end(res.statusCode);
122
+ // Add environment and payload size to trace
123
+ trace.environment = mergedConfig.environment;
124
+ trace.payloadSize = payloadSize;
125
+ analytics.record(trace);
126
+ // If error and we had skipped sampling, re-sample
127
+ }
128
+ catch (_) {
129
+ // never crash
130
+ }
131
+ fallbackTracer = null;
132
+ return originalEnd.apply(res, args);
133
+ };
134
+ next();
135
+ };
136
+ // Use AsyncLocalStorage if available
137
+ if (asyncLocalStorage) {
138
+ asyncLocalStorage.run({ tracer }, run);
139
+ }
140
+ else {
141
+ run();
142
+ }
143
+ }
144
+ catch (_) {
145
+ // Production-safe: if debugger fails, pass through
146
+ next();
147
+ }
148
+ };
149
+ return { middleware, engine, analytics, getTracer };
150
+ }
151
+ /**
152
+ * Handle /__debugger routes
153
+ */
154
+ function handleDebuggerRoute(req, res, next, analytics, config) {
155
+ if (!config.enableDashboard)
156
+ return next();
157
+ try {
158
+ const subPath = req.path.replace('/__debugger', '') || '/';
159
+ switch (subPath) {
160
+ case '/':
161
+ case '/api':
162
+ // JSON analytics API
163
+ res.json(analytics.getReport());
164
+ break;
165
+ case '/dashboard': {
166
+ // Serve the HTML dashboard
167
+ const dashboardPath = path.resolve(__dirname, '../../dashboard/index.html');
168
+ if (fs.existsSync(dashboardPath)) {
169
+ res.sendFile(dashboardPath);
170
+ }
171
+ else {
172
+ // Fallback: inline minimal dashboard
173
+ res.send(getInlineDashboard());
174
+ }
175
+ break;
176
+ }
177
+ case '/dashboard/style.css': {
178
+ const cssPath = path.resolve(__dirname, '../../dashboard/style.css');
179
+ if (fs.existsSync(cssPath)) {
180
+ res.type('text/css').sendFile(cssPath);
181
+ }
182
+ else {
183
+ res.status(404).send('Not found');
184
+ }
185
+ break;
186
+ }
187
+ case '/dashboard/app.js': {
188
+ const jsPath = path.resolve(__dirname, '../../dashboard/app.js');
189
+ if (fs.existsSync(jsPath)) {
190
+ res.type('application/javascript').sendFile(jsPath);
191
+ }
192
+ else {
193
+ res.status(404).send('Not found');
194
+ }
195
+ break;
196
+ }
197
+ case '/health':
198
+ res.json(analytics.getHealthMonitor().getAllHealth());
199
+ break;
200
+ case '/endpoint': {
201
+ const endpoint = req.query?.path || req.query?.endpoint;
202
+ if (endpoint) {
203
+ const report = analytics.getEndpointReport(String(endpoint));
204
+ res.json(report || { error: 'Endpoint not found' });
205
+ }
206
+ else {
207
+ res.json({ error: 'Provide ?path=/your/endpoint' });
208
+ }
209
+ break;
210
+ }
211
+ case '/search': {
212
+ const query = req.query?.q || req.query?.query;
213
+ const env = req.query?.env;
214
+ const limit = req.query?.limit ? parseInt(String(req.query.limit), 10) : 50;
215
+ if (query) {
216
+ const results = analytics.searchTraces(String(query), { env: env ? String(env) : undefined, limit });
217
+ res.json({ query, results, count: results.length });
218
+ }
219
+ else {
220
+ res.json({ error: 'Provide ?q=search_term' });
221
+ }
222
+ break;
223
+ }
224
+ default:
225
+ next();
226
+ }
227
+ }
228
+ catch (err) {
229
+ res.status(500).json({ error: 'Debugger dashboard error' });
230
+ }
231
+ }
232
+ /** Inline fallback dashboard if files aren't found */
233
+ function getInlineDashboard() {
234
+ return `<!DOCTYPE html>
235
+ <html lang="en">
236
+ <head>
237
+ <meta charset="UTF-8">
238
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
239
+ <title>Flow Debugger Dashboard</title>
240
+ <style>body{font-family:system-ui;background:#0a0a1a;color:#e0e0e0;padding:20px}
241
+ h1{color:#7c3aed}.card{background:#1a1a2e;border-radius:12px;padding:20px;margin:10px 0;border:1px solid #2a2a4a}</style>
242
+ </head>
243
+ <body>
244
+ <h1>🔍 Flow Debugger</h1>
245
+ <p>Dashboard files not found. API available at <a href="/__debugger" style="color:#7c3aed">/__debugger</a></p>
246
+ <div class="card" id="data">Loading...</div>
247
+ <script>
248
+ fetch('/__debugger').then(r=>r.json()).then(d=>{
249
+ document.getElementById('data').innerHTML='<pre>'+JSON.stringify(d,null,2)+'</pre>';
250
+ });
251
+ </script>
252
+ </body>
253
+ </html>`;
254
+ }
255
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../../src/middleware/express.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // flow-debugger — Analytics Engine
3
+ // Per-endpoint aggregation + service failure grouping
4
+ // ─────────────────────────────────────────────────────────────
5
+ import { HealthMonitor } from './HealthMonitor';
6
+ export class Analytics {
7
+ constructor(maxTraces = 1000) {
8
+ this.traces = [];
9
+ this.maxTraces = maxTraces;
10
+ this.startTime = new Date();
11
+ this.healthMonitor = new HealthMonitor();
12
+ }
13
+ /** Record a completed trace */
14
+ record(trace) {
15
+ try {
16
+ this.traces.push(trace);
17
+ // Trim if over limit (keep most recent)
18
+ if (this.traces.length > this.maxTraces) {
19
+ this.traces = this.traces.slice(-this.maxTraces);
20
+ }
21
+ // Update health monitor with step results
22
+ for (const step of trace.steps) {
23
+ this.healthMonitor.recordStep(step);
24
+ }
25
+ }
26
+ catch (_) {
27
+ // never crash
28
+ }
29
+ }
30
+ /** Get full analytics report */
31
+ getReport() {
32
+ const endpoints = this.getEndpointStats();
33
+ const totalRequests = this.traces.length;
34
+ const totalErrors = this.traces.filter(t => t.classification === 'ERROR' || t.classification === 'CRITICAL').length;
35
+ const totalSlow = this.traces.filter(t => t.classification === 'WARN').length;
36
+ const uptime = Date.now() - this.startTime.getTime();
37
+ return {
38
+ totalRequests,
39
+ totalErrors,
40
+ totalSlow,
41
+ uptime,
42
+ endpoints,
43
+ serviceHealth: this.healthMonitor.getAllHealth(),
44
+ topFailures: this.getTopFailures(),
45
+ recentTraces: this.traces.slice(-20).reverse(),
46
+ };
47
+ }
48
+ /** Get stats for a specific endpoint */
49
+ getEndpointReport(path) {
50
+ const stats = this.getEndpointStats();
51
+ return stats.find(s => s.path === path) || null;
52
+ }
53
+ /** Get aggregated stats per endpoint */
54
+ getEndpointStats() {
55
+ const grouped = new Map();
56
+ for (const trace of this.traces) {
57
+ const key = `${trace.method}:${trace.endpoint}`;
58
+ if (!grouped.has(key))
59
+ grouped.set(key, []);
60
+ grouped.get(key).push(trace);
61
+ }
62
+ const stats = [];
63
+ for (const [key, traces] of grouped) {
64
+ const [method, path] = key.split(':');
65
+ const durations = traces.map(t => t.totalDuration).sort((a, b) => a - b);
66
+ const errorCount = traces.filter(t => t.classification === 'ERROR' || t.classification === 'CRITICAL').length;
67
+ const slowCount = traces.filter(t => t.classification === 'WARN').length;
68
+ // Common issues
69
+ const issues = new Map();
70
+ for (const t of traces) {
71
+ if (t.rootCause) {
72
+ const key = t.rootCause.cause;
73
+ issues.set(key, (issues.get(key) || 0) + 1);
74
+ }
75
+ }
76
+ const commonIssues = [...issues.entries()]
77
+ .sort((a, b) => b[1] - a[1])
78
+ .slice(0, 5)
79
+ .map(([issue, count]) => `${issue} (${count}x)`);
80
+ // Service failure breakdown
81
+ const serviceFailures = this.getServiceFailures(traces);
82
+ stats.push({
83
+ path,
84
+ method,
85
+ totalRequests: traces.length,
86
+ errorCount,
87
+ slowCount,
88
+ avgDuration: durations.reduce((a, b) => a + b, 0) / durations.length,
89
+ p95Duration: durations[Math.floor(durations.length * 0.95)] || 0,
90
+ maxDuration: durations[durations.length - 1] || 0,
91
+ commonIssues,
92
+ serviceFailures,
93
+ recentTraces: traces.slice(-5).reverse(),
94
+ });
95
+ }
96
+ return stats.sort((a, b) => b.totalRequests - a.totalRequests);
97
+ }
98
+ /** Get service failure breakdown across all traces */
99
+ getTopFailures() {
100
+ return this.getServiceFailures(this.traces);
101
+ }
102
+ /** Calculate service failure stats from a set of traces */
103
+ getServiceFailures(traces) {
104
+ const failures = new Map();
105
+ let totalFailures = 0;
106
+ for (const trace of traces) {
107
+ for (const step of trace.steps) {
108
+ if (step.status === 'error' || step.status === 'timeout') {
109
+ failures.set(step.service, (failures.get(step.service) || 0) + 1);
110
+ totalFailures++;
111
+ }
112
+ }
113
+ }
114
+ return [...failures.entries()]
115
+ .map(([service, count]) => ({
116
+ service,
117
+ count,
118
+ percentage: totalFailures > 0 ? Math.round((count / totalFailures) * 100) : 0,
119
+ }))
120
+ .sort((a, b) => b.count - a.count);
121
+ }
122
+ /** Clear all stored traces */
123
+ clear() {
124
+ this.traces = [];
125
+ }
126
+ /** Get raw trace count */
127
+ getTraceCount() {
128
+ return this.traces.length;
129
+ }
130
+ /**
131
+ * Search traces by traceId, endpoint, or error message.
132
+ * Returns matching traces sorted by most recent first.
133
+ */
134
+ searchTraces(query, options) {
135
+ if (!query)
136
+ return [];
137
+ const lowerQuery = query.toLowerCase();
138
+ const limit = options?.limit || 50;
139
+ const matches = this.traces.filter(trace => {
140
+ // Filter by environment if specified
141
+ if (options?.env && trace.environment !== options.env) {
142
+ return false;
143
+ }
144
+ // Match traceId
145
+ if (trace.traceId.toLowerCase().includes(lowerQuery)) {
146
+ return true;
147
+ }
148
+ // Match endpoint
149
+ if (trace.endpoint.toLowerCase().includes(lowerQuery)) {
150
+ return true;
151
+ }
152
+ // Match error message in steps
153
+ for (const step of trace.steps) {
154
+ if (step.error && step.error.toLowerCase().includes(lowerQuery)) {
155
+ return true;
156
+ }
157
+ }
158
+ // Match root cause
159
+ if (trace.rootCause && trace.rootCause.cause.toLowerCase().includes(lowerQuery)) {
160
+ return true;
161
+ }
162
+ return false;
163
+ });
164
+ return matches.slice(-limit).reverse();
165
+ }
166
+ getHealthMonitor() {
167
+ return this.healthMonitor;
168
+ }
169
+ }
170
+ //# sourceMappingURL=Analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Analytics.js","sourceRoot":"","sources":["../../../src/core/Analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // flow-debugger — Classifier
3
+ // Classifies steps and traces into severity levels
4
+ // ─────────────────────────────────────────────────────────────
5
+ /**
6
+ * Classify a single step based on its duration and status.
7
+ *
8
+ * INFO → normal, <slowThreshold ms
9
+ * WARN → slow (>slowThreshold ms)
10
+ * ERROR → step failed
11
+ * CRITICAL → dependency down / timeout
12
+ */
13
+ export function classify(duration, status, config) {
14
+ const threshold = config.slowThreshold ?? 300;
15
+ if (status === 'timeout')
16
+ return 'CRITICAL';
17
+ if (status === 'error')
18
+ return 'ERROR';
19
+ if (duration > threshold)
20
+ return 'WARN';
21
+ return 'INFO';
22
+ }
23
+ /**
24
+ * Classify an entire trace based on its steps.
25
+ * The trace gets the highest severity from any of its steps.
26
+ */
27
+ export function classifyTrace(steps, _totalDuration, config) {
28
+ const threshold = config.slowThreshold ?? 300;
29
+ let maxLevel = 'INFO';
30
+ const priority = {
31
+ INFO: 0,
32
+ WARN: 1,
33
+ ERROR: 2,
34
+ CRITICAL: 3,
35
+ };
36
+ for (const step of steps) {
37
+ if (priority[step.classification] > priority[maxLevel]) {
38
+ maxLevel = step.classification;
39
+ }
40
+ }
41
+ // Also check total duration
42
+ if (maxLevel === 'INFO' && _totalDuration > threshold) {
43
+ maxLevel = 'WARN';
44
+ }
45
+ return maxLevel;
46
+ }
47
+ /**
48
+ * Classify a database query specifically — used by integrations
49
+ * to detect slow queries with a dedicated threshold.
50
+ */
51
+ export function classifyQuery(duration, status, config) {
52
+ const threshold = config.slowQueryThreshold ?? 300;
53
+ if (status === 'timeout')
54
+ return 'CRITICAL';
55
+ if (status === 'error')
56
+ return 'ERROR';
57
+ if (duration > threshold)
58
+ return 'WARN';
59
+ return 'INFO';
60
+ }
61
+ //# sourceMappingURL=Classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Classifier.js","sourceRoot":"","sources":["../../../src/core/Classifier.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,6BAA6B;AAC7B,mDAAmD;AACnD,gEAAgE;AAShE;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CACpB,QAAgB,EAChB,MAAkB,EAClB,MAA6C;IAE7C,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC;IAE9C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,QAAQ,GAAG,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CACzB,KAAkB,EAClB,cAAsB,EACtB,MAA6C;IAE7C,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC;IAC9C,IAAI,QAAQ,GAAwB,MAAM,CAAC;IAE3C,MAAM,QAAQ,GAAwC;QAClD,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;QACR,QAAQ,EAAE,CAAC;KACd,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACnC,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,IAAI,QAAQ,KAAK,MAAM,IAAI,cAAc,GAAG,SAAS,EAAE,CAAC;QACpD,QAAQ,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CACzB,QAAgB,EAChB,MAAkB,EAClB,MAAkD;IAElD,MAAM,SAAS,GAAG,MAAM,CAAC,kBAAkB,IAAI,GAAG,CAAC;IAEnD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,QAAQ,GAAG,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -0,0 +1,75 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // flow-debugger — Health Monitor
3
+ // Tracks dependency health from step results
4
+ // ─────────────────────────────────────────────────────────────
5
+ export class HealthMonitor {
6
+ constructor() {
7
+ this.records = new Map();
8
+ }
9
+ /** Record a step result to update health tracking */
10
+ recordStep(step) {
11
+ try {
12
+ const key = step.service;
13
+ if (key === 'internal' || key === 'unknown')
14
+ return;
15
+ if (!this.records.has(key)) {
16
+ this.records.set(key, {
17
+ service: step.service,
18
+ name: key,
19
+ successes: 0,
20
+ failures: 0,
21
+ lastCheck: new Date(),
22
+ });
23
+ }
24
+ const record = this.records.get(key);
25
+ record.lastCheck = new Date();
26
+ if (step.status === 'success') {
27
+ record.successes++;
28
+ }
29
+ else {
30
+ record.failures++;
31
+ }
32
+ }
33
+ catch (_) {
34
+ // never crash
35
+ }
36
+ }
37
+ /** Get health status for a specific service */
38
+ getHealth(service) {
39
+ const record = this.records.get(service);
40
+ if (!record)
41
+ return null;
42
+ return this.toHealthStatus(record);
43
+ }
44
+ /** Get health status for all tracked services */
45
+ getAllHealth() {
46
+ return [...this.records.values()].map(r => this.toHealthStatus(r));
47
+ }
48
+ toHealthStatus(record) {
49
+ const total = record.successes + record.failures;
50
+ const successRate = total > 0 ? record.successes / total : 1;
51
+ let status;
52
+ if (successRate >= 0.95) {
53
+ status = 'healthy';
54
+ }
55
+ else if (successRate >= 0.7) {
56
+ status = 'degraded';
57
+ }
58
+ else {
59
+ status = 'down';
60
+ }
61
+ return {
62
+ service: record.service,
63
+ name: record.name,
64
+ status,
65
+ lastCheck: record.lastCheck,
66
+ successRate: Math.round(successRate * 100),
67
+ totalChecks: total,
68
+ };
69
+ }
70
+ /** Reset all health records */
71
+ reset() {
72
+ this.records.clear();
73
+ }
74
+ }
75
+ //# sourceMappingURL=HealthMonitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HealthMonitor.js","sourceRoot":"","sources":["../../../src/core/HealthMonitor.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,iCAAiC;AACjC,6CAA6C;AAC7C,gEAAgE;AAiBhE,MAAM,OAAO,aAAa;IAA1B;QACY,YAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAsEtD,CAAC;IApEG,qDAAqD;IACrD,UAAU,CAAC,IAAe;QACtB,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;YACzB,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO;YAEpD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;oBAClB,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,IAAI,EAAE,GAAG;oBACT,SAAS,EAAE,CAAC;oBACZ,QAAQ,EAAE,CAAC;oBACX,SAAS,EAAE,IAAI,IAAI,EAAE;iBACxB,CAAC,CAAC;YACP,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;YACtC,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;YAE9B,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,CAAC,SAAS,EAAE,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtB,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,cAAc;QAClB,CAAC;IACL,CAAC;IAED,+CAA+C;IAC/C,SAAS,CAAC,OAAmB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,iDAAiD;IACjD,YAAY;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAEO,cAAc,CAAC,MAAoB;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjD,MAAM,WAAW,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7D,IAAI,MAAmB,CAAC;QACxB,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YACtB,MAAM,GAAG,SAAS,CAAC;QACvB,CAAC;aAAM,IAAI,WAAW,IAAI,GAAG,EAAE,CAAC;YAC5B,MAAM,GAAG,UAAU,CAAC;QACxB,CAAC;aAAM,CAAC;YACJ,MAAM,GAAG,MAAM,CAAC;QACpB,CAAC;QAED,OAAO;YACH,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM;YACN,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;YAC1C,WAAW,EAAE,KAAK;SACrB,CAAC;IACN,CAAC;IAED,+BAA+B;IAC/B,KAAK;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACJ"}