@getvision/core 0.0.0-develop-20251031183955 → 0.0.1
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.
- package/dist/__tests__/core.test.d.ts +2 -0
- package/dist/__tests__/core.test.d.ts.map +1 -0
- package/dist/__tests__/core.test.js +88 -0
- package/dist/__tests__/tracing.test.d.ts +2 -0
- package/dist/__tests__/tracing.test.d.ts.map +1 -0
- package/dist/__tests__/tracing.test.js +108 -0
- package/dist/core.d.ts +98 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +266 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -107
- package/dist/logs/index.d.ts +3 -0
- package/dist/logs/index.d.ts.map +1 -0
- package/dist/logs/index.js +2 -0
- package/dist/logs/interceptor.d.ts +21 -0
- package/dist/logs/interceptor.d.ts.map +1 -0
- package/dist/logs/interceptor.js +72 -0
- package/dist/logs/store.d.ts +36 -0
- package/dist/logs/store.d.ts.map +1 -0
- package/dist/logs/store.js +72 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/jsonrpc.d.ts +21 -0
- package/dist/server/jsonrpc.d.ts.map +1 -0
- package/dist/server/jsonrpc.js +73 -0
- package/dist/server/static.d.ts +10 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +54 -0
- package/dist/server/websocket.d.ts +42 -0
- package/dist/server/websocket.d.ts.map +1 -0
- package/dist/server/websocket.js +267 -0
- package/dist/tracing/index.d.ts +3 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +2 -0
- package/dist/tracing/store.d.ts +52 -0
- package/dist/tracing/store.d.ts.map +1 -0
- package/dist/tracing/store.js +101 -0
- package/dist/tracing/tracer.d.ts +28 -0
- package/dist/tracing/tracer.d.ts.map +1 -0
- package/dist/tracing/tracer.js +64 -0
- package/dist/types/adapter-options.d.ts +69 -0
- package/dist/types/adapter-options.d.ts.map +1 -0
- package/dist/types/adapter-options.js +4 -0
- package/dist/types/index.d.ts +193 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/logs.d.ts +14 -0
- package/dist/types/logs.d.ts.map +1 -0
- package/dist/types/logs.js +1 -0
- package/dist/ui/assets/index-5t7c-m29.js +243 -0
- package/dist/ui/assets/index-9ueE5-_1.js +228 -0
- package/dist/ui/assets/index-B2zDhd4y.js +228 -0
- package/dist/ui/assets/index-B6PCTRWI.js +228 -0
- package/dist/ui/assets/index-BAqOyMpS.js +228 -0
- package/dist/ui/assets/index-BBPymjIY.css +1 -0
- package/dist/ui/assets/index-BFZ9LDLI.js +228 -0
- package/dist/ui/assets/index-BK3A49yO.js +243 -0
- package/dist/ui/assets/index-BVC9j-JL.css +1 -0
- package/dist/ui/assets/index-BWzGTXsJ.js +228 -0
- package/dist/ui/assets/index-BZaQlF2p.js +228 -0
- package/dist/ui/assets/index-BbYLBWtj.css +1 -0
- package/dist/ui/assets/index-Bgf_12ju.js +243 -0
- package/dist/ui/assets/index-Bhxve5KF.css +1 -0
- package/dist/ui/assets/index-Bj-CWu-L.js +228 -0
- package/dist/ui/assets/index-BlJwGFyg.js +243 -0
- package/dist/ui/assets/index-BnD39P39.js +228 -0
- package/dist/ui/assets/index-C9X3l8Qf.js +228 -0
- package/dist/ui/assets/index-C9wDB-pp.js +228 -0
- package/dist/ui/assets/index-CAONCZtM.js +243 -0
- package/dist/ui/assets/index-CCtH3nj-.js +243 -0
- package/dist/ui/assets/index-CKzeeZJS.js +228 -0
- package/dist/ui/assets/index-Cctg6X14.js +243 -0
- package/dist/ui/assets/index-Ch3Kvj5x.js +228 -0
- package/dist/ui/assets/index-CkV-qXIH.css +1 -0
- package/dist/ui/assets/index-Cl2VKig8.js +228 -0
- package/dist/ui/assets/index-CoKjAtkW.css +1 -0
- package/dist/ui/assets/index-D4C4VyHp.css +1 -0
- package/dist/ui/assets/index-DHQw82rB.js +228 -0
- package/dist/ui/assets/index-DIfw1ZVL.css +1 -0
- package/dist/ui/assets/index-DJJX2zqa.js +228 -0
- package/dist/ui/assets/index-D_D2XkaS.js +228 -0
- package/dist/ui/assets/index-De-GZ9-w.js +228 -0
- package/dist/ui/assets/index-DoWtvKFs.js +228 -0
- package/dist/ui/assets/index-Dyseuj-Z.js +223 -0
- package/dist/ui/assets/index-ErxJEkTC.js +243 -0
- package/dist/ui/assets/index-HIUv_thh.css +1 -0
- package/dist/ui/assets/index-HhqjfP8c.js +228 -0
- package/dist/ui/assets/index-eUFXMYOK.js +221 -0
- package/dist/ui/assets/index-jabSppNC.js +228 -0
- package/dist/ui/assets/index-t88G2D4Q.js +228 -0
- package/dist/ui/assets/index-tl7-KOr9.css +1 -0
- package/dist/ui/assets/index-uyOJY0cv.js +228 -0
- package/dist/ui/assets/index-wmKPAJzR.js +243 -0
- package/dist/utils/service-detection.d.ts +43 -0
- package/dist/utils/service-detection.d.ts.map +1 -0
- package/dist/utils/service-detection.js +103 -0
- package/dist/utils/zod-utils.d.ts +7 -0
- package/dist/utils/zod-utils.d.ts.map +1 -0
- package/dist/utils/zod-utils.js +145 -0
- package/package.json +1 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
+
import { createServer } from 'http';
|
|
3
|
+
import { JsonRpcHandler } from './jsonrpc';
|
|
4
|
+
import { serveStatic, getUIPath } from './static';
|
|
5
|
+
/**
|
|
6
|
+
* Vision WebSocket Server
|
|
7
|
+
* Handles real-time communication with the dashboard UI
|
|
8
|
+
* Also serves static UI files on the same port
|
|
9
|
+
*/
|
|
10
|
+
export class VisionWebSocketServer {
|
|
11
|
+
httpServer;
|
|
12
|
+
wss;
|
|
13
|
+
clients = new Set();
|
|
14
|
+
rpc;
|
|
15
|
+
options;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.options = {
|
|
18
|
+
port: options.port ?? 9500,
|
|
19
|
+
host: options.host ?? 'localhost',
|
|
20
|
+
maxTraces: options.maxTraces ?? 1000,
|
|
21
|
+
maxLogs: options.maxLogs ?? 10_000,
|
|
22
|
+
captureConsole: options.captureConsole ?? true,
|
|
23
|
+
enableCors: options.enableCors ?? true,
|
|
24
|
+
};
|
|
25
|
+
this.rpc = new JsonRpcHandler();
|
|
26
|
+
// Create HTTP server first
|
|
27
|
+
this.httpServer = createServer((req, res) => {
|
|
28
|
+
this.handleHttp(req, res).catch(err => {
|
|
29
|
+
console.error('HTTP handler error:', err);
|
|
30
|
+
res.writeHead(500);
|
|
31
|
+
res.end('Internal Server Error');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
// Attach WebSocket server to HTTP server on /ws path
|
|
35
|
+
this.wss = new WebSocketServer({
|
|
36
|
+
server: this.httpServer,
|
|
37
|
+
path: '/ws',
|
|
38
|
+
});
|
|
39
|
+
this.setupServer();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Handle HTTP requests (for serving UI)
|
|
43
|
+
*/
|
|
44
|
+
async handleHttp(req, res) {
|
|
45
|
+
// Enable CORS
|
|
46
|
+
if (this.options.enableCors) {
|
|
47
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
48
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
49
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
50
|
+
}
|
|
51
|
+
if (req.method === 'OPTIONS') {
|
|
52
|
+
res.writeHead(200);
|
|
53
|
+
res.end();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Health check
|
|
57
|
+
if (req.url === '/health') {
|
|
58
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
59
|
+
res.end(JSON.stringify({ status: 'ok', clients: this.clients.size }));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Try to serve static files from built UI
|
|
63
|
+
const uiPath = getUIPath();
|
|
64
|
+
const served = await serveStatic(req, res, uiPath);
|
|
65
|
+
if (!served) {
|
|
66
|
+
// Fallback to embedded UI
|
|
67
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
68
|
+
res.end(this.getEmbeddedUI());
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get embedded UI HTML
|
|
73
|
+
* For now, returns a simple page that connects to WebSocket
|
|
74
|
+
* In production, this would serve the built React app
|
|
75
|
+
*/
|
|
76
|
+
getEmbeddedUI() {
|
|
77
|
+
return `<!DOCTYPE html>
|
|
78
|
+
<html lang="en">
|
|
79
|
+
<head>
|
|
80
|
+
<meta charset="UTF-8">
|
|
81
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
82
|
+
<title>Vision Dashboard</title>
|
|
83
|
+
<style>
|
|
84
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
85
|
+
body {
|
|
86
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
87
|
+
background: #0a0a0a;
|
|
88
|
+
color: #fff;
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
min-height: 100vh;
|
|
93
|
+
}
|
|
94
|
+
.container {
|
|
95
|
+
text-align: center;
|
|
96
|
+
max-width: 600px;
|
|
97
|
+
padding: 2rem;
|
|
98
|
+
}
|
|
99
|
+
h1 { font-size: 2.5rem; margin-bottom: 1rem; }
|
|
100
|
+
.status {
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 0.5rem;
|
|
104
|
+
padding: 0.5rem 1rem;
|
|
105
|
+
background: #1a1a1a;
|
|
106
|
+
border-radius: 8px;
|
|
107
|
+
margin: 1rem 0;
|
|
108
|
+
}
|
|
109
|
+
.dot {
|
|
110
|
+
width: 8px;
|
|
111
|
+
height: 8px;
|
|
112
|
+
border-radius: 50%;
|
|
113
|
+
background: #22c55e;
|
|
114
|
+
animation: pulse 2s infinite;
|
|
115
|
+
}
|
|
116
|
+
@keyframes pulse {
|
|
117
|
+
0%, 100% { opacity: 1; }
|
|
118
|
+
50% { opacity: 0.5; }
|
|
119
|
+
}
|
|
120
|
+
.info {
|
|
121
|
+
background: #1a1a1a;
|
|
122
|
+
border-radius: 8px;
|
|
123
|
+
padding: 1.5rem;
|
|
124
|
+
margin-top: 2rem;
|
|
125
|
+
text-align: left;
|
|
126
|
+
}
|
|
127
|
+
.info h2 { font-size: 1.2rem; margin-bottom: 1rem; }
|
|
128
|
+
.info p { color: #888; line-height: 1.6; margin-bottom: 0.5rem; }
|
|
129
|
+
code {
|
|
130
|
+
background: #0a0a0a;
|
|
131
|
+
padding: 0.2rem 0.4rem;
|
|
132
|
+
border-radius: 4px;
|
|
133
|
+
color: #22c55e;
|
|
134
|
+
font-family: 'Monaco', monospace;
|
|
135
|
+
}
|
|
136
|
+
a { color: #3b82f6; text-decoration: none; }
|
|
137
|
+
a:hover { text-decoration: underline; }
|
|
138
|
+
</style>
|
|
139
|
+
</head>
|
|
140
|
+
<body>
|
|
141
|
+
<div class="container">
|
|
142
|
+
<h1>🔮 Vision Dashboard</h1>
|
|
143
|
+
<div class="status">
|
|
144
|
+
<span class="dot"></span>
|
|
145
|
+
<span id="status">Connected to WebSocket</span>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div class="info">
|
|
149
|
+
<h2>Dashboard UI Coming Soon!</h2>
|
|
150
|
+
<p>The Vision Dashboard backend is running and ready.</p>
|
|
151
|
+
<p>The React UI is currently in development. For now, you can:</p>
|
|
152
|
+
<ul style="margin-top: 1rem; padding-left: 1.5rem; color: #888;">
|
|
153
|
+
<li>Connect via WebSocket at <code>ws://${this.options.host}:${this.options.port}</code></li>
|
|
154
|
+
<li>Use JSON-RPC methods: <code>status</code>, <code>traces/list</code>, <code>routes/list</code></li>
|
|
155
|
+
<li>Watch traces in real-time as requests come in</li>
|
|
156
|
+
</ul>
|
|
157
|
+
<p style="margin-top: 1rem;">
|
|
158
|
+
See <a href="https://github.com/yourusername/vision" target="_blank">documentation</a> for more info.
|
|
159
|
+
</p>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<script>
|
|
164
|
+
const ws = new WebSocket('ws://${this.options.host}:${this.options.port}');
|
|
165
|
+
const status = document.getElementById('status');
|
|
166
|
+
|
|
167
|
+
ws.onopen = () => {
|
|
168
|
+
status.textContent = 'Connected to WebSocket ✓';
|
|
169
|
+
console.log('🔮 Connected to Vision Dashboard');
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
ws.onclose = () => {
|
|
173
|
+
status.textContent = 'Disconnected';
|
|
174
|
+
status.style.color = '#ef4444';
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
ws.onmessage = (event) => {
|
|
178
|
+
const data = JSON.parse(event.data);
|
|
179
|
+
console.log('📨 Message:', data);
|
|
180
|
+
};
|
|
181
|
+
</script>
|
|
182
|
+
</body>
|
|
183
|
+
</html>`;
|
|
184
|
+
}
|
|
185
|
+
setupServer() {
|
|
186
|
+
// Start HTTP server
|
|
187
|
+
this.httpServer.listen(this.options.port, this.options.host, () => {
|
|
188
|
+
console.log(`🚀 Vision Dashboard running at http://${this.options.host}:${this.options.port}`);
|
|
189
|
+
console.log(` WebSocket: ws://${this.options.host}:${this.options.port}/ws`);
|
|
190
|
+
});
|
|
191
|
+
// Handle WebSocket connections
|
|
192
|
+
this.wss.on('connection', (ws) => {
|
|
193
|
+
console.log('🔌 Dashboard client connected');
|
|
194
|
+
this.clients.add(ws);
|
|
195
|
+
ws.on('message', async (data) => {
|
|
196
|
+
const message = data.toString();
|
|
197
|
+
const response = await this.rpc.handle(message);
|
|
198
|
+
if (response) {
|
|
199
|
+
ws.send(response);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
ws.on('close', () => {
|
|
203
|
+
console.log('🔌 Dashboard client disconnected');
|
|
204
|
+
this.clients.delete(ws);
|
|
205
|
+
});
|
|
206
|
+
ws.on('error', (error) => {
|
|
207
|
+
console.error('WebSocket error:', error);
|
|
208
|
+
this.clients.delete(ws);
|
|
209
|
+
});
|
|
210
|
+
// Send initial connection success
|
|
211
|
+
ws.send(JSON.stringify({
|
|
212
|
+
jsonrpc: '2.0',
|
|
213
|
+
method: 'connection.established',
|
|
214
|
+
params: { timestamp: Date.now() },
|
|
215
|
+
}));
|
|
216
|
+
});
|
|
217
|
+
this.wss.on('error', (error) => {
|
|
218
|
+
console.error('WebSocket server error:', error);
|
|
219
|
+
});
|
|
220
|
+
this.httpServer.on('error', (error) => {
|
|
221
|
+
console.error('HTTP server error:', error);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Register a JSON-RPC method handler
|
|
226
|
+
*/
|
|
227
|
+
registerMethod(method, handler) {
|
|
228
|
+
this.rpc.register(method, handler);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Broadcast an event to all connected clients
|
|
232
|
+
*/
|
|
233
|
+
broadcast(event) {
|
|
234
|
+
const notification = this.rpc.createNotification(event.type, event.data);
|
|
235
|
+
this.clients.forEach((client) => {
|
|
236
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
237
|
+
client.send(notification);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Get number of connected clients
|
|
243
|
+
*/
|
|
244
|
+
getClientCount() {
|
|
245
|
+
return this.clients.size;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Close the server
|
|
249
|
+
*/
|
|
250
|
+
async close() {
|
|
251
|
+
return new Promise((resolve, reject) => {
|
|
252
|
+
this.clients.forEach((client) => client.close());
|
|
253
|
+
this.clients.clear();
|
|
254
|
+
this.wss.close((wsError) => {
|
|
255
|
+
this.httpServer.close((httpError) => {
|
|
256
|
+
if (wsError || httpError) {
|
|
257
|
+
reject(wsError || httpError);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
console.log('✅ Vision Dashboard server closed');
|
|
261
|
+
resolve();
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tracing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Trace, Span } from '../types/index';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory trace store
|
|
4
|
+
* Stores traces with automatic cleanup when max limit is reached
|
|
5
|
+
*/
|
|
6
|
+
export declare class TraceStore {
|
|
7
|
+
private traces;
|
|
8
|
+
private maxTraces;
|
|
9
|
+
constructor(maxTraces?: number);
|
|
10
|
+
/**
|
|
11
|
+
* Create a new trace
|
|
12
|
+
*/
|
|
13
|
+
createTrace(method: string, path: string): Trace;
|
|
14
|
+
/**
|
|
15
|
+
* Add a trace to the store
|
|
16
|
+
*/
|
|
17
|
+
addTrace(trace: Trace): void;
|
|
18
|
+
/**
|
|
19
|
+
* Add a span to a trace
|
|
20
|
+
*/
|
|
21
|
+
addSpan(traceId: string, span: Span): void;
|
|
22
|
+
/**
|
|
23
|
+
* Complete a trace with final data
|
|
24
|
+
*/
|
|
25
|
+
completeTrace(traceId: string, statusCode: number, duration: number): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get a trace by ID
|
|
28
|
+
*/
|
|
29
|
+
getTrace(id: string): Trace | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Get all traces (newest first)
|
|
32
|
+
*/
|
|
33
|
+
getAllTraces(): Trace[];
|
|
34
|
+
/**
|
|
35
|
+
* Get traces with filters
|
|
36
|
+
*/
|
|
37
|
+
getTraces(filter?: {
|
|
38
|
+
method?: string;
|
|
39
|
+
statusCode?: number;
|
|
40
|
+
minDuration?: number;
|
|
41
|
+
limit?: number;
|
|
42
|
+
}): Trace[];
|
|
43
|
+
/**
|
|
44
|
+
* Clear all traces
|
|
45
|
+
*/
|
|
46
|
+
clear(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Get trace count
|
|
49
|
+
*/
|
|
50
|
+
count(): number;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tracing/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAEjD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAQ;gBAEb,SAAS,SAAO;IAI5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK;IAahD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAY5B;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;IAO1C;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQ1E;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIvC;;OAEG;IACH,YAAY,IAAI,KAAK,EAAE;IAIvB;;OAEG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE;QACjB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,GAAG,KAAK,EAAE;IAsBX;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory trace store
|
|
4
|
+
* Stores traces with automatic cleanup when max limit is reached
|
|
5
|
+
*/
|
|
6
|
+
export class TraceStore {
|
|
7
|
+
traces = new Map();
|
|
8
|
+
maxTraces;
|
|
9
|
+
constructor(maxTraces = 1000) {
|
|
10
|
+
this.maxTraces = maxTraces;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create a new trace
|
|
14
|
+
*/
|
|
15
|
+
createTrace(method, path) {
|
|
16
|
+
const trace = {
|
|
17
|
+
id: nanoid(),
|
|
18
|
+
timestamp: Date.now(),
|
|
19
|
+
method,
|
|
20
|
+
path,
|
|
21
|
+
spans: [],
|
|
22
|
+
};
|
|
23
|
+
this.addTrace(trace);
|
|
24
|
+
return trace;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Add a trace to the store
|
|
28
|
+
*/
|
|
29
|
+
addTrace(trace) {
|
|
30
|
+
// Remove oldest trace if we've hit the limit
|
|
31
|
+
if (this.traces.size >= this.maxTraces) {
|
|
32
|
+
const oldestKey = this.traces.keys().next().value;
|
|
33
|
+
if (oldestKey) {
|
|
34
|
+
this.traces.delete(oldestKey);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
this.traces.set(trace.id, trace);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Add a span to a trace
|
|
41
|
+
*/
|
|
42
|
+
addSpan(traceId, span) {
|
|
43
|
+
const trace = this.traces.get(traceId);
|
|
44
|
+
if (trace) {
|
|
45
|
+
trace.spans.push(span);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Complete a trace with final data
|
|
50
|
+
*/
|
|
51
|
+
completeTrace(traceId, statusCode, duration) {
|
|
52
|
+
const trace = this.traces.get(traceId);
|
|
53
|
+
if (trace) {
|
|
54
|
+
trace.statusCode = statusCode;
|
|
55
|
+
trace.duration = duration;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get a trace by ID
|
|
60
|
+
*/
|
|
61
|
+
getTrace(id) {
|
|
62
|
+
return this.traces.get(id);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all traces (newest first)
|
|
66
|
+
*/
|
|
67
|
+
getAllTraces() {
|
|
68
|
+
return Array.from(this.traces.values()).reverse();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get traces with filters
|
|
72
|
+
*/
|
|
73
|
+
getTraces(filter) {
|
|
74
|
+
let traces = this.getAllTraces();
|
|
75
|
+
if (filter?.method) {
|
|
76
|
+
traces = traces.filter((t) => t.method === filter.method);
|
|
77
|
+
}
|
|
78
|
+
if (filter?.statusCode) {
|
|
79
|
+
traces = traces.filter((t) => t.statusCode === filter.statusCode);
|
|
80
|
+
}
|
|
81
|
+
if (filter?.minDuration) {
|
|
82
|
+
traces = traces.filter((t) => (t.duration ?? 0) >= filter.minDuration);
|
|
83
|
+
}
|
|
84
|
+
if (filter?.limit) {
|
|
85
|
+
traces = traces.slice(0, filter.limit);
|
|
86
|
+
}
|
|
87
|
+
return traces;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Clear all traces
|
|
91
|
+
*/
|
|
92
|
+
clear() {
|
|
93
|
+
this.traces.clear();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get trace count
|
|
97
|
+
*/
|
|
98
|
+
count() {
|
|
99
|
+
return this.traces.size;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Span } from '../types/index';
|
|
2
|
+
/**
|
|
3
|
+
* Tracer for creating and managing spans
|
|
4
|
+
*/
|
|
5
|
+
export declare class Tracer {
|
|
6
|
+
private activeSpans;
|
|
7
|
+
/**
|
|
8
|
+
* Start a new span
|
|
9
|
+
*/
|
|
10
|
+
startSpan(name: string, traceId: string, parentId?: string): Span;
|
|
11
|
+
/**
|
|
12
|
+
* End a span
|
|
13
|
+
*/
|
|
14
|
+
endSpan(spanId: string): Span | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Add an attribute to a span
|
|
17
|
+
*/
|
|
18
|
+
setAttribute(spanId: string, key: string, value: unknown): void;
|
|
19
|
+
/**
|
|
20
|
+
* Add an event to a span
|
|
21
|
+
*/
|
|
22
|
+
addEvent(spanId: string, name: string, attributes?: Record<string, unknown>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get an active span
|
|
25
|
+
*/
|
|
26
|
+
getSpan(spanId: string): Span | undefined;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../src/tracing/tracer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAa,MAAM,gBAAgB,CAAA;AAErD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,WAAW,CAA0B;IAE7C;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAejE;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAUzC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAO/D;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYlF;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;CAG1C"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
/**
|
|
3
|
+
* Tracer for creating and managing spans
|
|
4
|
+
*/
|
|
5
|
+
export class Tracer {
|
|
6
|
+
activeSpans = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Start a new span
|
|
9
|
+
*/
|
|
10
|
+
startSpan(name, traceId, parentId) {
|
|
11
|
+
const span = {
|
|
12
|
+
id: nanoid(),
|
|
13
|
+
traceId,
|
|
14
|
+
parentId,
|
|
15
|
+
name,
|
|
16
|
+
startTime: Date.now(),
|
|
17
|
+
attributes: {},
|
|
18
|
+
events: [],
|
|
19
|
+
};
|
|
20
|
+
this.activeSpans.set(span.id, span);
|
|
21
|
+
return span;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* End a span
|
|
25
|
+
*/
|
|
26
|
+
endSpan(spanId) {
|
|
27
|
+
const span = this.activeSpans.get(spanId);
|
|
28
|
+
if (span) {
|
|
29
|
+
span.endTime = Date.now();
|
|
30
|
+
span.duration = span.endTime - span.startTime;
|
|
31
|
+
this.activeSpans.delete(spanId);
|
|
32
|
+
}
|
|
33
|
+
return span;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Add an attribute to a span
|
|
37
|
+
*/
|
|
38
|
+
setAttribute(spanId, key, value) {
|
|
39
|
+
const span = this.activeSpans.get(spanId);
|
|
40
|
+
if (span && span.attributes) {
|
|
41
|
+
span.attributes[key] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Add an event to a span
|
|
46
|
+
*/
|
|
47
|
+
addEvent(spanId, name, attributes) {
|
|
48
|
+
const span = this.activeSpans.get(spanId);
|
|
49
|
+
if (span) {
|
|
50
|
+
const event = {
|
|
51
|
+
name,
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
attributes,
|
|
54
|
+
};
|
|
55
|
+
span.events?.push(event);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get an active span
|
|
60
|
+
*/
|
|
61
|
+
getSpan(spanId) {
|
|
62
|
+
return this.activeSpans.get(spanId);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified adapter options and types
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Service configuration
|
|
6
|
+
*/
|
|
7
|
+
export interface ServiceConfig {
|
|
8
|
+
name?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
integrations?: IntegrationConfig;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Integration configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface IntegrationConfig {
|
|
17
|
+
database?: string;
|
|
18
|
+
redis?: string;
|
|
19
|
+
[key: string]: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Drizzle Studio configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface DrizzleConfig {
|
|
25
|
+
autoStart?: boolean;
|
|
26
|
+
port?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Service definition for manual grouping
|
|
30
|
+
*/
|
|
31
|
+
export interface ServiceDefinition {
|
|
32
|
+
name: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
routes: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Base adapter options (common to all adapters)
|
|
38
|
+
*/
|
|
39
|
+
export interface BaseAdapterOptions {
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
port?: number;
|
|
42
|
+
maxTraces?: number;
|
|
43
|
+
logging?: boolean;
|
|
44
|
+
service?: ServiceConfig;
|
|
45
|
+
services?: ServiceDefinition[];
|
|
46
|
+
drizzle?: DrizzleConfig;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Hono adapter options
|
|
50
|
+
*/
|
|
51
|
+
export interface VisionHonoOptions extends BaseAdapterOptions {
|
|
52
|
+
name?: string;
|
|
53
|
+
maxTraces?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Express adapter options
|
|
57
|
+
*/
|
|
58
|
+
export interface VisionExpressOptions extends BaseAdapterOptions {
|
|
59
|
+
maxLogs?: number;
|
|
60
|
+
cors?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fastify adapter options
|
|
64
|
+
*/
|
|
65
|
+
export interface VisionFastifyOptions extends BaseAdapterOptions {
|
|
66
|
+
maxLogs?: number;
|
|
67
|
+
cors?: boolean;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=adapter-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-options.d.ts","sourceRoot":"","sources":["../../src/types/adapter-options.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC9B,OAAO,CAAC,EAAE,aAAa,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf"}
|