@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
package/dist/index.js
CHANGED
|
@@ -9,112 +9,6 @@ var M=(a,e)=>()=>(e||a((e={exports:{}}).exports,e),e.exports);var L=import.meta.
|
|
|
9
9
|
* Copyright(c) 2014 Jonathan Ong
|
|
10
10
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
11
11
|
* MIT Licensed
|
|
12
|
-
*/var j=O(),X=L("path").extname;var H=Object.create(null),y=G,z=Object.create(null);D(H,z);function G(a){if(!a||typeof a!=="string")return!1;var e=X("x."+a).toLowerCase().substr(1);if(!e)return!1;return z[e]||!1}function D(a,e){var i=["nginx","apache",void 0,"iana"];Object.keys(j).forEach(function(o){var c=j[o],s=c.extensions;if(!s||!s.length)return;a[o]=s;for(var p=0;p<s.length;p++){var t=s[p];if(e[t]){var v=i.indexOf(j[e[t]].source),h=i.indexOf(c.source);if(e[t]!=="application/octet-stream"&&(v>h||v===h&&e[t].substr(0,12)==="application/"))continue}e[t]=o}})}var aa=S(P(import.meta.url));async function Q(a,e,i){let n=a.url||"/",o=n.indexOf("?");if(o!==-1)n=n.substring(0,o);if(n==="/"||!n.includes("."))n="/index.html";let c=q(i,n);if(!c.startsWith(i))return!1;if(!I(c))return!1;try{let s=await E(c),p=y(c)||"application/octet-stream";return e.writeHead(200,{"Content-Type":p,"Cache-Control":"public, max-age=3600"}),e.end(s),!0}catch(s){return console.error("Error serving static file:",s),!1}}function V(){let a=q(aa,"../..");return q(a,"dist/ui")}class b{httpServer;wss;clients=new Set;rpc;options;constructor(a={}){this.options={port:a.port??9500,host:a.host??"localhost",maxTraces:a.maxTraces??1000,maxLogs:a.maxLogs??1e4,captureConsole:a.captureConsole??!0,enableCors:a.enableCors??!0},this.rpc=new w,this.httpServer=na((e,i)=>{this.handleHttp(e,i).catch((n)=>{console.error("HTTP handler error:",n),i.writeHead(500),i.end("Internal Server Error")})}),this.wss=new ea({server:this.httpServer,path:"/ws"}),this.setupServer()}async handleHttp(a,e){if(this.options.enableCors)e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type");if(a.method==="OPTIONS"){e.writeHead(200),e.end();return}if(a.url==="/health"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",clients:this.clients.size}));return}let i=V();if(!await Q(a,e,i))e.writeHead(
|
|
13
|
-
<html lang="en">
|
|
14
|
-
<head>
|
|
15
|
-
<meta charset="UTF-8">
|
|
16
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
-
<title>Vision Dashboard</title>
|
|
18
|
-
<style>
|
|
19
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
20
|
-
body {
|
|
21
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
22
|
-
background: #0a0a0a;
|
|
23
|
-
color: #fff;
|
|
24
|
-
display: flex;
|
|
25
|
-
align-items: center;
|
|
26
|
-
justify-content: center;
|
|
27
|
-
min-height: 100vh;
|
|
28
|
-
}
|
|
29
|
-
.container {
|
|
30
|
-
text-align: center;
|
|
31
|
-
max-width: 600px;
|
|
32
|
-
padding: 2rem;
|
|
33
|
-
}
|
|
34
|
-
h1 { font-size: 2.5rem; margin-bottom: 1rem; }
|
|
35
|
-
.status {
|
|
36
|
-
display: inline-flex;
|
|
37
|
-
align-items: center;
|
|
38
|
-
gap: 0.5rem;
|
|
39
|
-
padding: 0.5rem 1rem;
|
|
40
|
-
background: #1a1a1a;
|
|
41
|
-
border-radius: 8px;
|
|
42
|
-
margin: 1rem 0;
|
|
43
|
-
}
|
|
44
|
-
.dot {
|
|
45
|
-
width: 8px;
|
|
46
|
-
height: 8px;
|
|
47
|
-
border-radius: 50%;
|
|
48
|
-
background: #22c55e;
|
|
49
|
-
animation: pulse 2s infinite;
|
|
50
|
-
}
|
|
51
|
-
@keyframes pulse {
|
|
52
|
-
0%, 100% { opacity: 1; }
|
|
53
|
-
50% { opacity: 0.5; }
|
|
54
|
-
}
|
|
55
|
-
.info {
|
|
56
|
-
background: #1a1a1a;
|
|
57
|
-
border-radius: 8px;
|
|
58
|
-
padding: 1.5rem;
|
|
59
|
-
margin-top: 2rem;
|
|
60
|
-
text-align: left;
|
|
61
|
-
}
|
|
62
|
-
.info h2 { font-size: 1.2rem; margin-bottom: 1rem; }
|
|
63
|
-
.info p { color: #888; line-height: 1.6; margin-bottom: 0.5rem; }
|
|
64
|
-
code {
|
|
65
|
-
background: #0a0a0a;
|
|
66
|
-
padding: 0.2rem 0.4rem;
|
|
67
|
-
border-radius: 4px;
|
|
68
|
-
color: #22c55e;
|
|
69
|
-
font-family: 'Monaco', monospace;
|
|
70
|
-
}
|
|
71
|
-
a { color: #3b82f6; text-decoration: none; }
|
|
72
|
-
a:hover { text-decoration: underline; }
|
|
73
|
-
</style>
|
|
74
|
-
</head>
|
|
75
|
-
<body>
|
|
76
|
-
<div class="container">
|
|
77
|
-
<h1>\uD83D\uDD2E Vision Dashboard</h1>
|
|
78
|
-
<div class="status">
|
|
79
|
-
<span class="dot"></span>
|
|
80
|
-
<span id="status">Connected to WebSocket</span>
|
|
81
|
-
</div>
|
|
82
|
-
|
|
83
|
-
<div class="info">
|
|
84
|
-
<h2>Dashboard UI Coming Soon!</h2>
|
|
85
|
-
<p>The Vision Dashboard backend is running and ready.</p>
|
|
86
|
-
<p>The React UI is currently in development. For now, you can:</p>
|
|
87
|
-
<ul style="margin-top: 1rem; padding-left: 1.5rem; color: #888;">
|
|
88
|
-
<li>Connect via WebSocket at <code>ws://${this.options.host}:${this.options.port}</code></li>
|
|
89
|
-
<li>Use JSON-RPC methods: <code>status</code>, <code>traces/list</code>, <code>routes/list</code></li>
|
|
90
|
-
<li>Watch traces in real-time as requests come in</li>
|
|
91
|
-
</ul>
|
|
92
|
-
<p style="margin-top: 1rem;">
|
|
93
|
-
See <a href="https://github.com/yourusername/vision" target="_blank">documentation</a> for more info.
|
|
94
|
-
</p>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
<script>
|
|
99
|
-
const ws = new WebSocket('ws://${this.options.host}:${this.options.port}');
|
|
100
|
-
const status = document.getElementById('status');
|
|
101
|
-
|
|
102
|
-
ws.onopen = () => {
|
|
103
|
-
status.textContent = 'Connected to WebSocket \u2713';
|
|
104
|
-
console.log('\uD83D\uDD2E Connected to Vision Dashboard');
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
ws.onclose = () => {
|
|
108
|
-
status.textContent = 'Disconnected';
|
|
109
|
-
status.style.color = '#ef4444';
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
ws.onmessage = (event) => {
|
|
113
|
-
const data = JSON.parse(event.data);
|
|
114
|
-
console.log('\uD83D\uDCE8 Message:', data);
|
|
115
|
-
};
|
|
116
|
-
</script>
|
|
117
|
-
</body>
|
|
118
|
-
</html>`}setupServer(){this.httpServer.listen(this.options.port,this.options.host,()=>{console.log(`\uD83D\uDE80 Vision Dashboard running at http://${this.options.host}:${this.options.port}`),console.log(` WebSocket: ws://${this.options.host}:${this.options.port}/ws`)}),this.wss.on("connection",(a)=>{console.log("\uD83D\uDD0C Dashboard client connected"),this.clients.add(a),a.on("message",async(e)=>{let i=e.toString(),n=await this.rpc.handle(i);if(n)a.send(n)}),a.on("close",()=>{console.log("\uD83D\uDD0C Dashboard client disconnected"),this.clients.delete(a)}),a.on("error",(e)=>{console.error("WebSocket error:",e),this.clients.delete(a)}),a.send(JSON.stringify({jsonrpc:"2.0",method:"connection.established",params:{timestamp:Date.now()}}))}),this.wss.on("error",(a)=>{console.error("WebSocket server error:",a)}),this.httpServer.on("error",(a)=>{console.error("HTTP server error:",a)})}registerMethod(a,e){this.rpc.register(a,e)}broadcast(a){let e=this.rpc.createNotification(a.type,a.data);this.clients.forEach((i)=>{if(i.readyState===ia.OPEN)i.send(e)})}getClientCount(){return this.clients.size}async close(){return new Promise((a,e)=>{this.clients.forEach((i)=>i.close()),this.clients.clear(),this.wss.close((i)=>{this.httpServer.close((n)=>{if(i||n)e(i||n);else console.log("\u2705 Vision Dashboard server closed"),a()})})})}}import{webcrypto as $}from"crypto";var W="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var oa=128,u,m;function sa(a){if(!u||u.length<a)u=Buffer.allocUnsafe(a*oa),$.getRandomValues(u),m=0;else if(m+a>u.length)$.getRandomValues(u),m=0;m+=a}function d(a=21){sa(a|=0);let e="";for(let i=m-a;i<m;i++)e+=W[u[i]&63];return e}class f{traces=new Map;maxTraces;constructor(a=1000){this.maxTraces=a}createTrace(a,e){let i={id:d(),timestamp:Date.now(),method:a,path:e,spans:[]};return this.addTrace(i),i}addTrace(a){if(this.traces.size>=this.maxTraces){let e=this.traces.keys().next().value;if(e)this.traces.delete(e)}this.traces.set(a.id,a)}addSpan(a,e){let i=this.traces.get(a);if(i)i.spans.push(e)}completeTrace(a,e,i){let n=this.traces.get(a);if(n)n.statusCode=e,n.duration=i}getTrace(a){return this.traces.get(a)}getAllTraces(){return Array.from(this.traces.values()).reverse()}getTraces(a){let e=this.getAllTraces();if(a?.method)e=e.filter((i)=>i.method===a.method);if(a?.statusCode)e=e.filter((i)=>i.statusCode===a.statusCode);if(a?.minDuration)e=e.filter((i)=>(i.duration??0)>=a.minDuration);if(a?.limit)e=e.slice(0,a.limit);return e}clear(){this.traces.clear()}count(){return this.traces.size}}class g{activeSpans=new Map;startSpan(a,e,i){let n={id:d(),traceId:e,parentId:i,name:a,startTime:Date.now(),attributes:{},events:[]};return this.activeSpans.set(n.id,n),n}endSpan(a){let e=this.activeSpans.get(a);if(e)e.endTime=Date.now(),e.duration=e.endTime-e.startTime,this.activeSpans.delete(a);return e}setAttribute(a,e,i){let n=this.activeSpans.get(a);if(n&&n.attributes)n.attributes[e]=i}addEvent(a,e,i){let n=this.activeSpans.get(a);if(n){let o={name:e,timestamp:Date.now(),attributes:i};n.events?.push(o)}}getSpan(a){return this.activeSpans.get(a)}}class U{logs=[];maxLogs;constructor(a=1e4){this.maxLogs=a}addLog(a,e,i,n){let o={id:d(),timestamp:Date.now(),level:a,message:e,args:i,stack:n};if(this.logs.push(o),this.logs.length>this.maxLogs)this.logs.shift();return o}getAllLogs(){return[...this.logs].reverse()}getLogs(a){let e=this.logs;if(a?.level)e=e.filter((n)=>n.level===a.level);if(a?.search){let n=a.search.toLowerCase();e=e.filter((o)=>o.message.toLowerCase().includes(n)||o.args?.some((c)=>String(c).toLowerCase().includes(n)))}if(a?.since)e=e.filter((n)=>n.timestamp>=(a.since??0));let i=[...e].reverse();if(a?.limit)return i.slice(0,a.limit);return i}clear(){this.logs=[]}count(){return this.logs.length}}class F{originalConsole={log:console.log,info:console.info,warn:console.warn,error:console.error,debug:console.debug};logStore;onLog;constructor(a,e){this.logStore=a,this.onLog=e}start(){let a=(e,i)=>{return(...n)=>{i.apply(console,n);let o=n.map((s)=>{if(typeof s==="string")return s;if(s instanceof Error)return s.message;try{return JSON.stringify(s)}catch{return String(s)}}).join(" "),c;if(e==="error"){let s=n.find((p)=>p instanceof Error);if(s)c=s.stack}this.logStore.addLog(e,o,n,c),this.onLog?.(e,o,n,c)}};console.log=a("log",this.originalConsole.log),console.info=a("info",this.originalConsole.info),console.warn=a("warn",this.originalConsole.warn),console.error=a("error",this.originalConsole.error),console.debug=a("debug",this.originalConsole.debug)}stop(){console.log=this.originalConsole.log,console.info=this.originalConsole.info,console.warn=this.originalConsole.warn,console.error=this.originalConsole.error,console.debug=this.originalConsole.debug}}class J{server;traceStore;tracer;logStore;consoleInterceptor;routes=[];services=[];appStatus={name:"Unknown",version:"0.0.0",environment:"development",running:!1};constructor(a={}){if(this.server=new b(a),this.traceStore=new f(a.maxTraces),this.tracer=new g,this.logStore=new U(a.maxLogs),a.captureConsole!==!1)this.consoleInterceptor=new F(this.logStore,()=>{this.broadcast({type:"log.entry",data:this.logStore.getLogs({limit:1})[0]})}),this.consoleInterceptor.start();this.registerMethods()}registerMethods(){this.server.registerMethod("status",async()=>{return this.appStatus}),this.server.registerMethod("traces/list",async(a)=>{return this.traceStore.getTraces({method:a?.method,statusCode:a?.statusCode,minDuration:a?.minDuration,limit:a?.limit??100})}),this.server.registerMethod("traces/get",async(a)=>{if(!a?.traceId)throw Error("traceId is required");return this.traceStore.getTrace(a.traceId)}),this.server.registerMethod("traces/clear",async()=>{return this.traceStore.clear(),{success:!0}}),this.server.registerMethod("traces/export",async(a)=>{let e=a?.format||"json",i=this.traceStore.getAllTraces();if(e==="ndjson")return i.map((n)=>JSON.stringify(n)).join(`
|
|
12
|
+
*/var j=O(),X=L("path").extname;var H=Object.create(null),y=G,z=Object.create(null);D(H,z);function G(a){if(!a||typeof a!=="string")return!1;var e=X("x."+a).toLowerCase().substr(1);if(!e)return!1;return z[e]||!1}function D(a,e){var i=["nginx","apache",void 0,"iana"];Object.keys(j).forEach(function(o){var c=j[o],s=c.extensions;if(!s||!s.length)return;a[o]=s;for(var p=0;p<s.length;p++){var t=s[p];if(e[t]){var v=i.indexOf(j[e[t]].source),h=i.indexOf(c.source);if(e[t]!=="application/octet-stream"&&(v>h||v===h&&e[t].substr(0,12)==="application/"))continue}e[t]=o}})}var aa=S(P(import.meta.url));async function Q(a,e,i){let n=a.url||"/",o=n.indexOf("?");if(o!==-1)n=n.substring(0,o);if(n==="/"||!n.includes("."))n="/index.html";let c=q(i,n);if(!c.startsWith(i))return!1;if(!I(c))return!1;try{let s=await E(c),p=y(c)||"application/octet-stream";return e.writeHead(200,{"Content-Type":p,"Cache-Control":"public, max-age=3600"}),e.end(s),!0}catch(s){return console.error("Error serving static file:",s),!1}}function V(){let a=q(aa,"../..");return q(a,"dist/ui")}class b{httpServer;wss;clients=new Set;rpc;options;constructor(a={}){this.options={port:a.port??9500,host:a.host??"localhost",maxTraces:a.maxTraces??1000,maxLogs:a.maxLogs??1e4,captureConsole:a.captureConsole??!0,enableCors:a.enableCors??!0},this.rpc=new w,this.httpServer=na((e,i)=>{this.handleHttp(e,i).catch((n)=>{console.error("HTTP handler error:",n),i.writeHead(500),i.end("Internal Server Error")})}),this.wss=new ea({server:this.httpServer,path:"/ws"}),this.setupServer()}async handleHttp(a,e){if(this.options.enableCors)e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type");if(a.method==="OPTIONS"){e.writeHead(200),e.end();return}if(a.url==="/health"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok",clients:this.clients.size}));return}let i=V();if(!await Q(a,e,i))e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Vision Dashboard UI not found. Build the UI or ensure adapters are running.")}setupServer(){this.httpServer.listen(this.options.port,this.options.host,()=>{console.log(`\uD83D\uDE80 Vision Dashboard running at http://${this.options.host}:${this.options.port}`),console.log(` WebSocket: ws://${this.options.host}:${this.options.port}/ws`)}),this.wss.on("connection",(a)=>{console.log("\uD83D\uDD0C Dashboard client connected"),this.clients.add(a),a.on("message",async(e)=>{let i=e.toString(),n=await this.rpc.handle(i);if(n)a.send(n)}),a.on("close",()=>{console.log("\uD83D\uDD0C Dashboard client disconnected"),this.clients.delete(a)}),a.on("error",(e)=>{console.error("WebSocket error:",e),this.clients.delete(a)}),a.send(JSON.stringify({jsonrpc:"2.0",method:"connection.established",params:{timestamp:Date.now()}}))}),this.wss.on("error",(a)=>{console.error("WebSocket server error:",a)}),this.httpServer.on("error",(a)=>{console.error("HTTP server error:",a)})}registerMethod(a,e){this.rpc.register(a,e)}broadcast(a){let e=this.rpc.createNotification(a.type,a.data);this.clients.forEach((i)=>{if(i.readyState===ia.OPEN)i.send(e)})}getClientCount(){return this.clients.size}async close(){return new Promise((a,e)=>{this.clients.forEach((i)=>i.close()),this.clients.clear(),this.wss.close((i)=>{this.httpServer.close((n)=>{if(i||n)e(i||n);else console.log("\u2705 Vision Dashboard server closed"),a()})})})}}import{webcrypto as $}from"crypto";var W="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var oa=128,u,m;function sa(a){if(!u||u.length<a)u=Buffer.allocUnsafe(a*oa),$.getRandomValues(u),m=0;else if(m+a>u.length)$.getRandomValues(u),m=0;m+=a}function d(a=21){sa(a|=0);let e="";for(let i=m-a;i<m;i++)e+=W[u[i]&63];return e}class f{traces=new Map;maxTraces;constructor(a=1000){this.maxTraces=a}createTrace(a,e){let i={id:d(),timestamp:Date.now(),method:a,path:e,spans:[]};return this.addTrace(i),i}addTrace(a){if(this.traces.size>=this.maxTraces){let e=this.traces.keys().next().value;if(e)this.traces.delete(e)}this.traces.set(a.id,a)}addSpan(a,e){let i=this.traces.get(a);if(i)i.spans.push(e)}completeTrace(a,e,i){let n=this.traces.get(a);if(n)n.statusCode=e,n.duration=i}getTrace(a){return this.traces.get(a)}getAllTraces(){return Array.from(this.traces.values()).reverse()}getTraces(a){let e=this.getAllTraces();if(a?.method)e=e.filter((i)=>i.method===a.method);if(a?.statusCode)e=e.filter((i)=>i.statusCode===a.statusCode);if(a?.minDuration)e=e.filter((i)=>(i.duration??0)>=a.minDuration);if(a?.limit)e=e.slice(0,a.limit);return e}clear(){this.traces.clear()}count(){return this.traces.size}}class g{activeSpans=new Map;startSpan(a,e,i){let n={id:d(),traceId:e,parentId:i,name:a,startTime:Date.now(),attributes:{},events:[]};return this.activeSpans.set(n.id,n),n}endSpan(a){let e=this.activeSpans.get(a);if(e)e.endTime=Date.now(),e.duration=e.endTime-e.startTime,this.activeSpans.delete(a);return e}setAttribute(a,e,i){let n=this.activeSpans.get(a);if(n&&n.attributes)n.attributes[e]=i}addEvent(a,e,i){let n=this.activeSpans.get(a);if(n){let o={name:e,timestamp:Date.now(),attributes:i};n.events?.push(o)}}getSpan(a){return this.activeSpans.get(a)}}class U{logs=[];maxLogs;constructor(a=1e4){this.maxLogs=a}addLog(a,e,i,n){let o={id:d(),timestamp:Date.now(),level:a,message:e,args:i,stack:n};if(this.logs.push(o),this.logs.length>this.maxLogs)this.logs.shift();return o}getAllLogs(){return[...this.logs].reverse()}getLogs(a){let e=this.logs;if(a?.level)e=e.filter((n)=>n.level===a.level);if(a?.search){let n=a.search.toLowerCase();e=e.filter((o)=>o.message.toLowerCase().includes(n)||o.args?.some((c)=>String(c).toLowerCase().includes(n)))}if(a?.since)e=e.filter((n)=>n.timestamp>=(a.since??0));let i=[...e].reverse();if(a?.limit)return i.slice(0,a.limit);return i}clear(){this.logs=[]}count(){return this.logs.length}}class F{originalConsole={log:console.log,info:console.info,warn:console.warn,error:console.error,debug:console.debug};logStore;onLog;constructor(a,e){this.logStore=a,this.onLog=e}start(){let a=(e,i)=>{return(...n)=>{i.apply(console,n);let o=n.map((s)=>{if(typeof s==="string")return s;if(s instanceof Error)return s.message;try{return JSON.stringify(s)}catch{return String(s)}}).join(" "),c;if(e==="error"){let s=n.find((p)=>p instanceof Error);if(s)c=s.stack}this.logStore.addLog(e,o,n,c),this.onLog?.(e,o,n,c)}};console.log=a("log",this.originalConsole.log),console.info=a("info",this.originalConsole.info),console.warn=a("warn",this.originalConsole.warn),console.error=a("error",this.originalConsole.error),console.debug=a("debug",this.originalConsole.debug)}stop(){console.log=this.originalConsole.log,console.info=this.originalConsole.info,console.warn=this.originalConsole.warn,console.error=this.originalConsole.error,console.debug=this.originalConsole.debug}}class J{server;traceStore;tracer;logStore;consoleInterceptor;routes=[];services=[];appStatus={name:"Unknown",version:"0.0.0",environment:"development",running:!1};constructor(a={}){if(this.server=new b(a),this.traceStore=new f(a.maxTraces),this.tracer=new g,this.logStore=new U(a.maxLogs),a.captureConsole!==!1)this.consoleInterceptor=new F(this.logStore,()=>{this.broadcast({type:"log.entry",data:this.logStore.getLogs({limit:1})[0]})}),this.consoleInterceptor.start();this.registerMethods()}registerMethods(){this.server.registerMethod("status",async()=>{return this.appStatus}),this.server.registerMethod("traces/list",async(a)=>{return this.traceStore.getTraces({method:a?.method,statusCode:a?.statusCode,minDuration:a?.minDuration,limit:a?.limit??100})}),this.server.registerMethod("traces/get",async(a)=>{if(!a?.traceId)throw Error("traceId is required");return this.traceStore.getTrace(a.traceId)}),this.server.registerMethod("traces/clear",async()=>{return this.traceStore.clear(),{success:!0}}),this.server.registerMethod("traces/export",async(a)=>{let e=a?.format||"json",i=this.traceStore.getAllTraces();if(e==="ndjson")return i.map((n)=>JSON.stringify(n)).join(`
|
|
119
13
|
`);return JSON.stringify(i,null,2)}),this.server.registerMethod("routes/list",async()=>{return this.routes}),this.server.registerMethod("services/list",async()=>{return this.services}),this.server.registerMethod("version",async()=>{return{version:"0.0.1",name:"Vision Dashboard"}}),this.server.registerMethod("logs/list",async(a)=>{return this.logStore.getLogs({level:a?.level,search:a?.search,limit:a?.limit??100,since:a?.since})}),this.server.registerMethod("logs/clear",async()=>{return this.logStore.clear(),{success:!0}}),this.server.registerMethod("traces/addClientMetrics",async(a)=>{let{traceId:e,clientDuration:i}=a;if(!e||typeof i!=="number")throw Error("traceId and clientDuration are required");let n=this.traceStore.getTrace(e);if(n)n.metadata={...n.metadata||{},clientDuration:i};return{success:!0}})}setAppStatus(a){this.appStatus={...this.appStatus,...a},this.broadcast({type:"app.started",data:this.appStatus})}registerRoutes(a){this.routes=a}registerServices(a){this.services=a}createTrace(a,e){return this.traceStore.createTrace(a,e)}completeTrace(a,e,i){this.traceStore.completeTrace(a,e,i);let n=this.traceStore.getTrace(a);if(n)this.broadcast({type:"trace.new",data:n})}getTracer(){return this.tracer}getServer(){return this.server}createSpanHelper(a){return(e,i={},n)=>{let o=this.tracer.startSpan(e,a);for(let[c,s]of Object.entries(i))this.tracer.setAttribute(o.id,c,s);try{let c=n(),s=this.tracer.endSpan(o.id);if(s)this.traceStore.addSpan(a,s);return c}catch(c){this.tracer.setAttribute(o.id,"error",!0),this.tracer.setAttribute(o.id,"error.message",c instanceof Error?c.message:String(c));let s=this.tracer.endSpan(o.id);if(s)this.traceStore.addSpan(a,s);throw c}}}getTraceStore(){return this.traceStore}log(a,e,i){let n=i?[i]:void 0,o=this.logStore.addLog(a,e,n);return this.broadcast({type:"log.entry",data:o}),o}getLogStore(){return this.logStore}broadcast(a){this.server.broadcast(a)}logStdout(a){this.broadcast({type:"log.stdout",data:{message:a,timestamp:Date.now()}})}logStderr(a){this.broadcast({type:"log.stderr",data:{message:a,timestamp:Date.now()}})}getClientCount(){return this.server.getClientCount()}async close(){await this.server.close()}}function ca(a){try{let e=Z(a);return{template:R(e),fields:e}}catch(e){console.warn("Failed to generate template from Zod schema:",e);return}}function Z(a,e=[]){let i=[];if(!(a.def||a._def))return i;let o=a,c=o.def||o._def,s=c?.type||c?.typeName;if(s==="object"||s==="ZodObject"){let p=c?.shape,t=typeof p==="function"?p():p;for(let[v,h]of Object.entries(t||{})){let l=h,r=l.def||l._def,N=l.type==="optional"||r?.type==="optional"||r?.typeName==="ZodOptional"||r?.typeName==="ZodDefault",k=r?.description||l.description;if(!k&&r?.wrapped)k=(r.wrapped.def||r.wrapped._def)?.description||r.wrapped.description;let T=pa(l),_=Z(l,[...e,v]);i.push({name:v,type:T,description:k,required:!N,nested:_.length>0?_:void 0,example:ta(l,T)})}}return i}function pa(a){let e=a,i=e.def||e._def;while(i?.type==="optional"||i?.type==="nullable"||i?.type==="default"||i?.typeName==="ZodOptional"||i?.typeName==="ZodNullable"||i?.typeName==="ZodDefault")e=i?.innerType||i?.wrapped||e,i=e.def||e._def;switch(i?.type||i?.typeName||e.type){case"string":case"ZodString":return"string";case"number":case"ZodNumber":return"number";case"boolean":case"ZodBoolean":return"boolean";case"array":case"ZodArray":return"array";case"object":case"ZodObject":return"object";case"enum":case"ZodEnum":return"enum";case"date":case"ZodDate":return"date";default:return"any"}}function ta(a,e){switch(e){case"string":return"";case"number":return 0;case"boolean":return!1;case"array":return[];case"object":return{};default:return null}}function R(a,e=0){let i=[],n=" ".repeat(e);return i.push("{"),a.forEach((o,c)=>{let s=c===a.length-1,p=o.description||o.name;i.push(`${n} // ${p}`);let t;if(o.nested&&o.nested.length>0)t=R(o.nested,e+1);else t=JSON.stringify(o.example);i.push(`${n} "${o.name}": ${t}${s?"":","}`)}),i.push(`${n}}`),i.join(`
|
|
120
14
|
`)}import{readFileSync as ra,existsSync as Y}from"fs";import{join as la}from"path";import{spawn as ua}from"child_process";function ma(){try{let a=la(process.cwd(),"package.json");if(Y(a)){let e=JSON.parse(ra(a,"utf-8"));return{name:e.name||"unknown",version:e.version||"0.0.0"}}}catch(a){}return{name:"unknown",version:"0.0.0"}}function da(){let a={},e=["DATABASE_URL","DB_URL","POSTGRES_URL","MYSQL_URL","MONGODB_URL"];for(let n of e)if(process.env[n]){a.database=process.env[n];break}let i=["REDIS_URL","CACHE_URL","UPSTASH_REDIS_URL"];for(let n of i)if(process.env[n]){a.redis=process.env[n];break}return a}function K(){let a=["drizzle.config.ts","drizzle.config.js","drizzle.config.mjs"];for(let e of a)if(Y(e))return{detected:!0,configPath:e};return{detected:!1}}var x=null;function xa(a=4983){if(!K().detected)return console.warn("\u26A0\uFE0F Drizzle config not found. Skipping Drizzle Studio auto-start."),!1;console.log(`\uD83D\uDDC4\uFE0F Starting Drizzle Studio on port ${a}...`);try{return x=ua("npx",["drizzle-kit","studio","--port",String(a),"--host","0.0.0.0"],{stdio:"inherit",detached:!1}),x.on("error",(i)=>{console.error("\u274C Failed to start Drizzle Studio:",i.message)}),x.on("exit",(i)=>{if(i!==0&&i!==null)console.error(`\u274C Drizzle Studio exited with code ${i}`)}),console.log("\u2705 Drizzle Studio started"),!0}catch(i){return console.error("\u274C Failed to start Drizzle Studio:",i),!1}}function va(){if(x)x.kill(),x=null,console.log("\uD83D\uDED1 Drizzle Studio stopped")}export{va as stopDrizzleStudio,xa as startDrizzleStudio,ca as generateZodTemplate,K as detectDrizzle,ma as autoDetectPackageInfo,da as autoDetectIntegrations,b as VisionWebSocketServer,J as VisionCore,g as Tracer,f as TraceStore};
|
|
@@ -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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console interceptor to capture logs
|
|
3
|
+
* Preserves original console behavior while storing logs
|
|
4
|
+
*/
|
|
5
|
+
export class ConsoleInterceptor {
|
|
6
|
+
originalConsole = {
|
|
7
|
+
log: console.log,
|
|
8
|
+
info: console.info,
|
|
9
|
+
warn: console.warn,
|
|
10
|
+
error: console.error,
|
|
11
|
+
debug: console.debug,
|
|
12
|
+
};
|
|
13
|
+
logStore;
|
|
14
|
+
onLog;
|
|
15
|
+
constructor(logStore, onLog) {
|
|
16
|
+
this.logStore = logStore;
|
|
17
|
+
this.onLog = onLog;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start intercepting console methods
|
|
21
|
+
*/
|
|
22
|
+
start() {
|
|
23
|
+
const intercept = (level, original) => {
|
|
24
|
+
return (...args) => {
|
|
25
|
+
// Call original console method first
|
|
26
|
+
original.apply(console, args);
|
|
27
|
+
// Format message
|
|
28
|
+
const message = args
|
|
29
|
+
.map((arg) => {
|
|
30
|
+
if (typeof arg === 'string')
|
|
31
|
+
return arg;
|
|
32
|
+
if (arg instanceof Error)
|
|
33
|
+
return arg.message;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.stringify(arg);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return String(arg);
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
.join(' ');
|
|
42
|
+
// Capture stack trace for errors
|
|
43
|
+
let stack;
|
|
44
|
+
if (level === 'error') {
|
|
45
|
+
const err = args.find((arg) => arg instanceof Error);
|
|
46
|
+
if (err) {
|
|
47
|
+
stack = err.stack;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Store log
|
|
51
|
+
this.logStore.addLog(level, message, args, stack);
|
|
52
|
+
// Notify listener
|
|
53
|
+
this.onLog?.(level, message, args, stack);
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
console.log = intercept('log', this.originalConsole.log);
|
|
57
|
+
console.info = intercept('info', this.originalConsole.info);
|
|
58
|
+
console.warn = intercept('warn', this.originalConsole.warn);
|
|
59
|
+
console.error = intercept('error', this.originalConsole.error);
|
|
60
|
+
console.debug = intercept('debug', this.originalConsole.debug);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Stop intercepting and restore original console
|
|
64
|
+
*/
|
|
65
|
+
stop() {
|
|
66
|
+
console.log = this.originalConsole.log;
|
|
67
|
+
console.info = this.originalConsole.info;
|
|
68
|
+
console.warn = this.originalConsole.warn;
|
|
69
|
+
console.error = this.originalConsole.error;
|
|
70
|
+
console.debug = this.originalConsole.debug;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LogEntry, LogLevel } from '../types/logs';
|
|
2
|
+
/**
|
|
3
|
+
* Circular buffer for storing logs
|
|
4
|
+
* Automatically removes oldest entries when limit is reached
|
|
5
|
+
*/
|
|
6
|
+
export declare class LogStore {
|
|
7
|
+
private logs;
|
|
8
|
+
private maxLogs;
|
|
9
|
+
constructor(maxLogs?: number);
|
|
10
|
+
/**
|
|
11
|
+
* Add a log entry
|
|
12
|
+
*/
|
|
13
|
+
addLog(level: LogLevel, message: string, args?: any[], stack?: string): LogEntry;
|
|
14
|
+
/**
|
|
15
|
+
* Get all logs (newest first)
|
|
16
|
+
*/
|
|
17
|
+
getAllLogs(): LogEntry[];
|
|
18
|
+
/**
|
|
19
|
+
* Get logs with filters
|
|
20
|
+
*/
|
|
21
|
+
getLogs(filter?: {
|
|
22
|
+
level?: LogLevel;
|
|
23
|
+
search?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
since?: number;
|
|
26
|
+
}): LogEntry[];
|
|
27
|
+
/**
|
|
28
|
+
* Clear all logs
|
|
29
|
+
*/
|
|
30
|
+
clear(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get log count
|
|
33
|
+
*/
|
|
34
|
+
count(): number;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/logs/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAEvD;;;GAGG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,SAAS;IAI5B;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ;IAoBhF;;OAEG;IACH,UAAU,IAAI,QAAQ,EAAE;IAIxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,EAAE;QACf,KAAK,CAAC,EAAE,QAAQ,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,GAAG,QAAQ,EAAE;IAgCd;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
/**
|
|
3
|
+
* Circular buffer for storing logs
|
|
4
|
+
* Automatically removes oldest entries when limit is reached
|
|
5
|
+
*/
|
|
6
|
+
export class LogStore {
|
|
7
|
+
logs = [];
|
|
8
|
+
maxLogs;
|
|
9
|
+
constructor(maxLogs = 10_000) {
|
|
10
|
+
this.maxLogs = maxLogs;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Add a log entry
|
|
14
|
+
*/
|
|
15
|
+
addLog(level, message, args, stack) {
|
|
16
|
+
const entry = {
|
|
17
|
+
id: nanoid(),
|
|
18
|
+
timestamp: Date.now(),
|
|
19
|
+
level,
|
|
20
|
+
message,
|
|
21
|
+
args,
|
|
22
|
+
stack,
|
|
23
|
+
};
|
|
24
|
+
this.logs.push(entry);
|
|
25
|
+
// Remove oldest if we've hit the limit
|
|
26
|
+
if (this.logs.length > this.maxLogs) {
|
|
27
|
+
this.logs.shift();
|
|
28
|
+
}
|
|
29
|
+
return entry;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get all logs (newest first)
|
|
33
|
+
*/
|
|
34
|
+
getAllLogs() {
|
|
35
|
+
return [...this.logs].reverse();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get logs with filters
|
|
39
|
+
*/
|
|
40
|
+
getLogs(filter) {
|
|
41
|
+
let filtered = this.logs;
|
|
42
|
+
if (filter?.level) {
|
|
43
|
+
filtered = filtered.filter((log) => log.level === filter.level);
|
|
44
|
+
}
|
|
45
|
+
if (filter?.search) {
|
|
46
|
+
const searchLower = filter.search.toLowerCase();
|
|
47
|
+
filtered = filtered.filter((log) => log.message.toLowerCase().includes(searchLower) ||
|
|
48
|
+
log.args?.some((arg) => String(arg).toLowerCase().includes(searchLower)));
|
|
49
|
+
}
|
|
50
|
+
if (filter?.since) {
|
|
51
|
+
filtered = filtered.filter((log) => log.timestamp >= (filter.since ?? 0));
|
|
52
|
+
}
|
|
53
|
+
// Newest first
|
|
54
|
+
const reversed = [...filtered].reverse();
|
|
55
|
+
if (filter?.limit) {
|
|
56
|
+
return reversed.slice(0, filter.limit);
|
|
57
|
+
}
|
|
58
|
+
return reversed;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Clear all logs
|
|
62
|
+
*/
|
|
63
|
+
clear() {
|
|
64
|
+
this.logs = [];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get log count
|
|
68
|
+
*/
|
|
69
|
+
count() {
|
|
70
|
+
return this.logs.length;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Handler
|
|
3
|
+
*/
|
|
4
|
+
export declare class JsonRpcHandler {
|
|
5
|
+
private methods;
|
|
6
|
+
/**
|
|
7
|
+
* Register a JSON-RPC method
|
|
8
|
+
*/
|
|
9
|
+
register(method: string, handler: (params: unknown) => Promise<unknown>): void;
|
|
10
|
+
/**
|
|
11
|
+
* Handle incoming JSON-RPC request
|
|
12
|
+
*/
|
|
13
|
+
handle(message: string): Promise<string | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Create a notification (server -> client)
|
|
16
|
+
*/
|
|
17
|
+
createNotification(method: string, params?: unknown): string;
|
|
18
|
+
private createSuccessResponse;
|
|
19
|
+
private createErrorResponse;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=jsonrpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonrpc.d.ts","sourceRoot":"","sources":["../../src/server/jsonrpc.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAA2D;IAE1E;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAI9E;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkCrD;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM;IAS5D,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;CAc5B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Handler
|
|
3
|
+
*/
|
|
4
|
+
export class JsonRpcHandler {
|
|
5
|
+
methods = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Register a JSON-RPC method
|
|
8
|
+
*/
|
|
9
|
+
register(method, handler) {
|
|
10
|
+
this.methods.set(method, handler);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Handle incoming JSON-RPC request
|
|
14
|
+
*/
|
|
15
|
+
async handle(message) {
|
|
16
|
+
let request;
|
|
17
|
+
try {
|
|
18
|
+
request = JSON.parse(message);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
return this.createErrorResponse(null, -32700, 'Parse error');
|
|
22
|
+
}
|
|
23
|
+
// Validate JSON-RPC request
|
|
24
|
+
if (request.jsonrpc !== '2.0') {
|
|
25
|
+
return this.createErrorResponse(request.id ?? null, -32600, 'Invalid Request');
|
|
26
|
+
}
|
|
27
|
+
// Handle notification (no response needed)
|
|
28
|
+
if (request.id === undefined) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
// Find and execute method
|
|
32
|
+
const handler = this.methods.get(request.method);
|
|
33
|
+
if (!handler) {
|
|
34
|
+
return this.createErrorResponse(request.id, -32601, `Method not found: ${request.method}`);
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const result = await handler(request.params);
|
|
38
|
+
return this.createSuccessResponse(request.id, result);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : 'Internal error';
|
|
42
|
+
return this.createErrorResponse(request.id, -32603, message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a notification (server -> client)
|
|
47
|
+
*/
|
|
48
|
+
createNotification(method, params) {
|
|
49
|
+
const notification = {
|
|
50
|
+
jsonrpc: '2.0',
|
|
51
|
+
method,
|
|
52
|
+
params,
|
|
53
|
+
};
|
|
54
|
+
return JSON.stringify(notification);
|
|
55
|
+
}
|
|
56
|
+
createSuccessResponse(id, result) {
|
|
57
|
+
const response = {
|
|
58
|
+
jsonrpc: '2.0',
|
|
59
|
+
result,
|
|
60
|
+
id,
|
|
61
|
+
};
|
|
62
|
+
return JSON.stringify(response);
|
|
63
|
+
}
|
|
64
|
+
createErrorResponse(id, code, message, data) {
|
|
65
|
+
const error = { code, message, data };
|
|
66
|
+
const response = {
|
|
67
|
+
jsonrpc: '2.0',
|
|
68
|
+
error,
|
|
69
|
+
id,
|
|
70
|
+
};
|
|
71
|
+
return JSON.stringify(response);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
+
/**
|
|
3
|
+
* Serve static files from the built UI directory
|
|
4
|
+
*/
|
|
5
|
+
export declare function serveStatic(req: IncomingMessage, res: ServerResponse, uiPath: string): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Get the path to the UI dist directory
|
|
8
|
+
*/
|
|
9
|
+
export declare function getUIPath(): string;
|
|
10
|
+
//# sourceMappingURL=static.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAI3D;;GAEG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAuClB;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAQlC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { lookup } from 'mime-types';
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
/**
|
|
8
|
+
* Serve static files from the built UI directory
|
|
9
|
+
*/
|
|
10
|
+
export async function serveStatic(req, res, uiPath) {
|
|
11
|
+
let filePath = req.url || '/';
|
|
12
|
+
// Remove query string
|
|
13
|
+
const queryIndex = filePath.indexOf('?');
|
|
14
|
+
if (queryIndex !== -1) {
|
|
15
|
+
filePath = filePath.substring(0, queryIndex);
|
|
16
|
+
}
|
|
17
|
+
// Default to index.html for root and SPA routes
|
|
18
|
+
if (filePath === '/' || !filePath.includes('.')) {
|
|
19
|
+
filePath = '/index.html';
|
|
20
|
+
}
|
|
21
|
+
const fullPath = join(uiPath, filePath);
|
|
22
|
+
// Security: prevent directory traversal
|
|
23
|
+
if (!fullPath.startsWith(uiPath)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (!existsSync(fullPath)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const content = await readFile(fullPath);
|
|
31
|
+
const mimeType = lookup(fullPath) || 'application/octet-stream';
|
|
32
|
+
res.writeHead(200, {
|
|
33
|
+
'Content-Type': mimeType,
|
|
34
|
+
'Cache-Control': 'public, max-age=3600',
|
|
35
|
+
});
|
|
36
|
+
res.end(content);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error('Error serving static file:', error);
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get the path to the UI dist directory
|
|
46
|
+
*/
|
|
47
|
+
export function getUIPath() {
|
|
48
|
+
// Get the core package root directory
|
|
49
|
+
// __dirname in dev: /Users/.../packages/core/src/server
|
|
50
|
+
// __dirname in prod: /Users/.../packages/core/dist/server
|
|
51
|
+
const coreRoot = join(__dirname, '../..');
|
|
52
|
+
const uiPath = join(coreRoot, 'dist/ui');
|
|
53
|
+
return uiPath;
|
|
54
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { VisionServerOptions, DashboardEvent } from '../types/index';
|
|
2
|
+
/**
|
|
3
|
+
* Vision WebSocket Server
|
|
4
|
+
* Handles real-time communication with the dashboard UI
|
|
5
|
+
* Also serves static UI files on the same port
|
|
6
|
+
*/
|
|
7
|
+
export declare class VisionWebSocketServer {
|
|
8
|
+
private httpServer;
|
|
9
|
+
private wss;
|
|
10
|
+
private clients;
|
|
11
|
+
private rpc;
|
|
12
|
+
private options;
|
|
13
|
+
constructor(options?: VisionServerOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Handle HTTP requests (for serving UI)
|
|
16
|
+
*/
|
|
17
|
+
private handleHttp;
|
|
18
|
+
/**
|
|
19
|
+
* Get embedded UI HTML
|
|
20
|
+
* For now, returns a simple page that connects to WebSocket
|
|
21
|
+
* In production, this would serve the built React app
|
|
22
|
+
*/
|
|
23
|
+
private getEmbeddedUI;
|
|
24
|
+
private setupServer;
|
|
25
|
+
/**
|
|
26
|
+
* Register a JSON-RPC method handler
|
|
27
|
+
*/
|
|
28
|
+
registerMethod(method: string, handler: (params: unknown) => Promise<unknown>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Broadcast an event to all connected clients
|
|
31
|
+
*/
|
|
32
|
+
broadcast(event: DashboardEvent): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get number of connected clients
|
|
35
|
+
*/
|
|
36
|
+
getClientCount(): number;
|
|
37
|
+
/**
|
|
38
|
+
* Close the server
|
|
39
|
+
*/
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/server/websocket.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEzE;;;;GAIG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,OAAO,CAA+B;gBAElC,OAAO,GAAE,mBAAwB;IA8B7C;;OAEG;YACW,UAAU;IAgCxB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IA8GrB,OAAO,CAAC,WAAW;IAkDnB;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAIpF;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAUtC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAiB7B"}
|