shokupan 0.10.5 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -1815
- package/dist/{analyzer-BqIe1p0R.js → analyzer-BkNQHWj4.js} +3 -8
- package/dist/{analyzer-BqIe1p0R.js.map → analyzer-BkNQHWj4.js.map} +1 -1
- package/dist/{analyzer-CKLGLFtx.cjs → analyzer-DM-OlRq8.cjs} +2 -7
- package/dist/{analyzer-CKLGLFtx.cjs.map → analyzer-DM-OlRq8.cjs.map} +1 -1
- package/dist/{analyzer.impl-D9Yi1Hax.cjs → analyzer.impl-CVJ8zfGQ.cjs} +596 -42
- package/dist/analyzer.impl-CVJ8zfGQ.cjs.map +1 -0
- package/dist/{analyzer.impl-CV6W1Eq7.js → analyzer.impl-CsA1bS_s.js} +596 -42
- package/dist/analyzer.impl-CsA1bS_s.js.map +1 -0
- package/dist/cli.cjs +206 -18
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +206 -18
- package/dist/cli.js.map +1 -1
- package/dist/context.d.ts +46 -9
- package/dist/index.cjs +3239 -1173
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3236 -1171
- package/dist/index.js.map +1 -1
- package/dist/plugins/application/api-explorer/static/explorer-client.mjs +375 -29
- package/dist/plugins/application/api-explorer/static/style.css +327 -8
- package/dist/plugins/application/api-explorer/static/theme.css +11 -2
- package/dist/plugins/application/asyncapi/generator.d.ts +4 -0
- package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +154 -22
- package/dist/plugins/application/asyncapi/static/style.css +24 -8
- package/dist/plugins/application/auth.d.ts +5 -0
- package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +119 -0
- package/dist/plugins/application/dashboard/metrics-collector.d.ts +38 -2
- package/dist/plugins/application/dashboard/plugin.d.ts +53 -1
- package/dist/plugins/application/dashboard/static/charts.js +127 -62
- package/dist/plugins/application/dashboard/static/client.js +160 -0
- package/dist/plugins/application/dashboard/static/graph.mjs +167 -56
- package/dist/plugins/application/dashboard/static/reactflow.css +20 -10
- package/dist/plugins/application/dashboard/static/registry.js +112 -8
- package/dist/plugins/application/dashboard/static/requests.js +1167 -71
- package/dist/plugins/application/dashboard/static/styles.css +186 -14
- package/dist/plugins/application/dashboard/static/tabs.js +44 -9
- package/dist/plugins/application/dashboard/static/tabulator.css +23 -3
- package/dist/plugins/application/dashboard/static/theme.css +11 -2
- package/dist/plugins/application/mcp-server/plugin.d.ts +39 -0
- package/dist/plugins/application/openapi/analyzer.impl.d.ts +65 -1
- package/dist/plugins/application/openapi/openapi.d.ts +3 -0
- package/dist/plugins/application/shared/ast-utils.d.ts +7 -0
- package/dist/plugins/middleware/compression.d.ts +12 -2
- package/dist/plugins/middleware/rate-limit.d.ts +5 -0
- package/dist/router.d.ts +59 -19
- package/dist/server.d.ts +22 -0
- package/dist/shokupan.d.ts +31 -3
- package/dist/util/adapter/bun.d.ts +8 -0
- package/dist/util/adapter/filesystem.d.ts +20 -0
- package/dist/util/adapter/index.d.ts +4 -0
- package/dist/util/adapter/interface.d.ts +12 -0
- package/dist/util/adapter/node.d.ts +8 -0
- package/dist/util/adapter/wintercg.d.ts +5 -0
- package/dist/util/body-parser.d.ts +30 -0
- package/dist/util/controller-scanner.d.ts +4 -0
- package/dist/util/cpu-monitor.d.ts +2 -0
- package/dist/util/decorators.d.ts +20 -3
- package/dist/util/di.d.ts +3 -8
- package/dist/util/metadata.d.ts +18 -0
- package/dist/util/middleware-tracker.d.ts +10 -0
- package/dist/util/request.d.ts +1 -0
- package/dist/util/symbol.d.ts +1 -0
- package/dist/util/types.d.ts +167 -1
- package/package.json +7 -5
- package/dist/analyzer.impl-CV6W1Eq7.js.map +0 -1
- package/dist/analyzer.impl-D9Yi1Hax.cjs.map +0 -1
- package/dist/http-server-BEMPIs33.cjs +0 -85
- package/dist/http-server-BEMPIs33.cjs.map +0 -1
- package/dist/http-server-CCeagTyU.js +0 -68
- package/dist/http-server-CCeagTyU.js.map +0 -1
- package/dist/plugins/application/dashboard/static/failures.js +0 -85
- package/dist/plugins/application/dashboard/static/poll.js +0 -146
- package/dist/plugins/application/http-server.d.ts +0 -13
|
@@ -252,77 +252,142 @@ const errorRateChart = new Chart(errorRateCtx, {
|
|
|
252
252
|
options: commonOptions
|
|
253
253
|
});
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const metrics = data.metrics || [];
|
|
255
|
+
// Helper to update a chart with a new data point
|
|
256
|
+
function pushData(chart, label, datasetValues) {
|
|
257
|
+
if (!chart.data.labels) chart.data.labels = [];
|
|
258
|
+
chart.data.labels.push(label);
|
|
259
|
+
if (chart.data.labels.length > 60) chart.data.labels.shift();
|
|
261
260
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
261
|
+
datasetValues.forEach((val, idx) => {
|
|
262
|
+
if (!chart.data.datasets[idx]) return;
|
|
263
|
+
chart.data.datasets[idx].data.push(val);
|
|
264
|
+
if (chart.data.datasets[idx].data.length > 60) chart.data.datasets[idx].data.shift();
|
|
265
|
+
});
|
|
266
|
+
chart.update('none'); // 'none' for smooth animation
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Initialize charts with history
|
|
270
|
+
window.initCharts = function (history) {
|
|
271
|
+
if (!history || !Array.isArray(history)) return;
|
|
272
|
+
|
|
273
|
+
// Sort by timestamp just in case
|
|
274
|
+
history.sort((a, b) => a.timestamp - b.timestamp);
|
|
275
|
+
|
|
276
|
+
const labels = history.map(m => new Date(m.timestamp).toLocaleTimeString());
|
|
277
|
+
|
|
278
|
+
// Helper to batch set data
|
|
279
|
+
const setChartData = (chart, dataExtractors) => {
|
|
280
|
+
chart.data.labels = [...labels];
|
|
281
|
+
dataExtractors.forEach((extractor, idx) => {
|
|
282
|
+
if (chart.data.datasets[idx]) {
|
|
283
|
+
chart.data.datasets[idx].data = history.map(extractor);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
chart.update();
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
setChartData(latencyChart, [
|
|
290
|
+
m => m.responseTime.avg,
|
|
291
|
+
m => m.responseTime.p95,
|
|
292
|
+
m => m.responseTime.p99
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
setChartData(rpsChart, [
|
|
296
|
+
m => m.requests.total,
|
|
297
|
+
m => m.requests.error
|
|
298
|
+
]);
|
|
299
|
+
|
|
300
|
+
setChartData(cpuChart, [
|
|
301
|
+
m => m.cpu
|
|
302
|
+
]);
|
|
303
|
+
|
|
304
|
+
setChartData(memoryChart, [
|
|
305
|
+
m => (m.memory.heapUsed / 1024 / 1024).toFixed(2),
|
|
306
|
+
m => (m.memory.used / 1024 / 1024).toFixed(2)
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
setChartData(heapChart, [
|
|
310
|
+
m => (m.memory.heapUsed / 1024 / 1024).toFixed(2),
|
|
311
|
+
m => (m.memory.heapTotal / 1024 / 1024).toFixed(2)
|
|
312
|
+
]);
|
|
313
|
+
|
|
314
|
+
setChartData(eventLoopChart, [
|
|
315
|
+
m => m.eventLoopLatency.mean,
|
|
316
|
+
m => m.eventLoopLatency.p95,
|
|
317
|
+
m => m.eventLoopLatency.p99
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
setChartData(errorRateChart, [
|
|
321
|
+
m => {
|
|
304
322
|
const total = m.requests.success + m.requests.error;
|
|
305
323
|
return total > 0 ? ((m.requests.success / total) * 100).toFixed(2) : 100;
|
|
306
|
-
}
|
|
307
|
-
|
|
324
|
+
},
|
|
325
|
+
m => {
|
|
308
326
|
const total = m.requests.success + m.requests.error;
|
|
309
327
|
return total > 0 ? ((m.requests.error / total) * 100).toFixed(2) : 0;
|
|
310
|
-
}
|
|
311
|
-
|
|
328
|
+
}
|
|
329
|
+
]);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// Push a single metric update
|
|
333
|
+
window.pushChartData = function (metric) {
|
|
334
|
+
if (!metric) return;
|
|
335
|
+
const label = new Date(metric.timestamp).toLocaleTimeString();
|
|
336
|
+
|
|
337
|
+
pushData(latencyChart, label, [
|
|
338
|
+
metric.responseTime.avg,
|
|
339
|
+
metric.responseTime.p95,
|
|
340
|
+
metric.responseTime.p99
|
|
341
|
+
]);
|
|
342
|
+
|
|
343
|
+
pushData(rpsChart, label, [
|
|
344
|
+
metric.requests.total,
|
|
345
|
+
metric.requests.error
|
|
346
|
+
]);
|
|
312
347
|
|
|
348
|
+
pushData(cpuChart, label, [
|
|
349
|
+
metric.cpu
|
|
350
|
+
]);
|
|
351
|
+
|
|
352
|
+
pushData(memoryChart, label, [
|
|
353
|
+
(metric.memory.heapUsed / 1024 / 1024).toFixed(2),
|
|
354
|
+
(metric.memory.used / 1024 / 1024).toFixed(2)
|
|
355
|
+
]);
|
|
356
|
+
|
|
357
|
+
pushData(heapChart, label, [
|
|
358
|
+
(metric.memory.heapUsed / 1024 / 1024).toFixed(2),
|
|
359
|
+
(metric.memory.heapTotal / 1024 / 1024).toFixed(2)
|
|
360
|
+
]);
|
|
361
|
+
|
|
362
|
+
pushData(eventLoopChart, label, [
|
|
363
|
+
metric.eventLoopLatency.mean,
|
|
364
|
+
metric.eventLoopLatency.p95,
|
|
365
|
+
metric.eventLoopLatency.p99
|
|
366
|
+
]);
|
|
367
|
+
|
|
368
|
+
const total = metric.requests.success + metric.requests.error;
|
|
369
|
+
pushData(errorRateChart, label, [
|
|
370
|
+
total > 0 ? ((metric.requests.success / total) * 100).toFixed(2) : 100,
|
|
371
|
+
total > 0 ? ((metric.requests.error / total) * 100).toFixed(2) : 0
|
|
372
|
+
]);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
// Old updateCharts exposed for manual refresh if needed (e.g. changing time range)
|
|
377
|
+
window.refreshCharts = async function () {
|
|
378
|
+
const period = document.getElementById('time-range-selector').value || '1m';
|
|
379
|
+
try {
|
|
380
|
+
const res = await fetch(`${url}metrics/history?interval=${period}`, { headers });
|
|
381
|
+
const data = await res.json();
|
|
382
|
+
const metrics = data.metrics || [];
|
|
383
|
+
window.initCharts(metrics);
|
|
313
384
|
} catch (e) {
|
|
314
385
|
console.error("Failed to fetch metrics", e);
|
|
315
386
|
}
|
|
316
|
-
}
|
|
387
|
+
};
|
|
317
388
|
|
|
318
|
-
// Initial load
|
|
389
|
+
// Initial load listener - removed polling
|
|
319
390
|
document.addEventListener("DOMContentLoaded", () => {
|
|
320
|
-
|
|
321
|
-
//
|
|
322
|
-
setInterval(() => {
|
|
323
|
-
const period = document.getElementById('time-range-selector').value;
|
|
324
|
-
if (['1m', '5m', '30m', '1h', '2h'].includes(period)) {
|
|
325
|
-
updateCharts();
|
|
326
|
-
}
|
|
327
|
-
}, 10000);
|
|
391
|
+
// window.refreshCharts();
|
|
392
|
+
// Wait for WS init instead
|
|
328
393
|
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
|
|
2
|
+
(function () {
|
|
3
|
+
let ws;
|
|
4
|
+
let reconnectTimer;
|
|
5
|
+
let initialConnection = true;
|
|
6
|
+
|
|
7
|
+
function formatDuration(deltaMs) {
|
|
8
|
+
if (deltaMs > (7 * 24 * 60 * 60 * 1000)) return (deltaMs / (7 * 24 * 60 * 60 * 1000)).toFixed(0) + " weeks";
|
|
9
|
+
if (deltaMs > (24 * 60 * 60 * 1000)) return (deltaMs / (24 * 60 * 60 * 1000)).toFixed(0) + " days";
|
|
10
|
+
if (deltaMs > (60 * 60 * 1000)) return (deltaMs / (60 * 60 * 1000)).toFixed(0) + " hours";
|
|
11
|
+
if (deltaMs > 60 * 1000) return (deltaMs / (60 * 1000)).toFixed(0) + " minutes";
|
|
12
|
+
if (deltaMs > 1000) return (deltaMs / 1000).toFixed(2) + " seconds";
|
|
13
|
+
return deltaMs.toFixed(0) + " ms";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function updateDOM(data) {
|
|
17
|
+
if (!data) return;
|
|
18
|
+
const metrics = data.metrics;
|
|
19
|
+
const uptime = data.uptime;
|
|
20
|
+
|
|
21
|
+
if (metrics) {
|
|
22
|
+
window.metrics = metrics; // Update global metrics for any other scripts using it
|
|
23
|
+
|
|
24
|
+
setSafeText('total-requests', metrics.totalRequests);
|
|
25
|
+
setSafeText('active-requests', metrics.activeRequests);
|
|
26
|
+
setSafeText('successful-requests', metrics.successfulRequests);
|
|
27
|
+
setSafeText('failed-requests', metrics.failedRequests);
|
|
28
|
+
|
|
29
|
+
if (metrics.averageTotalTime_ms !== undefined) {
|
|
30
|
+
setSafeText('avg-latency', metrics.averageTotalTime_ms.toFixed(2));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Recalc rates
|
|
34
|
+
const finishedRequests = metrics.totalRequests - metrics.activeRequests;
|
|
35
|
+
const successRate = finishedRequests ? Math.round((metrics.successfulRequests / finishedRequests) * 100) : 100;
|
|
36
|
+
const failRate = finishedRequests ? Math.round((metrics.failedRequests / finishedRequests) * 100) : 0;
|
|
37
|
+
|
|
38
|
+
setSafeText('success-rate', successRate + '%');
|
|
39
|
+
setSafeText('fail-rate', failRate + '%');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (uptime) {
|
|
43
|
+
setSafeText('uptime', uptime);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Charts are now updated via specific 'metric-update' events or 'init' history
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function setSafeText(id, text) {
|
|
50
|
+
const el = document.getElementById(id);
|
|
51
|
+
if (el) el.innerText = text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function connect() {
|
|
55
|
+
// Determine WS URL
|
|
56
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
57
|
+
// Handle relative path for dashboard mount
|
|
58
|
+
let path = window.location.pathname;
|
|
59
|
+
if (!path.endsWith('/')) path += '/';
|
|
60
|
+
// remove "dashboard/" or "dashboard" from end if present to get root?
|
|
61
|
+
// No, the plugin mounted the router at /dashboard usually.
|
|
62
|
+
// But the WS route is on the SAME router.
|
|
63
|
+
// So if dashboard is at /dashboard, ws is at /dashboard/ws.
|
|
64
|
+
|
|
65
|
+
// Actually, window.location.pathname includes the mount path.
|
|
66
|
+
// If we are at /dashboard/, we want /dashboard/ws.
|
|
67
|
+
// If we are at /admin/dashboard/, we want /admin/dashboard/ws.
|
|
68
|
+
const wsUrl = protocol + '//' + window.location.host + path + 'ws';
|
|
69
|
+
|
|
70
|
+
console.log("Connecting to WebSocket:", wsUrl);
|
|
71
|
+
ws = new WebSocket(wsUrl);
|
|
72
|
+
|
|
73
|
+
ws.onopen = () => {
|
|
74
|
+
console.log("Connected to Dashboard WebSocket");
|
|
75
|
+
const statusEl = document.getElementById('ws-status');
|
|
76
|
+
if (statusEl) {
|
|
77
|
+
statusEl.style.background = '#10b981'; // green
|
|
78
|
+
statusEl.title = 'WebSocket: Connected';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (reconnectTimer) {
|
|
82
|
+
clearTimeout(reconnectTimer);
|
|
83
|
+
reconnectTimer = null;
|
|
84
|
+
}
|
|
85
|
+
// Request initial data? The server sends it on open.
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
ws.onmessage = (event) => {
|
|
89
|
+
try {
|
|
90
|
+
const msg = JSON.parse(event.data);
|
|
91
|
+
if (msg.type === 'init') {
|
|
92
|
+
updateDOM(msg);
|
|
93
|
+
if (msg.history && window.initCharts) {
|
|
94
|
+
window.initCharts(msg.history);
|
|
95
|
+
}
|
|
96
|
+
} else if (msg.type === 'metric-update') {
|
|
97
|
+
// Push single metric update to charts
|
|
98
|
+
if (window.pushChartData && msg.metric) {
|
|
99
|
+
window.pushChartData(msg.metric);
|
|
100
|
+
}
|
|
101
|
+
} else if (msg.type === 'requests-update') {
|
|
102
|
+
console.log('[Dashboard Client] Received requests update', msg.requests);
|
|
103
|
+
if (window.updateRequestsList && msg.requests) {
|
|
104
|
+
window.updateRequestsList(msg.requests);
|
|
105
|
+
}
|
|
106
|
+
} else if (msg.type === 'metrics') {
|
|
107
|
+
// Standard live update (text metrics)
|
|
108
|
+
updateDOM(msg);
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.error("Failed to parse WebSocket message", e);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
ws.onclose = () => {
|
|
116
|
+
console.log("Dashboard WebSocket disconnected");
|
|
117
|
+
const statusEl = document.getElementById('ws-status');
|
|
118
|
+
if (statusEl) {
|
|
119
|
+
statusEl.style.background = '#ef4444'; // red
|
|
120
|
+
statusEl.title = 'WebSocket: Disconnected';
|
|
121
|
+
}
|
|
122
|
+
ws = null;
|
|
123
|
+
scheduleReconnect();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
ws.onerror = (err) => {
|
|
127
|
+
console.error("WebSocket error:", err);
|
|
128
|
+
ws = null;
|
|
129
|
+
// onclose will be called
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function scheduleReconnect() {
|
|
134
|
+
if (reconnectTimer) return;
|
|
135
|
+
console.log("Scheduling reconnect in 2s...");
|
|
136
|
+
reconnectTimer = setTimeout(() => {
|
|
137
|
+
reconnectTimer = null;
|
|
138
|
+
connect();
|
|
139
|
+
}, 2000);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Expose printDuration for other scripts if needed (poll.js did this)
|
|
143
|
+
window.printDuration = formatDuration;
|
|
144
|
+
|
|
145
|
+
// Start connection
|
|
146
|
+
connect();
|
|
147
|
+
|
|
148
|
+
// Listen for time range changes
|
|
149
|
+
const timeSelector = document.getElementById('time-range-selector');
|
|
150
|
+
if (timeSelector) {
|
|
151
|
+
timeSelector.addEventListener('change', (e) => {
|
|
152
|
+
const interval = e.target.value;
|
|
153
|
+
console.log("Time range changed to:", interval);
|
|
154
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
155
|
+
ws.send(JSON.stringify({ type: 'get-history', interval }));
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
})();
|