@getvision/core 0.0.0 → 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/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 @@
|
|
|
1
|
+
{"version":3,"file":"core.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/core.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { VisionCore } from '../core';
|
|
3
|
+
describe('VisionCore (without server)', () => {
|
|
4
|
+
test('should create and complete trace', () => {
|
|
5
|
+
const vision = new VisionCore({
|
|
6
|
+
port: 0,
|
|
7
|
+
maxTraces: 100,
|
|
8
|
+
captureConsole: false
|
|
9
|
+
});
|
|
10
|
+
const trace = vision.createTrace('GET', '/test');
|
|
11
|
+
expect(trace).toBeDefined();
|
|
12
|
+
expect(trace.id).toBeDefined();
|
|
13
|
+
// Complete trace
|
|
14
|
+
vision.completeTrace(trace.id, 200, 50);
|
|
15
|
+
// Retrieve trace from store
|
|
16
|
+
const retrieved = vision.getTraceStore().getTrace(trace.id);
|
|
17
|
+
expect(retrieved).toBeDefined();
|
|
18
|
+
});
|
|
19
|
+
test('should use tracer', () => {
|
|
20
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
21
|
+
const tracer = vision.getTracer();
|
|
22
|
+
expect(tracer).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
test('should create span helper', () => {
|
|
25
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
26
|
+
const trace = vision.createTrace('GET', '/test');
|
|
27
|
+
const withSpan = vision.createSpanHelper(trace.id);
|
|
28
|
+
const result = withSpan('test.operation', { 'test.attr': 'value' }, () => {
|
|
29
|
+
return 'test result';
|
|
30
|
+
});
|
|
31
|
+
expect(result).toBe('test result');
|
|
32
|
+
// Check span was added
|
|
33
|
+
const retrieved = vision.getTraceStore().getTrace(trace.id);
|
|
34
|
+
expect(retrieved?.spans.length).toBeGreaterThan(0);
|
|
35
|
+
expect(retrieved?.spans[0].name).toBe('test.operation');
|
|
36
|
+
});
|
|
37
|
+
test('should handle errors in span helper', () => {
|
|
38
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
39
|
+
const trace = vision.createTrace('GET', '/test');
|
|
40
|
+
const withSpan = vision.createSpanHelper(trace.id);
|
|
41
|
+
expect(() => {
|
|
42
|
+
withSpan('test.error', {}, () => {
|
|
43
|
+
throw new Error('Test error');
|
|
44
|
+
});
|
|
45
|
+
}).toThrow('Test error');
|
|
46
|
+
// Check error was recorded in span
|
|
47
|
+
const retrieved = vision.getTraceStore().getTrace(trace.id);
|
|
48
|
+
const errorSpan = retrieved?.spans[0];
|
|
49
|
+
expect(errorSpan?.attributes?.error).toBe(true);
|
|
50
|
+
expect(errorSpan?.attributes?.['error.message']).toBe('Test error');
|
|
51
|
+
});
|
|
52
|
+
test('should register routes', () => {
|
|
53
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
54
|
+
const routes = [
|
|
55
|
+
{ method: 'GET', path: '/users', handler: 'getUsers' },
|
|
56
|
+
{ method: 'POST', path: '/users', handler: 'createUser' },
|
|
57
|
+
];
|
|
58
|
+
vision.registerRoutes(routes);
|
|
59
|
+
// Routes are registered, no easy way to verify without getter
|
|
60
|
+
expect(true).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
test('should set app status', () => {
|
|
63
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
64
|
+
vision.setAppStatus({
|
|
65
|
+
name: 'Test App',
|
|
66
|
+
version: '1.0.0',
|
|
67
|
+
environment: 'test',
|
|
68
|
+
running: true,
|
|
69
|
+
});
|
|
70
|
+
expect(true).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
test('should log messages', () => {
|
|
73
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
74
|
+
const entry = vision.log('info', 'Test log message', { key: 'value' });
|
|
75
|
+
expect(entry).toBeDefined();
|
|
76
|
+
expect(entry.level).toBe('info');
|
|
77
|
+
expect(entry.message).toBe('Test log message');
|
|
78
|
+
});
|
|
79
|
+
test('should broadcast events', () => {
|
|
80
|
+
const vision = new VisionCore({ port: 0, captureConsole: false });
|
|
81
|
+
// Just test that broadcast doesn't throw
|
|
82
|
+
vision.broadcast({
|
|
83
|
+
type: 'log.entry',
|
|
84
|
+
data: { id: "id", message: 'hello', level: "info", timestamp: Date.now() }
|
|
85
|
+
});
|
|
86
|
+
expect(true).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tracing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
2
|
+
import { TraceStore, Tracer } from '../tracing/index';
|
|
3
|
+
describe('TraceStore', () => {
|
|
4
|
+
let store;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
store = new TraceStore(100);
|
|
7
|
+
});
|
|
8
|
+
test('should add trace', () => {
|
|
9
|
+
const trace = {
|
|
10
|
+
id: '123',
|
|
11
|
+
timestamp: Date.now(),
|
|
12
|
+
spans: [],
|
|
13
|
+
method: 'GET',
|
|
14
|
+
path: '/test',
|
|
15
|
+
metadata: {},
|
|
16
|
+
};
|
|
17
|
+
store.addTrace(trace);
|
|
18
|
+
const retrieved = store.getTrace('123');
|
|
19
|
+
expect(retrieved).toBeDefined();
|
|
20
|
+
expect(retrieved?.id).toBe('123');
|
|
21
|
+
expect(retrieved?.path).toBe('/test');
|
|
22
|
+
expect(retrieved?.method).toBe('GET');
|
|
23
|
+
});
|
|
24
|
+
test('should get traces with filters', () => {
|
|
25
|
+
const trace1 = {
|
|
26
|
+
id: '1',
|
|
27
|
+
method: 'GET',
|
|
28
|
+
path: '/users',
|
|
29
|
+
statusCode: 200,
|
|
30
|
+
timestamp: Date.now(),
|
|
31
|
+
spans: [],
|
|
32
|
+
metadata: {},
|
|
33
|
+
};
|
|
34
|
+
const trace2 = {
|
|
35
|
+
id: '2',
|
|
36
|
+
timestamp: Date.now(),
|
|
37
|
+
spans: [],
|
|
38
|
+
metadata: {},
|
|
39
|
+
method: 'POST',
|
|
40
|
+
path: '/users',
|
|
41
|
+
statusCode: 201
|
|
42
|
+
};
|
|
43
|
+
store.addTrace(trace1);
|
|
44
|
+
store.addTrace(trace2);
|
|
45
|
+
const getTraces = store.getTraces({ method: 'GET' });
|
|
46
|
+
expect(getTraces.length).toBe(1);
|
|
47
|
+
expect(getTraces[0].id).toBe('1');
|
|
48
|
+
const postTraces = store.getTraces({ method: 'POST' });
|
|
49
|
+
expect(postTraces.length).toBe(1);
|
|
50
|
+
expect(postTraces[0].id).toBe('2');
|
|
51
|
+
});
|
|
52
|
+
test('should limit number of traces', () => {
|
|
53
|
+
const smallStore = new TraceStore(2);
|
|
54
|
+
for (let i = 0; i < 5; i++) {
|
|
55
|
+
smallStore.addTrace({
|
|
56
|
+
id: `trace-${i}`,
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
method: "GET",
|
|
59
|
+
path: '/test',
|
|
60
|
+
spans: [],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const traces = smallStore.getAllTraces();
|
|
64
|
+
expect(traces.length).toBeLessThanOrEqual(2);
|
|
65
|
+
});
|
|
66
|
+
test('should clear all traces', () => {
|
|
67
|
+
store.addTrace({
|
|
68
|
+
id: '1',
|
|
69
|
+
timestamp: Date.now(),
|
|
70
|
+
method: "GET",
|
|
71
|
+
path: '/test',
|
|
72
|
+
spans: [],
|
|
73
|
+
});
|
|
74
|
+
store.clear();
|
|
75
|
+
const traces = store.getAllTraces();
|
|
76
|
+
expect(traces.length).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
test('should filter by status code', () => {
|
|
79
|
+
store.addTrace({
|
|
80
|
+
id: '1',
|
|
81
|
+
timestamp: Date.now(),
|
|
82
|
+
spans: [],
|
|
83
|
+
method: "GET",
|
|
84
|
+
path: '/test',
|
|
85
|
+
statusCode: 200,
|
|
86
|
+
metadata: {},
|
|
87
|
+
});
|
|
88
|
+
store.addTrace({
|
|
89
|
+
id: '2',
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
spans: [],
|
|
92
|
+
method: "GET",
|
|
93
|
+
path: '/test2',
|
|
94
|
+
statusCode: 200,
|
|
95
|
+
metadata: {},
|
|
96
|
+
});
|
|
97
|
+
const successTraces = store.getTraces({ statusCode: 200 });
|
|
98
|
+
expect(successTraces.length).toBe(2);
|
|
99
|
+
expect(successTraces[0]?.statusCode).toBe(200);
|
|
100
|
+
expect(successTraces[1]?.statusCode).toBe(200);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('Tracer', () => {
|
|
104
|
+
test('should create tracer instance', () => {
|
|
105
|
+
const tracer = new Tracer();
|
|
106
|
+
expect(tracer).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { VisionWebSocketServer } from './server';
|
|
2
|
+
import { TraceStore, Tracer } from './tracing';
|
|
3
|
+
import { LogStore } from './logs/store';
|
|
4
|
+
import type { VisionServerOptions, AppStatus, RouteMetadata, ServiceGroup, Trace, DashboardEvent, LogLevel, LogEntry } from './types/index';
|
|
5
|
+
/**
|
|
6
|
+
* VisionCore - Main orchestrator for the Vision Dashboard
|
|
7
|
+
*/
|
|
8
|
+
export declare class VisionCore {
|
|
9
|
+
private server;
|
|
10
|
+
private traceStore;
|
|
11
|
+
private tracer;
|
|
12
|
+
private logStore;
|
|
13
|
+
private consoleInterceptor?;
|
|
14
|
+
private routes;
|
|
15
|
+
private services;
|
|
16
|
+
private appStatus;
|
|
17
|
+
constructor(options?: VisionServerOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Register all JSON-RPC methods
|
|
20
|
+
*/
|
|
21
|
+
private registerMethods;
|
|
22
|
+
/**
|
|
23
|
+
* Update app status
|
|
24
|
+
*/
|
|
25
|
+
setAppStatus(status: Partial<AppStatus>): void;
|
|
26
|
+
/**
|
|
27
|
+
* Register routes from adapter
|
|
28
|
+
*/
|
|
29
|
+
registerRoutes(routes: RouteMetadata[]): void;
|
|
30
|
+
/**
|
|
31
|
+
* Register grouped services
|
|
32
|
+
*/
|
|
33
|
+
registerServices(services: ServiceGroup[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new trace
|
|
36
|
+
*/
|
|
37
|
+
createTrace(method: string, path: string): Trace;
|
|
38
|
+
/**
|
|
39
|
+
* Complete a trace
|
|
40
|
+
*/
|
|
41
|
+
completeTrace(traceId: string, statusCode: number, duration: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Get tracer instance
|
|
44
|
+
*/
|
|
45
|
+
getTracer(): Tracer;
|
|
46
|
+
/**
|
|
47
|
+
* Get WebSocket server instance (for registering JSON-RPC methods)
|
|
48
|
+
*/
|
|
49
|
+
getServer(): VisionWebSocketServer;
|
|
50
|
+
/**
|
|
51
|
+
* Create a span helper for easy span creation
|
|
52
|
+
* @param traceId - Trace ID to attach spans to
|
|
53
|
+
* @returns A function that creates spans with automatic error handling
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* const withSpan = vision.createSpanHelper(traceId)
|
|
58
|
+
*
|
|
59
|
+
* const user = withSpan('db.select', { 'db.system': 'sqlite' }, () => {
|
|
60
|
+
* return db.select().from(users).get()
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
createSpanHelper(traceId: string): <T>(name: string, attributes: Record<string, any> | undefined, fn: () => T) => T;
|
|
65
|
+
/**
|
|
66
|
+
* Get trace store
|
|
67
|
+
*/
|
|
68
|
+
getTraceStore(): TraceStore;
|
|
69
|
+
/**
|
|
70
|
+
* Universal log API - can be called by any logger
|
|
71
|
+
*/
|
|
72
|
+
log(level: LogLevel, message: string, meta?: Record<string, any>): LogEntry;
|
|
73
|
+
/**
|
|
74
|
+
* Get log store instance
|
|
75
|
+
*/
|
|
76
|
+
getLogStore(): LogStore;
|
|
77
|
+
/**
|
|
78
|
+
* Broadcast event to all connected clients
|
|
79
|
+
*/
|
|
80
|
+
broadcast(event: DashboardEvent): void;
|
|
81
|
+
/**
|
|
82
|
+
* Log stdout message
|
|
83
|
+
*/
|
|
84
|
+
logStdout(message: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Log stderr message
|
|
87
|
+
*/
|
|
88
|
+
logStderr(message: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* Get number of connected dashboard clients
|
|
91
|
+
*/
|
|
92
|
+
getClientCount(): number;
|
|
93
|
+
/**
|
|
94
|
+
* Close the Vision server
|
|
95
|
+
*/
|
|
96
|
+
close(): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,KAAK,EACV,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,KAAK,EACL,cAAc,EACd,QAAQ,EACR,QAAQ,EACT,MAAM,eAAe,CAAA;AAEtB;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,kBAAkB,CAAC,CAAoB;IAC/C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAKhB;gBAEW,OAAO,GAAE,mBAAwB;IAwB7C;;OAEG;IACH,OAAO,CAAC,eAAe;IA0FvB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAK9C;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI;IAI7C;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIhD;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK;IAKhD;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAS1E;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,qBAAqB;IAIlC;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,IACtB,CAAC,EACP,MAAM,MAAM,EACZ,YAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAAK,EACpC,IAAI,MAAM,CAAC,KACV,CAAC;IAqCN;;OAEG;IACH,aAAa,IAAI,UAAU;IAI3B;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,QAAQ;IAU3E;;OAEG;IACH,WAAW,IAAI,QAAQ;IAIvB;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAItC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { VisionWebSocketServer } from './server';
|
|
2
|
+
import { TraceStore, Tracer } from './tracing';
|
|
3
|
+
import { LogStore } from './logs/store';
|
|
4
|
+
import { ConsoleInterceptor } from './logs/interceptor';
|
|
5
|
+
/**
|
|
6
|
+
* VisionCore - Main orchestrator for the Vision Dashboard
|
|
7
|
+
*/
|
|
8
|
+
export class VisionCore {
|
|
9
|
+
server;
|
|
10
|
+
traceStore;
|
|
11
|
+
tracer;
|
|
12
|
+
logStore;
|
|
13
|
+
consoleInterceptor;
|
|
14
|
+
routes = [];
|
|
15
|
+
services = [];
|
|
16
|
+
appStatus = {
|
|
17
|
+
name: 'Unknown',
|
|
18
|
+
version: '0.0.0',
|
|
19
|
+
environment: 'development',
|
|
20
|
+
running: false,
|
|
21
|
+
};
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.server = new VisionWebSocketServer(options);
|
|
24
|
+
this.traceStore = new TraceStore(options.maxTraces);
|
|
25
|
+
this.tracer = new Tracer();
|
|
26
|
+
this.logStore = new LogStore(options.maxLogs);
|
|
27
|
+
// Optional console intercept
|
|
28
|
+
if (options.captureConsole !== false) {
|
|
29
|
+
this.consoleInterceptor = new ConsoleInterceptor(this.logStore, () => {
|
|
30
|
+
// Broadcast latest log entry to connected clients
|
|
31
|
+
this.broadcast({
|
|
32
|
+
type: 'log.entry',
|
|
33
|
+
data: this.logStore.getLogs({ limit: 1 })[0]
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
this.consoleInterceptor.start();
|
|
37
|
+
}
|
|
38
|
+
this.registerMethods();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Register all JSON-RPC methods
|
|
42
|
+
*/
|
|
43
|
+
registerMethods() {
|
|
44
|
+
// App status
|
|
45
|
+
this.server.registerMethod('status', async () => {
|
|
46
|
+
return this.appStatus;
|
|
47
|
+
});
|
|
48
|
+
// List all traces
|
|
49
|
+
this.server.registerMethod('traces/list', async (params) => {
|
|
50
|
+
return this.traceStore.getTraces({
|
|
51
|
+
method: params?.method,
|
|
52
|
+
statusCode: params?.statusCode,
|
|
53
|
+
minDuration: params?.minDuration,
|
|
54
|
+
limit: params?.limit ?? 100,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
// Get specific trace
|
|
58
|
+
this.server.registerMethod('traces/get', async (params) => {
|
|
59
|
+
if (!params?.traceId) {
|
|
60
|
+
throw new Error('traceId is required');
|
|
61
|
+
}
|
|
62
|
+
return this.traceStore.getTrace(params.traceId);
|
|
63
|
+
});
|
|
64
|
+
// Clear traces
|
|
65
|
+
this.server.registerMethod('traces/clear', async () => {
|
|
66
|
+
this.traceStore.clear();
|
|
67
|
+
return { success: true };
|
|
68
|
+
});
|
|
69
|
+
// Export traces
|
|
70
|
+
this.server.registerMethod('traces/export', async (params) => {
|
|
71
|
+
const format = params?.format || 'json';
|
|
72
|
+
const traces = this.traceStore.getAllTraces();
|
|
73
|
+
if (format === 'ndjson') {
|
|
74
|
+
return traces.map(t => JSON.stringify(t)).join('\n');
|
|
75
|
+
}
|
|
76
|
+
return JSON.stringify(traces, null, 2);
|
|
77
|
+
});
|
|
78
|
+
// Get routes
|
|
79
|
+
this.server.registerMethod('routes/list', async () => {
|
|
80
|
+
return this.routes;
|
|
81
|
+
});
|
|
82
|
+
// Get services (grouped routes)
|
|
83
|
+
this.server.registerMethod('services/list', async () => {
|
|
84
|
+
return this.services;
|
|
85
|
+
});
|
|
86
|
+
// Get version
|
|
87
|
+
this.server.registerMethod('version', async () => {
|
|
88
|
+
return {
|
|
89
|
+
version: '0.0.1',
|
|
90
|
+
name: 'Vision Dashboard',
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
// Logs methods
|
|
94
|
+
this.server.registerMethod('logs/list', async (params) => {
|
|
95
|
+
return this.logStore.getLogs({
|
|
96
|
+
level: params?.level,
|
|
97
|
+
search: params?.search,
|
|
98
|
+
limit: params?.limit ?? 100,
|
|
99
|
+
since: params?.since,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
this.server.registerMethod('logs/clear', async () => {
|
|
103
|
+
this.logStore.clear();
|
|
104
|
+
return { success: true };
|
|
105
|
+
});
|
|
106
|
+
this.server.registerMethod('traces/addClientMetrics', async (params) => {
|
|
107
|
+
const { traceId, clientDuration } = params;
|
|
108
|
+
if (!traceId || typeof clientDuration !== 'number') {
|
|
109
|
+
throw new Error('traceId and clientDuration are required');
|
|
110
|
+
}
|
|
111
|
+
const trace = this.traceStore.getTrace(traceId);
|
|
112
|
+
if (trace) {
|
|
113
|
+
trace.metadata = { ...(trace.metadata || {}), clientDuration };
|
|
114
|
+
}
|
|
115
|
+
return { success: true };
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Update app status
|
|
120
|
+
*/
|
|
121
|
+
setAppStatus(status) {
|
|
122
|
+
this.appStatus = { ...this.appStatus, ...status };
|
|
123
|
+
this.broadcast({ type: 'app.started', data: this.appStatus });
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Register routes from adapter
|
|
127
|
+
*/
|
|
128
|
+
registerRoutes(routes) {
|
|
129
|
+
this.routes = routes;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Register grouped services
|
|
133
|
+
*/
|
|
134
|
+
registerServices(services) {
|
|
135
|
+
this.services = services;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create a new trace
|
|
139
|
+
*/
|
|
140
|
+
createTrace(method, path) {
|
|
141
|
+
const trace = this.traceStore.createTrace(method, path);
|
|
142
|
+
return trace;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Complete a trace
|
|
146
|
+
*/
|
|
147
|
+
completeTrace(traceId, statusCode, duration) {
|
|
148
|
+
this.traceStore.completeTrace(traceId, statusCode, duration);
|
|
149
|
+
const trace = this.traceStore.getTrace(traceId);
|
|
150
|
+
if (trace) {
|
|
151
|
+
this.broadcast({ type: 'trace.new', data: trace });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get tracer instance
|
|
156
|
+
*/
|
|
157
|
+
getTracer() {
|
|
158
|
+
return this.tracer;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get WebSocket server instance (for registering JSON-RPC methods)
|
|
162
|
+
*/
|
|
163
|
+
getServer() {
|
|
164
|
+
return this.server;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a span helper for easy span creation
|
|
168
|
+
* @param traceId - Trace ID to attach spans to
|
|
169
|
+
* @returns A function that creates spans with automatic error handling
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* const withSpan = vision.createSpanHelper(traceId)
|
|
174
|
+
*
|
|
175
|
+
* const user = withSpan('db.select', { 'db.system': 'sqlite' }, () => {
|
|
176
|
+
* return db.select().from(users).get()
|
|
177
|
+
* })
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
createSpanHelper(traceId) {
|
|
181
|
+
return (name, attributes = {}, fn) => {
|
|
182
|
+
const span = this.tracer.startSpan(name, traceId);
|
|
183
|
+
// Add attributes
|
|
184
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
185
|
+
this.tracer.setAttribute(span.id, key, value);
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const result = fn();
|
|
189
|
+
const completedSpan = this.tracer.endSpan(span.id);
|
|
190
|
+
// Add span to trace store
|
|
191
|
+
if (completedSpan) {
|
|
192
|
+
this.traceStore.addSpan(traceId, completedSpan);
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
this.tracer.setAttribute(span.id, 'error', true);
|
|
198
|
+
this.tracer.setAttribute(span.id, 'error.message', error instanceof Error ? error.message : String(error));
|
|
199
|
+
const completedSpan = this.tracer.endSpan(span.id);
|
|
200
|
+
// Add span to trace store even on error
|
|
201
|
+
if (completedSpan) {
|
|
202
|
+
this.traceStore.addSpan(traceId, completedSpan);
|
|
203
|
+
}
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get trace store
|
|
210
|
+
*/
|
|
211
|
+
getTraceStore() {
|
|
212
|
+
return this.traceStore;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Universal log API - can be called by any logger
|
|
216
|
+
*/
|
|
217
|
+
log(level, message, meta) {
|
|
218
|
+
const args = meta ? [meta] : undefined;
|
|
219
|
+
const entry = this.logStore.addLog(level, message, args);
|
|
220
|
+
// Broadcast to connected clients
|
|
221
|
+
this.broadcast({ type: 'log.entry', data: entry });
|
|
222
|
+
return entry;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get log store instance
|
|
226
|
+
*/
|
|
227
|
+
getLogStore() {
|
|
228
|
+
return this.logStore;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Broadcast event to all connected clients
|
|
232
|
+
*/
|
|
233
|
+
broadcast(event) {
|
|
234
|
+
this.server.broadcast(event);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Log stdout message
|
|
238
|
+
*/
|
|
239
|
+
logStdout(message) {
|
|
240
|
+
this.broadcast({
|
|
241
|
+
type: 'log.stdout',
|
|
242
|
+
data: { message, timestamp: Date.now() },
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Log stderr message
|
|
247
|
+
*/
|
|
248
|
+
logStderr(message) {
|
|
249
|
+
this.broadcast({
|
|
250
|
+
type: 'log.stderr',
|
|
251
|
+
data: { message, timestamp: Date.now() },
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get number of connected dashboard clients
|
|
256
|
+
*/
|
|
257
|
+
getClientCount() {
|
|
258
|
+
return this.server.getClientCount();
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Close the Vision server
|
|
262
|
+
*/
|
|
263
|
+
async close() {
|
|
264
|
+
await this.server.close();
|
|
265
|
+
}
|
|
266
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { VisionCore } from './core';
|
|
2
|
+
export { VisionWebSocketServer } from './server/index';
|
|
3
|
+
export { TraceStore, Tracer } from './tracing/index';
|
|
4
|
+
export { generateZodTemplate } from './utils/zod-utils';
|
|
5
|
+
export { autoDetectPackageInfo, autoDetectIntegrations, detectDrizzle, startDrizzleStudio, stopDrizzleStudio, } from './utils/service-detection';
|
|
6
|
+
export type { PackageInfo, IntegrationConfig, DrizzleInfo } from './utils/service-detection';
|
|
7
|
+
export type * from './types/index';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5F,mBAAmB,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logs/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LogStore } from './store';
|
|
2
|
+
import type { LogLevel } from '../types/logs';
|
|
3
|
+
/**
|
|
4
|
+
* Console interceptor to capture logs
|
|
5
|
+
* Preserves original console behavior while storing logs
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConsoleInterceptor {
|
|
8
|
+
private originalConsole;
|
|
9
|
+
private logStore;
|
|
10
|
+
private onLog?;
|
|
11
|
+
constructor(logStore: LogStore, onLog?: (level: LogLevel, message: string, args?: any[], stack?: string) => void);
|
|
12
|
+
/**
|
|
13
|
+
* Start intercepting console methods
|
|
14
|
+
*/
|
|
15
|
+
start(): void;
|
|
16
|
+
/**
|
|
17
|
+
* Stop intercepting and restore original console
|
|
18
|
+
*/
|
|
19
|
+
stop(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../../src/logs/interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAMtB;IAED,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,KAAK,CAAC,CAA0E;gBAE5E,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI;IAKhH;;OAEG;IACH,KAAK,IAAI,IAAI;IA2Cb;;OAEG;IACH,IAAI,IAAI,IAAI;CAOb"}
|