adonisjs-server-stats 1.2.1 → 1.3.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 (95) hide show
  1. package/README.md +144 -9
  2. package/dist/src/dashboard/chart_aggregator.d.ts +21 -0
  3. package/dist/src/dashboard/chart_aggregator.d.ts.map +1 -0
  4. package/dist/src/dashboard/chart_aggregator.js +89 -0
  5. package/dist/src/dashboard/dashboard_controller.d.ts +147 -0
  6. package/dist/src/dashboard/dashboard_controller.d.ts.map +1 -0
  7. package/dist/src/dashboard/dashboard_controller.js +1008 -0
  8. package/dist/src/dashboard/dashboard_routes.d.ts +16 -0
  9. package/dist/src/dashboard/dashboard_routes.d.ts.map +1 -0
  10. package/dist/src/dashboard/dashboard_routes.js +88 -0
  11. package/dist/src/dashboard/dashboard_store.d.ts +158 -0
  12. package/dist/src/dashboard/dashboard_store.d.ts.map +1 -0
  13. package/dist/src/dashboard/dashboard_store.js +723 -0
  14. package/dist/src/dashboard/integrations/cache_inspector.d.ts +88 -0
  15. package/dist/src/dashboard/integrations/cache_inspector.d.ts.map +1 -0
  16. package/dist/src/dashboard/integrations/cache_inspector.js +215 -0
  17. package/dist/src/dashboard/integrations/config_inspector.d.ts +33 -0
  18. package/dist/src/dashboard/integrations/config_inspector.d.ts.map +1 -0
  19. package/dist/src/dashboard/integrations/config_inspector.js +155 -0
  20. package/dist/src/dashboard/integrations/index.d.ts +7 -0
  21. package/dist/src/dashboard/integrations/index.d.ts.map +1 -0
  22. package/dist/src/dashboard/integrations/index.js +3 -0
  23. package/dist/src/dashboard/integrations/queue_inspector.d.ts +106 -0
  24. package/dist/src/dashboard/integrations/queue_inspector.d.ts.map +1 -0
  25. package/dist/src/dashboard/integrations/queue_inspector.js +182 -0
  26. package/dist/src/dashboard/migrator.d.ts +18 -0
  27. package/dist/src/dashboard/migrator.d.ts.map +1 -0
  28. package/dist/src/dashboard/migrator.js +144 -0
  29. package/dist/src/dashboard/models/stats_email.d.ts +19 -0
  30. package/dist/src/dashboard/models/stats_email.d.ts.map +1 -0
  31. package/dist/src/dashboard/models/stats_email.js +66 -0
  32. package/dist/src/dashboard/models/stats_event.d.ts +14 -0
  33. package/dist/src/dashboard/models/stats_event.d.ts.map +1 -0
  34. package/dist/src/dashboard/models/stats_event.js +43 -0
  35. package/dist/src/dashboard/models/stats_log.d.ts +12 -0
  36. package/dist/src/dashboard/models/stats_log.d.ts.map +1 -0
  37. package/dist/src/dashboard/models/stats_log.js +42 -0
  38. package/dist/src/dashboard/models/stats_metric.d.ts +15 -0
  39. package/dist/src/dashboard/models/stats_metric.d.ts.map +1 -0
  40. package/dist/src/dashboard/models/stats_metric.js +50 -0
  41. package/dist/src/dashboard/models/stats_query.d.ts +20 -0
  42. package/dist/src/dashboard/models/stats_query.d.ts.map +1 -0
  43. package/dist/src/dashboard/models/stats_query.js +67 -0
  44. package/dist/src/dashboard/models/stats_request.d.ts +21 -0
  45. package/dist/src/dashboard/models/stats_request.d.ts.map +1 -0
  46. package/dist/src/dashboard/models/stats_request.js +61 -0
  47. package/dist/src/dashboard/models/stats_saved_filter.d.ts +11 -0
  48. package/dist/src/dashboard/models/stats_saved_filter.d.ts.map +1 -0
  49. package/dist/src/dashboard/models/stats_saved_filter.js +38 -0
  50. package/dist/src/dashboard/models/stats_trace.d.ts +19 -0
  51. package/dist/src/dashboard/models/stats_trace.d.ts.map +1 -0
  52. package/dist/src/dashboard/models/stats_trace.js +67 -0
  53. package/dist/src/debug/debug_store.d.ts +5 -0
  54. package/dist/src/debug/debug_store.d.ts.map +1 -1
  55. package/dist/src/debug/debug_store.js +10 -0
  56. package/dist/src/debug/email_collector.d.ts +2 -0
  57. package/dist/src/debug/email_collector.d.ts.map +1 -1
  58. package/dist/src/debug/email_collector.js +4 -0
  59. package/dist/src/debug/event_collector.d.ts +2 -0
  60. package/dist/src/debug/event_collector.d.ts.map +1 -1
  61. package/dist/src/debug/event_collector.js +11 -2
  62. package/dist/src/debug/query_collector.d.ts +2 -0
  63. package/dist/src/debug/query_collector.d.ts.map +1 -1
  64. package/dist/src/debug/query_collector.js +11 -0
  65. package/dist/src/debug/ring_buffer.d.ts +3 -0
  66. package/dist/src/debug/ring_buffer.d.ts.map +1 -1
  67. package/dist/src/debug/ring_buffer.js +6 -0
  68. package/dist/src/debug/trace_collector.d.ts +4 -2
  69. package/dist/src/debug/trace_collector.d.ts.map +1 -1
  70. package/dist/src/debug/trace_collector.js +7 -2
  71. package/dist/src/debug/types.d.ts +8 -0
  72. package/dist/src/debug/types.d.ts.map +1 -1
  73. package/dist/src/edge/client/dashboard.css +1504 -0
  74. package/dist/src/edge/client/dashboard.js +2378 -0
  75. package/dist/src/edge/client/debug-panel.css +530 -110
  76. package/dist/src/edge/client/debug-panel.js +663 -22
  77. package/dist/src/edge/client/stats-bar.css +115 -41
  78. package/dist/src/edge/client/stats-bar.js +37 -3
  79. package/dist/src/edge/plugin.d.ts.map +1 -1
  80. package/dist/src/edge/plugin.js +21 -0
  81. package/dist/src/edge/views/dashboard.edge +382 -0
  82. package/dist/src/edge/views/debug-panel.edge +60 -14
  83. package/dist/src/edge/views/stats-bar.edge +9 -0
  84. package/dist/src/index.d.ts +2 -0
  85. package/dist/src/index.d.ts.map +1 -1
  86. package/dist/src/index.js +1 -0
  87. package/dist/src/middleware/request_tracking_middleware.d.ts +20 -0
  88. package/dist/src/middleware/request_tracking_middleware.d.ts.map +1 -1
  89. package/dist/src/middleware/request_tracking_middleware.js +66 -2
  90. package/dist/src/provider/server_stats_provider.d.ts +13 -0
  91. package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
  92. package/dist/src/provider/server_stats_provider.js +175 -1
  93. package/dist/src/types.d.ts +42 -0
  94. package/dist/src/types.d.ts.map +1 -1
  95. package/package.json +14 -1
@@ -1,20 +1,94 @@
1
1
  /* Scoped CSS for the Edge server stats bar.
2
2
  * All classes use the `.ss-` prefix to avoid conflicts with Tailwind or app styles.
3
+ * Theme via CSS custom properties scoped to .ss-bar and .ss-toggle.
3
4
  */
4
5
 
6
+ /* ── Theme: Dark (default) ────────────────────────────────────── */
7
+ .ss-bar, .ss-toggle {
8
+ --ss-bg-deep: #0a0a0a;
9
+ --ss-surface: #171717;
10
+ --ss-surface-alt: #141414;
11
+ --ss-text: #d4d4d4;
12
+ --ss-text-bright: #e5e5e5;
13
+ --ss-text-secondary: #a3a3a3;
14
+ --ss-muted: #737373;
15
+ --ss-dim: #525252;
16
+ --ss-accent: #34d399;
17
+ --ss-amber-fg: #fbbf24;
18
+ --ss-red-fg: #f87171;
19
+ --ss-border: #333;
20
+ --ss-border-dim: #262626;
21
+ --ss-border-strong: #404040;
22
+ --ss-hover: rgba(38,38,38,0.4);
23
+ --ss-hover-subtle: rgba(38,38,38,0.25);
24
+ --ss-shadow: rgb(0 0 0 / 0.15);
25
+ --ss-tooltip-bg: #262626;
26
+ --ss-tooltip-border: rgba(255,255,255,0.1);
27
+ }
28
+
29
+ /* ── Theme: Light (auto via system preference) ────────────────── */
30
+ @media (prefers-color-scheme: light) {
31
+ .ss-bar:not([data-ss-theme="dark"]),
32
+ .ss-toggle:not([data-ss-theme="dark"]) {
33
+ --ss-bg-deep: #f0f0f0;
34
+ --ss-surface: #ffffff;
35
+ --ss-surface-alt: #f5f5f5;
36
+ --ss-text: #171717;
37
+ --ss-text-bright: #0f0f0f;
38
+ --ss-text-secondary: #525252;
39
+ --ss-muted: #6b7280;
40
+ --ss-dim: #9ca3af;
41
+ --ss-accent: #059669;
42
+ --ss-amber-fg: #b45309;
43
+ --ss-red-fg: #dc2626;
44
+ --ss-border: #e5e5e5;
45
+ --ss-border-dim: #e5e5e5;
46
+ --ss-border-strong: #d4d4d4;
47
+ --ss-hover: rgba(0,0,0,0.04);
48
+ --ss-hover-subtle: rgba(0,0,0,0.02);
49
+ --ss-shadow: rgb(0 0 0 / 0.06);
50
+ --ss-tooltip-bg: #ffffff;
51
+ --ss-tooltip-border: rgba(0,0,0,0.1);
52
+ }
53
+ }
54
+
55
+ /* ── Theme: Light (manual override) ───────────────────────────── */
56
+ .ss-bar[data-ss-theme="light"],
57
+ .ss-toggle[data-ss-theme="light"] {
58
+ --ss-bg-deep: #f0f0f0;
59
+ --ss-surface: #ffffff;
60
+ --ss-surface-alt: #f5f5f5;
61
+ --ss-text: #171717;
62
+ --ss-text-bright: #0f0f0f;
63
+ --ss-text-secondary: #525252;
64
+ --ss-muted: #6b7280;
65
+ --ss-dim: #9ca3af;
66
+ --ss-accent: #059669;
67
+ --ss-amber-fg: #b45309;
68
+ --ss-red-fg: #dc2626;
69
+ --ss-border: #e5e5e5;
70
+ --ss-border-dim: #e5e5e5;
71
+ --ss-border-strong: #d4d4d4;
72
+ --ss-hover: rgba(0,0,0,0.04);
73
+ --ss-hover-subtle: rgba(0,0,0,0.02);
74
+ --ss-shadow: rgb(0 0 0 / 0.06);
75
+ --ss-tooltip-bg: #ffffff;
76
+ --ss-tooltip-border: rgba(0,0,0,0.1);
77
+ }
78
+
5
79
  .ss-bar {
6
80
  position: fixed;
7
81
  inset-inline: 0;
8
82
  bottom: 0;
9
- z-index: 50;
83
+ z-index: 150;
10
84
  display: flex;
11
85
  height: 28px;
12
86
  align-items: center;
13
- border-top: 1px solid #262626;
14
- background: #0a0a0a;
87
+ border-top: 1px solid var(--ss-border-dim);
88
+ background: var(--ss-bg-deep);
15
89
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
16
- color: #a3a3a3;
17
- box-shadow: 0 -4px 6px -1px rgb(0 0 0 / 0.1), 0 -2px 4px -2px rgb(0 0 0 / 0.1);
90
+ color: var(--ss-text-secondary);
91
+ box-shadow: 0 -4px 6px -1px var(--ss-shadow), 0 -2px 4px -2px var(--ss-shadow);
18
92
  }
19
93
  .ss-bar.ss-hidden { display: none; }
20
94
 
@@ -44,7 +118,7 @@
44
118
  align-items: center;
45
119
  flex-shrink: 0;
46
120
  gap: 0;
47
- background: rgba(38, 38, 38, 0.25);
121
+ background: var(--ss-hover-subtle);
48
122
  border-radius: 4px;
49
123
  padding: 0 1px;
50
124
  }
@@ -52,7 +126,7 @@
52
126
  .ss-group-sep {
53
127
  width: 1px;
54
128
  height: 14px;
55
- background: #333;
129
+ background: var(--ss-border);
56
130
  flex-shrink: 0;
57
131
  }
58
132
 
@@ -68,58 +142,58 @@
68
142
  .ss-badge-link {
69
143
  cursor: pointer;
70
144
  }
71
- .ss-badge:hover { background: rgba(38, 38, 38, 0.6); }
72
- .ss-badge.ss-pinned { background: rgba(38, 38, 38, 0.8); }
145
+ .ss-badge:hover { background: var(--ss-hover); }
146
+ .ss-badge.ss-pinned { background: var(--ss-hover); }
73
147
 
74
148
  .ss-label {
75
149
  font-size: 10px;
76
150
  font-weight: 500;
77
151
  letter-spacing: 0.05em;
78
- color: #737373;
152
+ color: var(--ss-muted);
79
153
  }
80
154
  .ss-value {
81
155
  font-size: 11px;
82
156
  font-weight: 600;
83
157
  font-variant-numeric: tabular-nums;
84
- color: #34d399;
158
+ color: var(--ss-accent);
85
159
  }
86
160
 
87
161
  .ss-dot {
88
162
  width: 6px;
89
163
  height: 6px;
90
164
  border-radius: 50%;
91
- background: #34d399;
165
+ background: var(--ss-accent);
92
166
  flex-shrink: 0;
93
167
  }
94
- .ss-dot.ss-stale { background: #f59e0b; }
168
+ .ss-dot.ss-stale { background: var(--ss-amber-fg); }
95
169
 
96
- .ss-green { color: #34d399; }
97
- .ss-amber { color: #fbbf24; }
98
- .ss-red { color: #f87171; }
99
- .ss-muted { color: #737373; }
170
+ .ss-green { color: var(--ss-accent); }
171
+ .ss-amber { color: var(--ss-amber-fg); }
172
+ .ss-red { color: var(--ss-red-fg); }
173
+ .ss-muted { color: var(--ss-muted); }
100
174
 
101
175
  /* Toggle button */
102
176
  .ss-toggle {
103
177
  position: fixed;
104
178
  right: 12px;
105
- z-index: 50;
179
+ z-index: 150;
106
180
  display: flex;
107
181
  align-items: center;
108
182
  gap: 6px;
109
183
  border-radius: 4px;
110
- border: 1px solid #404040;
111
- background: #171717;
184
+ border: 1px solid var(--ss-border-strong);
185
+ background: var(--ss-surface);
112
186
  padding: 2px 8px;
113
187
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
114
188
  font-size: 10px;
115
189
  text-transform: uppercase;
116
- color: #a3a3a3;
190
+ color: var(--ss-text-secondary);
117
191
  cursor: pointer;
118
192
  transition: border-color 0.15s, color 0.15s;
119
193
  }
120
194
  .ss-toggle:hover {
121
- border-color: #525252;
122
- color: #e5e5e5;
195
+ border-color: var(--ss-dim);
196
+ color: var(--ss-text-bright);
123
197
  }
124
198
  .ss-toggle.ss-visible { bottom: 36px; }
125
199
  .ss-toggle.ss-collapsed { bottom: 12px; }
@@ -128,7 +202,7 @@
128
202
  display: flex;
129
203
  align-items: center;
130
204
  gap: 6px;
131
- color: #737373;
205
+ color: var(--ss-muted);
132
206
  }
133
207
  .ss-toggle-summary .ss-value {
134
208
  font-size: 10px;
@@ -139,7 +213,7 @@
139
213
  /* Tooltip — positioned absolutely within .ss-bar (outside scroll area) via JS */
140
214
  .ss-tooltip {
141
215
  position: absolute;
142
- z-index: 60;
216
+ z-index: 180;
143
217
  pointer-events: none;
144
218
  }
145
219
  .ss-tooltip.ss-pinned {
@@ -147,12 +221,12 @@
147
221
  }
148
222
  .ss-tooltip-inner {
149
223
  border-radius: 8px;
150
- background: #262626;
224
+ background: var(--ss-tooltip-bg);
151
225
  padding: 10px 12px;
152
226
  font-size: 11px;
153
- color: #d4d4d4;
154
- box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.25);
155
- border: 1px solid rgba(255,255,255,0.1);
227
+ color: var(--ss-text);
228
+ box-shadow: 0 20px 25px -5px var(--ss-shadow);
229
+ border: 1px solid var(--ss-tooltip-border);
156
230
  min-width: 160px;
157
231
  }
158
232
  .ss-tooltip-close {
@@ -161,14 +235,14 @@
161
235
  right: 6px;
162
236
  background: none;
163
237
  border: none;
164
- color: #737373;
238
+ color: var(--ss-muted);
165
239
  font-size: 14px;
166
240
  cursor: pointer;
167
241
  padding: 0 4px;
168
242
  line-height: 1;
169
243
  font-family: inherit;
170
244
  }
171
- .ss-tooltip-close:hover { color: #e5e5e5; }
245
+ .ss-tooltip-close:hover { color: var(--ss-text-bright); }
172
246
  .ss-tooltip-header {
173
247
  display: flex;
174
248
  align-items: baseline;
@@ -177,44 +251,44 @@
177
251
  }
178
252
  .ss-tooltip-title {
179
253
  font-weight: 500;
180
- color: #f5f5f5;
254
+ color: var(--ss-text-bright);
181
255
  }
182
256
  .ss-tooltip-unit {
183
257
  font-size: 10px;
184
- color: #737373;
258
+ color: var(--ss-muted);
185
259
  }
186
260
  .ss-tooltip-current {
187
261
  margin-top: 6px;
188
262
  font-variant-numeric: tabular-nums;
189
263
  }
190
- .ss-tooltip-current-label { color: #a3a3a3; }
191
- .ss-tooltip-current-value { font-weight: 600; color: #f5f5f5; }
264
+ .ss-tooltip-current-label { color: var(--ss-text-secondary); }
265
+ .ss-tooltip-current-value { font-weight: 600; color: var(--ss-text-bright); }
192
266
  .ss-tooltip-stats {
193
267
  margin-top: 4px;
194
268
  display: flex;
195
269
  gap: 12px;
196
270
  font-size: 10px;
197
271
  font-variant-numeric: tabular-nums;
198
- color: #a3a3a3;
272
+ color: var(--ss-text-secondary);
199
273
  }
200
274
  .ss-tooltip-details {
201
275
  margin-top: 6px;
202
276
  font-size: 10px;
203
277
  line-height: 1.625;
204
- color: #737373;
278
+ color: var(--ss-muted);
205
279
  }
206
280
  .ss-tooltip-sparkline {
207
281
  margin-top: 8px;
208
282
  overflow: hidden;
209
283
  border-radius: 4px;
210
- border: 1px solid rgba(64,64,64,0.5);
211
- background: rgba(23,23,23,0.5);
284
+ border: 1px solid var(--ss-border-dim);
285
+ background: var(--ss-surface-alt);
212
286
  }
213
287
  .ss-tooltip-samples {
214
288
  margin-top: 4px;
215
289
  text-align: center;
216
290
  font-size: 9px;
217
- color: #525252;
291
+ color: var(--ss-dim);
218
292
  }
219
293
  .ss-tooltip-arrow {
220
294
  position: absolute;
@@ -225,5 +299,5 @@
225
299
  height: 0;
226
300
  border-left: 5px solid transparent;
227
301
  border-right: 5px solid transparent;
228
- border-top: 5px solid #262626;
302
+ border-top: 5px solid var(--ss-tooltip-bg);
229
303
  }
@@ -16,6 +16,32 @@
16
16
 
17
17
  if (!bar || !toggle) return;
18
18
 
19
+ // ── Theme detection & application ───────────────────────────────
20
+ let themeOverride = localStorage.getItem('ss-dash-theme');
21
+
22
+ const applyBarTheme = () => {
23
+ if (themeOverride) {
24
+ bar.setAttribute('data-ss-theme', themeOverride);
25
+ toggle.setAttribute('data-ss-theme', themeOverride);
26
+ } else {
27
+ bar.removeAttribute('data-ss-theme');
28
+ toggle.removeAttribute('data-ss-theme');
29
+ }
30
+ };
31
+
32
+ applyBarTheme();
33
+
34
+ // Expose for debug-panel toggle to call directly
35
+ window.__ssApplyBarTheme = applyBarTheme;
36
+
37
+ // Listen for cross-tab theme changes
38
+ window.addEventListener('storage', function (e) {
39
+ if (e.key === 'ss-dash-theme') {
40
+ themeOverride = e.newValue;
41
+ applyBarTheme();
42
+ }
43
+ });
44
+
19
45
  const ENDPOINT = bar.dataset.endpoint || '/admin/api/server-stats';
20
46
  const INTERVAL = Number(bar.dataset.interval) || 3000;
21
47
  const MAX_HISTORY = 60;
@@ -63,9 +89,17 @@
63
89
  const thresh = (v, warn, crit) => v > crit ? 'ss-red' : v > warn ? 'ss-amber' : 'ss-green';
64
90
  const threshInverse = (v, warn, crit) => v < crit ? 'ss-red' : v < warn ? 'ss-amber' : 'ss-green';
65
91
 
66
- // Map color class → hex for sparklines
67
- const HEX = { 'ss-red': '#f87171', 'ss-amber': '#fbbf24', 'ss-green': '#34d399', 'ss-muted': '#737373' };
68
- const hexFromClass = (cls) => HEX[cls] || '#34d399';
92
+ // Map color class → CSS variable for sparklines (reads themed value at render time)
93
+ const HEX_FALLBACK = { 'ss-red': '#f87171', 'ss-amber': '#fbbf24', 'ss-green': '#34d399', 'ss-muted': '#737373' };
94
+ const HEX_VAR = { 'ss-red': '--ss-red-fg', 'ss-amber': '--ss-amber-fg', 'ss-green': '--ss-accent', 'ss-muted': '--ss-muted' };
95
+ const hexFromClass = (cls) => {
96
+ const varName = HEX_VAR[cls];
97
+ if (varName) {
98
+ const val = getComputedStyle(bar).getPropertyValue(varName).trim();
99
+ if (val) return val;
100
+ }
101
+ return HEX_FALLBACK[cls] || '#34d399';
102
+ };
69
103
 
70
104
  const ratioColor = (used, max) => {
71
105
  if (max === 0) return 'ss-muted';
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/edge/plugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,IACrD,MAAM,GAAG,UAgIlB"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/edge/plugin.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA0BrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,IACrD,MAAM,GAAG,UAoIlB"}
@@ -1,9 +1,26 @@
1
1
  import { readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
2
3
  import { dirname, join } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { Template } from "edge.js";
5
6
  const DIR = dirname(fileURLToPath(import.meta.url));
6
7
  const read = (rel) => readFileSync(join(DIR, rel), "utf-8");
8
+ /**
9
+ * Try to locate and read the @adonisjs/transmit-client build file.
10
+ * Returns the file contents wrapped to expose `window.Transmit`, or
11
+ * an empty string if the package is not installed.
12
+ */
13
+ function loadTransmitClient() {
14
+ try {
15
+ const req = createRequire(join(process.cwd(), "package.json"));
16
+ const clientPath = req.resolve("@adonisjs/transmit-client/build/index.js");
17
+ const src = readFileSync(clientPath, "utf-8");
18
+ return `(function(){var __exports={};(function(){${src.replace(/^export\s*\{[^}]*\}\s*;?\s*$/m, "")}\n__exports.Transmit=Transmit;})();window.Transmit=__exports.Transmit;})()`;
19
+ }
20
+ catch {
21
+ return "";
22
+ }
23
+ }
7
24
  /**
8
25
  * Edge plugin that registers the `@serverStats()` tag.
9
26
  *
@@ -99,6 +116,10 @@ export function edgePluginServerStats(config) {
99
116
  state.logsEndpoint = "/admin/api/debug/logs";
100
117
  state.customPanes = config.devToolbar?.panes || [];
101
118
  state.showTracing = !!config.devToolbar?.tracing;
119
+ state.dashboardPath = config.devToolbar?.dashboard
120
+ ? (config.devToolbar.dashboardPath || '/__stats')
121
+ : null;
122
+ state.transmitClient = loadTransmitClient();
102
123
  }
103
124
  // Pre-render via Template directly — bypasses edge.createRenderer() which
104
125
  // would re-run #executePlugins and cause infinite recursion.