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.
Files changed (73) hide show
  1. package/README.md +46 -1815
  2. package/dist/{analyzer-BqIe1p0R.js → analyzer-BkNQHWj4.js} +3 -8
  3. package/dist/{analyzer-BqIe1p0R.js.map → analyzer-BkNQHWj4.js.map} +1 -1
  4. package/dist/{analyzer-CKLGLFtx.cjs → analyzer-DM-OlRq8.cjs} +2 -7
  5. package/dist/{analyzer-CKLGLFtx.cjs.map → analyzer-DM-OlRq8.cjs.map} +1 -1
  6. package/dist/{analyzer.impl-D9Yi1Hax.cjs → analyzer.impl-CVJ8zfGQ.cjs} +596 -42
  7. package/dist/analyzer.impl-CVJ8zfGQ.cjs.map +1 -0
  8. package/dist/{analyzer.impl-CV6W1Eq7.js → analyzer.impl-CsA1bS_s.js} +596 -42
  9. package/dist/analyzer.impl-CsA1bS_s.js.map +1 -0
  10. package/dist/cli.cjs +206 -18
  11. package/dist/cli.cjs.map +1 -1
  12. package/dist/cli.js +206 -18
  13. package/dist/cli.js.map +1 -1
  14. package/dist/context.d.ts +46 -9
  15. package/dist/index.cjs +3239 -1173
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +3236 -1171
  18. package/dist/index.js.map +1 -1
  19. package/dist/plugins/application/api-explorer/static/explorer-client.mjs +375 -29
  20. package/dist/plugins/application/api-explorer/static/style.css +327 -8
  21. package/dist/plugins/application/api-explorer/static/theme.css +11 -2
  22. package/dist/plugins/application/asyncapi/generator.d.ts +4 -0
  23. package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +154 -22
  24. package/dist/plugins/application/asyncapi/static/style.css +24 -8
  25. package/dist/plugins/application/auth.d.ts +5 -0
  26. package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +119 -0
  27. package/dist/plugins/application/dashboard/metrics-collector.d.ts +38 -2
  28. package/dist/plugins/application/dashboard/plugin.d.ts +53 -1
  29. package/dist/plugins/application/dashboard/static/charts.js +127 -62
  30. package/dist/plugins/application/dashboard/static/client.js +160 -0
  31. package/dist/plugins/application/dashboard/static/graph.mjs +167 -56
  32. package/dist/plugins/application/dashboard/static/reactflow.css +20 -10
  33. package/dist/plugins/application/dashboard/static/registry.js +112 -8
  34. package/dist/plugins/application/dashboard/static/requests.js +1167 -71
  35. package/dist/plugins/application/dashboard/static/styles.css +186 -14
  36. package/dist/plugins/application/dashboard/static/tabs.js +44 -9
  37. package/dist/plugins/application/dashboard/static/tabulator.css +23 -3
  38. package/dist/plugins/application/dashboard/static/theme.css +11 -2
  39. package/dist/plugins/application/mcp-server/plugin.d.ts +39 -0
  40. package/dist/plugins/application/openapi/analyzer.impl.d.ts +65 -1
  41. package/dist/plugins/application/openapi/openapi.d.ts +3 -0
  42. package/dist/plugins/application/shared/ast-utils.d.ts +7 -0
  43. package/dist/plugins/middleware/compression.d.ts +12 -2
  44. package/dist/plugins/middleware/rate-limit.d.ts +5 -0
  45. package/dist/router.d.ts +59 -19
  46. package/dist/server.d.ts +22 -0
  47. package/dist/shokupan.d.ts +31 -3
  48. package/dist/util/adapter/bun.d.ts +8 -0
  49. package/dist/util/adapter/filesystem.d.ts +20 -0
  50. package/dist/util/adapter/index.d.ts +4 -0
  51. package/dist/util/adapter/interface.d.ts +12 -0
  52. package/dist/util/adapter/node.d.ts +8 -0
  53. package/dist/util/adapter/wintercg.d.ts +5 -0
  54. package/dist/util/body-parser.d.ts +30 -0
  55. package/dist/util/controller-scanner.d.ts +4 -0
  56. package/dist/util/cpu-monitor.d.ts +2 -0
  57. package/dist/util/decorators.d.ts +20 -3
  58. package/dist/util/di.d.ts +3 -8
  59. package/dist/util/metadata.d.ts +18 -0
  60. package/dist/util/middleware-tracker.d.ts +10 -0
  61. package/dist/util/request.d.ts +1 -0
  62. package/dist/util/symbol.d.ts +1 -0
  63. package/dist/util/types.d.ts +167 -1
  64. package/package.json +7 -5
  65. package/dist/analyzer.impl-CV6W1Eq7.js.map +0 -1
  66. package/dist/analyzer.impl-D9Yi1Hax.cjs.map +0 -1
  67. package/dist/http-server-BEMPIs33.cjs +0 -85
  68. package/dist/http-server-BEMPIs33.cjs.map +0 -1
  69. package/dist/http-server-CCeagTyU.js +0 -68
  70. package/dist/http-server-CCeagTyU.js.map +0 -1
  71. package/dist/plugins/application/dashboard/static/failures.js +0 -85
  72. package/dist/plugins/application/dashboard/static/poll.js +0 -146
  73. 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
- async function updateCharts() {
256
- const period = document.getElementById('time-range-selector').value || '1m';
257
- try {
258
- const res = await fetch(`${url}metrics/history?interval=${period}`, { headers });
259
- const data = await res.json();
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
- const labels = metrics.map(m => new Date(m.timestamp).toLocaleTimeString());
263
-
264
- // Latency
265
- latencyChart.data.labels = labels;
266
- latencyChart.data.datasets[0].data = metrics.map(m => m.responseTime.avg);
267
- latencyChart.data.datasets[1].data = metrics.map(m => m.responseTime.p95);
268
- latencyChart.data.datasets[2].data = metrics.map(m => m.responseTime.p99);
269
- latencyChart.update();
270
-
271
- // RPS
272
- rpsChart.data.labels = labels;
273
- rpsChart.data.datasets[0].data = metrics.map(m => m.requests.total);
274
- rpsChart.data.datasets[1].data = metrics.map(m => m.requests.error);
275
- rpsChart.update();
276
-
277
- // CPU
278
- cpuChart.data.labels = labels;
279
- cpuChart.data.datasets[0].data = metrics.map(m => m.cpu);
280
- cpuChart.update();
281
-
282
- // Memory
283
- memoryChart.data.labels = labels;
284
- memoryChart.data.datasets[0].data = metrics.map(m => (m.memory.heapUsed / 1024 / 1024).toFixed(2));
285
- memoryChart.data.datasets[1].data = metrics.map(m => (m.memory.used / 1024 / 1024).toFixed(2));
286
- memoryChart.update();
287
-
288
- // Heap
289
- heapChart.data.labels = labels;
290
- heapChart.data.datasets[0].data = metrics.map(m => (m.memory.heapUsed / 1024 / 1024).toFixed(2));
291
- heapChart.data.datasets[1].data = metrics.map(m => (m.memory.heapTotal / 1024 / 1024).toFixed(2));
292
- heapChart.update();
293
-
294
- // Event Loop Latency
295
- eventLoopChart.data.labels = labels;
296
- eventLoopChart.data.datasets[0].data = metrics.map(m => m.eventLoopLatency.mean);
297
- eventLoopChart.data.datasets[1].data = metrics.map(m => m.eventLoopLatency.p95);
298
- eventLoopChart.data.datasets[2].data = metrics.map(m => m.eventLoopLatency.p99);
299
- eventLoopChart.update();
300
-
301
- // Error Rate
302
- errorRateChart.data.labels = labels;
303
- errorRateChart.data.datasets[0].data = metrics.map(m => {
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
- errorRateChart.data.datasets[1].data = metrics.map(m => {
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
- errorRateChart.update();
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
- updateCharts();
321
- // Poll every 10s for short intervals
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
+ })();