adonisjs-server-stats 1.4.0 → 1.5.2

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 (84) hide show
  1. package/README.md +272 -142
  2. package/dist/configure.d.ts.map +1 -1
  3. package/dist/src/controller/debug_controller.d.ts +2 -2
  4. package/dist/src/controller/debug_controller.d.ts.map +1 -1
  5. package/dist/src/controller/server_stats_controller.d.ts +1 -1
  6. package/dist/src/controller/server_stats_controller.d.ts.map +1 -1
  7. package/dist/src/dashboard/chart_aggregator.d.ts.map +1 -1
  8. package/dist/src/dashboard/chart_aggregator.js +8 -8
  9. package/dist/src/dashboard/dashboard_controller.d.ts +12 -97
  10. package/dist/src/dashboard/dashboard_controller.d.ts.map +1 -1
  11. package/dist/src/dashboard/dashboard_controller.js +244 -522
  12. package/dist/src/dashboard/dashboard_routes.d.ts.map +1 -1
  13. package/dist/src/dashboard/dashboard_routes.js +7 -2
  14. package/dist/src/dashboard/dashboard_store.d.ts +6 -3
  15. package/dist/src/dashboard/dashboard_store.d.ts.map +1 -1
  16. package/dist/src/dashboard/dashboard_store.js +54 -78
  17. package/dist/src/dashboard/integrations/cache_inspector.d.ts.map +1 -1
  18. package/dist/src/dashboard/integrations/queue_inspector.d.ts.map +1 -1
  19. package/dist/src/dashboard/migrator.d.ts.map +1 -1
  20. package/dist/src/dashboard/migrator.js +3 -1
  21. package/dist/src/dashboard/models/stats_event.d.ts +1 -1
  22. package/dist/src/dashboard/models/stats_event.d.ts.map +1 -1
  23. package/dist/src/dashboard/models/stats_query.d.ts +1 -1
  24. package/dist/src/dashboard/models/stats_query.d.ts.map +1 -1
  25. package/dist/src/dashboard/models/stats_request.d.ts +2 -2
  26. package/dist/src/dashboard/models/stats_request.d.ts.map +1 -1
  27. package/dist/src/dashboard/models/stats_request.js +1 -1
  28. package/dist/src/dashboard/models/stats_trace.d.ts +1 -1
  29. package/dist/src/dashboard/models/stats_trace.d.ts.map +1 -1
  30. package/dist/src/debug/debug_store.d.ts +6 -6
  31. package/dist/src/debug/debug_store.d.ts.map +1 -1
  32. package/dist/src/debug/debug_store.js +10 -10
  33. package/dist/src/debug/email_collector.d.ts +0 -9
  34. package/dist/src/debug/email_collector.d.ts.map +1 -1
  35. package/dist/src/debug/email_collector.js +6 -28
  36. package/dist/src/debug/event_collector.d.ts +1 -1
  37. package/dist/src/debug/event_collector.d.ts.map +1 -1
  38. package/dist/src/debug/event_collector.js +17 -17
  39. package/dist/src/debug/query_collector.d.ts +1 -1
  40. package/dist/src/debug/query_collector.d.ts.map +1 -1
  41. package/dist/src/debug/query_collector.js +13 -14
  42. package/dist/src/debug/ring_buffer.d.ts.map +1 -1
  43. package/dist/src/debug/route_inspector.d.ts +1 -1
  44. package/dist/src/debug/route_inspector.d.ts.map +1 -1
  45. package/dist/src/debug/route_inspector.js +12 -12
  46. package/dist/src/debug/trace_collector.d.ts.map +1 -1
  47. package/dist/src/debug/trace_collector.js +6 -5
  48. package/dist/src/edge/client/dashboard.css +516 -171
  49. package/dist/src/edge/client/dashboard.js +2756 -1662
  50. package/dist/src/edge/client/debug-panel.css +476 -133
  51. package/dist/src/edge/client/debug-panel.js +1496 -1043
  52. package/dist/src/edge/client/stats-bar.css +64 -30
  53. package/dist/src/edge/client/stats-bar.js +598 -319
  54. package/dist/src/edge/plugin.d.ts +1 -1
  55. package/dist/src/edge/plugin.d.ts.map +1 -1
  56. package/dist/src/edge/plugin.js +41 -59
  57. package/dist/src/edge/views/stats-bar.edge +1 -1
  58. package/dist/src/index.d.ts +1 -1
  59. package/dist/src/index.d.ts.map +1 -1
  60. package/dist/src/middleware/request_tracking_middleware.d.ts +4 -4
  61. package/dist/src/middleware/request_tracking_middleware.d.ts.map +1 -1
  62. package/dist/src/middleware/request_tracking_middleware.js +7 -6
  63. package/dist/src/prometheus/prometheus_collector.d.ts +1 -1
  64. package/dist/src/prometheus/prometheus_collector.d.ts.map +1 -1
  65. package/dist/src/provider/server_stats_provider.d.ts +1 -1
  66. package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
  67. package/dist/src/provider/server_stats_provider.js +33 -32
  68. package/dist/src/types.d.ts +2 -2
  69. package/dist/src/utils/json_helpers.d.ts +8 -0
  70. package/dist/src/utils/json_helpers.d.ts.map +1 -0
  71. package/dist/src/utils/json_helpers.js +21 -0
  72. package/dist/src/utils/mail_helpers.d.ts +13 -0
  73. package/dist/src/utils/mail_helpers.d.ts.map +1 -0
  74. package/dist/src/utils/mail_helpers.js +26 -0
  75. package/dist/src/utils/math_helpers.d.ts +8 -0
  76. package/dist/src/utils/math_helpers.d.ts.map +1 -0
  77. package/dist/src/utils/math_helpers.js +11 -0
  78. package/dist/src/utils/time_helpers.d.ts +12 -0
  79. package/dist/src/utils/time_helpers.d.ts.map +1 -0
  80. package/dist/src/utils/time_helpers.js +32 -0
  81. package/dist/src/utils/transmit_client.d.ts +9 -0
  82. package/dist/src/utils/transmit_client.d.ts.map +1 -0
  83. package/dist/src/utils/transmit_client.js +20 -0
  84. package/package.json +35 -29
@@ -1,4 +1,4 @@
1
- import type { ServerStatsConfig } from "../types.js";
1
+ import type { ServerStatsConfig } from '../types.js';
2
2
  /**
3
3
  * Edge plugin that registers the `@serverStats()` tag.
4
4
  *
@@ -1 +1 @@
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
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/edge/plugin.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAKpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,IACrD,MAAM,GAAG,UAmHlB"}
@@ -1,26 +1,10 @@
1
- import { readFileSync } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { Template } from "edge.js";
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Template } from 'edge.js';
5
+ import { loadTransmitClient } from '../utils/transmit_client.js';
6
6
  const DIR = dirname(fileURLToPath(import.meta.url));
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
+ const read = (rel) => readFileSync(join(DIR, rel), 'utf-8');
24
8
  /**
25
9
  * Edge plugin that registers the `@serverStats()` tag.
26
10
  *
@@ -43,64 +27,62 @@ function loadTransmitClient() {
43
27
  export function edgePluginServerStats(config) {
44
28
  return (edge) => {
45
29
  // Mount Edge views under the `ss` disk (needed for @include resolution)
46
- edge.mount("ss", join(DIR, "views"));
30
+ edge.mount('ss', join(DIR, 'views'));
47
31
  // Read client assets once at boot
48
- const css = read("client/stats-bar.css");
49
- const js = read("client/stats-bar.js");
50
- const endpoint = typeof config.endpoint === "string"
51
- ? config.endpoint
52
- : "/admin/api/server-stats";
32
+ const css = read('client/stats-bar.css');
33
+ const js = read('client/stats-bar.js');
34
+ const endpoint = typeof config.endpoint === 'string' ? config.endpoint : '/admin/api/server-stats';
53
35
  const intervalMs = config.intervalMs || 3000;
54
36
  const showDebug = !!config.devToolbar?.enabled;
55
37
  // Badge groups for the Edge template
56
38
  const groups = [
57
39
  // Process
58
40
  [
59
- { id: "node", label: "NODE" },
60
- { id: "up", label: "UP" },
61
- { id: "cpu", label: "CPU" },
62
- { id: "evt", label: "EVT" },
41
+ { id: 'node', label: 'NODE' },
42
+ { id: 'up', label: 'UP' },
43
+ { id: 'cpu', label: 'CPU' },
44
+ { id: 'evt', label: 'EVT' },
63
45
  ],
64
46
  // Memory
65
47
  [
66
- { id: "mem", label: "HEAP" },
67
- { id: "rss", label: "RSS" },
68
- { id: "sys", label: "SYS" },
48
+ { id: 'mem', label: 'HEAP' },
49
+ { id: 'rss', label: 'RSS' },
50
+ { id: 'sys', label: 'SYS' },
69
51
  ],
70
52
  // HTTP
71
53
  [
72
- { id: "rps", label: "REQ/s" },
73
- { id: "avg", label: "AVG" },
74
- { id: "err", label: "ERR" },
75
- { id: "conn", label: "CONN" },
54
+ { id: 'rps', label: 'REQ/s' },
55
+ { id: 'avg', label: 'AVG' },
56
+ { id: 'err', label: 'ERR' },
57
+ { id: 'conn', label: 'CONN' },
76
58
  ],
77
59
  // DB
78
- [{ id: "db", label: "DB" }],
60
+ [{ id: 'db', label: 'DB' }],
79
61
  // Redis
80
62
  [
81
- { id: "redis", label: "REDIS" },
82
- { id: "rmem", label: "MEM" },
83
- { id: "rkeys", label: "KEYS" },
84
- { id: "rhit", label: "HIT" },
63
+ { id: 'redis', label: 'REDIS' },
64
+ { id: 'rmem', label: 'MEM' },
65
+ { id: 'rkeys', label: 'KEYS' },
66
+ { id: 'rhit', label: 'HIT' },
85
67
  ],
86
68
  // Queue
87
69
  [
88
- { id: "q", label: "Q" },
89
- { id: "workers", label: "WORKERS" },
70
+ { id: 'q', label: 'Q' },
71
+ { id: 'workers', label: 'WORKERS' },
90
72
  ],
91
73
  // App
92
74
  [
93
- { id: "users", label: "USERS" },
94
- { id: "hooks", label: "HOOKS" },
95
- { id: "mail", label: "MAIL" },
75
+ { id: 'users', label: 'USERS' },
76
+ { id: 'hooks', label: 'HOOKS' },
77
+ { id: 'mail', label: 'MAIL' },
96
78
  ],
97
79
  // Logs
98
80
  [
99
- { id: "logerr", label: "LOG ERR" },
100
- { id: "lograte", label: "LOG/m" },
81
+ { id: 'logerr', label: 'LOG ERR' },
82
+ { id: 'lograte', label: 'LOG/m' },
101
83
  ],
102
84
  // Debug (conditional)
103
- ...(showDebug ? [[{ id: "dbg-queries", label: "QRY" }]] : []),
85
+ ...(showDebug ? [[{ id: 'dbg-queries', label: 'QRY' }]] : []),
104
86
  ];
105
87
  const state = {
106
88
  css,
@@ -111,25 +93,25 @@ export function edgePluginServerStats(config) {
111
93
  groups,
112
94
  };
113
95
  if (showDebug) {
114
- state.debugCss = read("client/debug-panel.css");
115
- state.debugJs = read("client/debug-panel.js");
116
- state.logsEndpoint = "/admin/api/debug/logs";
96
+ state.debugCss = read('client/debug-panel.css');
97
+ state.debugJs = read('client/debug-panel.js');
98
+ state.logsEndpoint = '/admin/api/debug/logs';
117
99
  state.customPanes = config.devToolbar?.panes || [];
118
100
  state.showTracing = !!config.devToolbar?.tracing;
119
101
  state.dashboardPath = config.devToolbar?.dashboard
120
- ? (config.devToolbar.dashboardPath || '/__stats')
102
+ ? config.devToolbar.dashboardPath || '/__stats'
121
103
  : null;
122
- state.transmitClient = loadTransmitClient();
104
+ state.transmitClient = loadTransmitClient(join(process.cwd(), 'package.json'));
123
105
  }
124
106
  // Pre-render via Template directly — bypasses edge.createRenderer() which
125
107
  // would re-run #executePlugins and cause infinite recursion.
126
108
  const template = new Template(edge.compiler, edge.globals, {}, edge.processor);
127
- const html = template.render("ss::stats-bar", state);
109
+ const html = template.render('ss::stats-bar', state);
128
110
  const escaped = JSON.stringify(html);
129
111
  // Track whether shouldShow is configured (controls render-time guard)
130
112
  const hasShouldShow = !!config.shouldShow;
131
113
  edge.registerTag({
132
- tagName: "serverStats",
114
+ tagName: 'serverStats',
133
115
  block: false,
134
116
  seekable: true,
135
117
  compile(_parser, buffer, token) {
@@ -5,7 +5,7 @@
5
5
  <div id="ss-bar" class="ss-bar" data-endpoint="{{ endpoint }}" data-interval="{{ intervalMs }}">
6
6
  <div class="ss-bar-left">
7
7
  @if(showDebug)
8
- <button type="button" id="ss-dbg-wrench" class="ss-dbg-btn" title="Open debug panel">🔍</button>
8
+ <button type="button" id="ss-dbg-wrench" class="ss-dbg-btn" title="Open debug panel">🔍 Open debug panel</button>
9
9
  @end
10
10
  <div id="ss-dot" class="ss-dot"></div>
11
11
  </div>
@@ -4,7 +4,7 @@ export { RequestMetrics } from './engine/request_metrics.js';
4
4
  export { trace } from './debug/trace_collector.js';
5
5
  export { DashboardStore } from './dashboard/dashboard_store.js';
6
6
  export type { MetricCollector } from './collectors/collector.js';
7
- export type { MetricValue, ServerStats, ServerStatsConfig, LogStats, DevToolbarOptions } from './types.js';
7
+ export type { MetricValue, ServerStats, ServerStatsConfig, LogStats, DevToolbarOptions, } from './types.js';
8
8
  export type { DebugPane, DebugPaneColumn, DebugPaneFormatType, DebugPaneSearch, BadgeColor, QueryRecord, EventRecord, EmailRecord, RouteRecord, TraceSpan, TraceRecord, DevToolbarConfig, } from './debug/types.js';
9
9
  export type { RequestFilters, QueryFilters, EventFilters, EmailFilters, LogFilters, TraceFilters, PaginatedResult, } from './dashboard/dashboard_store.js';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC1G,YAAY,EACV,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,eAAe,GAChB,MAAM,gCAAgC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EACV,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,iBAAiB,GAClB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,eAAe,GAChB,MAAM,gCAAgC,CAAA"}
@@ -1,7 +1,7 @@
1
- import type { HttpContext } from "@adonisjs/core/http";
2
- import type { NextFn } from "@adonisjs/core/types/http";
3
- import type { TraceCollector } from "../debug/trace_collector.js";
4
- import type { TraceRecord } from "../debug/types.js";
1
+ import type { TraceCollector } from '../debug/trace_collector.js';
2
+ import type { TraceRecord } from '../debug/types.js';
3
+ import type { HttpContext } from '@adonisjs/core/http';
4
+ import type { NextFn } from '@adonisjs/core/types/http';
5
5
  /**
6
6
  * Returns true if the current async context is inside an excluded request
7
7
  * (e.g. a debug panel polling request). Used by collectors to skip
@@ -1 +1 @@
1
- {"version":3,"file":"request_tracking_middleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/request_tracking_middleware.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AASrD;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAOD,wBAAgB,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,IAAI,QAE/D;AAOD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,QAEjE;AAQD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,QAEnD;AASD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAErD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAQD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,IAAI,QAGjD;AAED,MAAM,CAAC,OAAO,OAAO,yBAAyB;IACtC,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM;CAsE5C"}
1
+ {"version":3,"file":"request_tracking_middleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/request_tracking_middleware.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AASvD;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAOD,wBAAgB,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,IAAI,QAE/D;AAOD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,QAEjE;AAQD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,QAEnD;AASD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAErD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,WAAW,CAAA;CACpB;AAQD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,IAAI,QAEpF;AAED,MAAM,CAAC,OAAO,OAAO,yBAAyB;IACtC,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM;CAuE5C"}
@@ -1,6 +1,6 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
- import { performance } from "node:perf_hooks";
3
- import { getRequestMetrics } from "../collectors/http_collector.js";
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { getRequestMetrics } from '../collectors/http_collector.js';
4
4
  /**
5
5
  * AsyncLocalStorage that marks the current request as "excluded" from
6
6
  * debug collection. Checked by QueryCollector and EventCollector to
@@ -70,7 +70,8 @@ export default class RequestTrackingMiddleware {
70
70
  // runs BEFORE router middleware like initialize_auth_middleware and
71
71
  // silentAuth — so ctx.auth isn't populated yet. The function is called
72
72
  // at Edge render time (inside the controller), when auth is available.
73
- if (shouldShowFn && typeof ctx.view?.share === "function") {
73
+ if (shouldShowFn && typeof ctx.view?.share === 'function') {
74
+ ;
74
75
  ctx.view.share({
75
76
  __ssShowFn: () => {
76
77
  try {
@@ -85,8 +86,8 @@ export default class RequestTrackingMiddleware {
85
86
  // Skip tracing and dashboard persistence for the debug panel's own requests
86
87
  // (e.g. /admin/api/debug/*, /admin/api/server-stats) so they don't flood
87
88
  // the timeline. HTTP metrics (req/s, avg latency) are still recorded.
88
- const skipTracing = excludedPrefixes.length > 0
89
- && excludedPrefixes.some((prefix) => requestUrl.startsWith(prefix));
89
+ const skipTracing = excludedPrefixes.length > 0 &&
90
+ excludedPrefixes.some((prefix) => requestUrl.startsWith(prefix));
90
91
  const runRequest = async () => {
91
92
  try {
92
93
  await next();
@@ -1,5 +1,5 @@
1
- import type { ConfigProvider } from '@adonisjs/core/types';
2
1
  import type { ServerStats } from '../types.js';
2
+ import type { ConfigProvider } from '@adonisjs/core/types';
3
3
  export declare function serverStatsCollector(): ConfigProvider<any>;
4
4
  export declare const ServerStatsCollector: {
5
5
  instance: {
@@ -1 +1 @@
1
- {"version":3,"file":"prometheus_collector.d.ts","sourceRoot":"","sources":["../../../src/prometheus/prometheus_collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,wBAAgB,oBAAoB,IAAI,cAAc,CAAC,GAAG,CAAC,CA4M1D;AAED,eAAO,MAAM,oBAAoB,EAAE;IAAE,QAAQ,EAAE;QAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAElG,CAAA"}
1
+ {"version":3,"file":"prometheus_collector.d.ts","sourceRoot":"","sources":["../../../src/prometheus/prometheus_collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,wBAAgB,oBAAoB,IAAI,cAAc,CAAC,GAAG,CAAC,CA6M1D;AAED,eAAO,MAAM,oBAAoB,EAAE;IACjC,QAAQ,EAAE;QAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAG/D,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { ApplicationService } from "@adonisjs/core/types";
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
2
  export default class ServerStatsProvider {
3
3
  protected app: ApplicationService;
4
4
  private intervalId;
@@ -1 +1 @@
1
- {"version":3,"file":"server_stats_provider.d.ts","sourceRoot":"","sources":["../../../src/provider/server_stats_provider.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK/D,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAY1B,SAAS,CAAC,GAAG,EAAE,kBAAkB;IAX7C,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,kBAAkB,CAAiC;IAC3D,OAAO,CAAC,uBAAuB,CAA+C;IAC9E,OAAO,CAAC,mBAAmB,CAA8C;IACzE,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,UAAU,CAA+C;gBAE3C,GAAG,EAAE,kBAAkB;IAEvC,IAAI;IAuCJ,KAAK;YAoFG,eAAe;IAqF7B;;;;;;OAMG;YACW,cAAc;IA4GtB,QAAQ;CAwCf"}
1
+ {"version":3,"file":"server_stats_provider.d.ts","sourceRoot":"","sources":["../../../src/provider/server_stats_provider.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAE9D,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAY1B,SAAS,CAAC,GAAG,EAAE,kBAAkB;IAX7C,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,uBAAuB,CAA8C;IAC7E,OAAO,CAAC,mBAAmB,CAA6C;IACxE,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,UAAU,CAA8C;gBAE1C,GAAG,EAAE,kBAAkB;IAEvC,IAAI;IAkCJ,KAAK;YA+EG,eAAe;IAmF7B;;;;;;OAMG;YACW,cAAc;IAoGtB,QAAQ;CAwCf"}
@@ -1,9 +1,9 @@
1
- import { StatsEngine } from "../engine/stats_engine.js";
2
- import { DebugStore } from "../debug/debug_store.js";
3
- import { DashboardStore } from "../dashboard/dashboard_store.js";
4
- import { LogStreamService } from "../log_stream/log_stream_service.js";
5
- import { setShouldShow, setTraceCollector, setDashboardPath, setExcludedPrefixes, setOnRequestComplete, } from "../middleware/request_tracking_middleware.js";
6
- import { registerDashboardRoutes } from "../dashboard/dashboard_routes.js";
1
+ import { registerDashboardRoutes } from '../dashboard/dashboard_routes.js';
2
+ import { DashboardStore } from '../dashboard/dashboard_store.js';
3
+ import { DebugStore } from '../debug/debug_store.js';
4
+ import { StatsEngine } from '../engine/stats_engine.js';
5
+ import { LogStreamService } from '../log_stream/log_stream_service.js';
6
+ import { setShouldShow, setTraceCollector, setDashboardPath, setExcludedPrefixes, setOnRequestComplete, } from '../middleware/request_tracking_middleware.js';
7
7
  export default class ServerStatsProvider {
8
8
  app;
9
9
  intervalId = null;
@@ -20,7 +20,7 @@ export default class ServerStatsProvider {
20
20
  this.app = app;
21
21
  }
22
22
  async boot() {
23
- const config = this.app.config.get("server_stats");
23
+ const config = this.app.config.get('server_stats');
24
24
  if (!config)
25
25
  return;
26
26
  // Wire up the per-request shouldShow callback
@@ -32,7 +32,7 @@ export default class ServerStatsProvider {
32
32
  const toolbarConfig = config.devToolbar;
33
33
  if (toolbarConfig?.enabled && toolbarConfig.dashboard && !this.app.inProduction) {
34
34
  try {
35
- const router = await this.app.container.make("router");
35
+ const router = await this.app.container.make('router');
36
36
  const dashPath = toolbarConfig.dashboardPath ?? '/__stats';
37
37
  registerDashboardRoutes(router, dashPath, () => this.dashboardController, config.shouldShow);
38
38
  }
@@ -43,8 +43,8 @@ export default class ServerStatsProvider {
43
43
  if (!this.app.usingEdgeJS)
44
44
  return;
45
45
  try {
46
- const edge = await import("edge.js");
47
- const { edgePluginServerStats } = await import("../edge/plugin.js");
46
+ const edge = await import('edge.js');
47
+ const { edgePluginServerStats } = await import('../edge/plugin.js');
48
48
  edge.default.use(edgePluginServerStats(config));
49
49
  }
50
50
  catch {
@@ -52,14 +52,13 @@ export default class ServerStatsProvider {
52
52
  }
53
53
  }
54
54
  async ready() {
55
- const config = this.app.config.get("server_stats");
55
+ const config = this.app.config.get('server_stats');
56
56
  if (!config)
57
57
  return;
58
58
  if (this.app.inTest && config.skipInTest !== false)
59
59
  return;
60
60
  this.engine = new StatsEngine(config.collectors);
61
- // Bind engine to container so the controller can access it
62
- this.app.container.singleton("server_stats.engine", () => this.engine);
61
+ this.app.container.singleton('server_stats.engine', () => this.engine);
63
62
  await this.engine.start();
64
63
  // Dev toolbar setup
65
64
  const toolbarConfig = config.devToolbar;
@@ -80,7 +79,8 @@ export default class ServerStatsProvider {
80
79
  });
81
80
  // Exclude the stats endpoint and user-specified prefixes from tracing
82
81
  // so the debug panel's own polling doesn't flood the timeline
83
- const prefixes = [...(toolbarConfig.excludeFromTracing ?? [])];
82
+ const defaultExcludes = ['/admin/api/debug', '/admin/api/server-stats'];
83
+ const prefixes = [...(toolbarConfig.excludeFromTracing ?? defaultExcludes)];
84
84
  if (typeof config.endpoint === 'string') {
85
85
  prefixes.push(config.endpoint);
86
86
  }
@@ -89,9 +89,9 @@ export default class ServerStatsProvider {
89
89
  }
90
90
  }
91
91
  let transmit = null;
92
- if (config.transport === "transmit") {
92
+ if (config.transport === 'transmit') {
93
93
  try {
94
- transmit = await this.app.container.make("transmit");
94
+ transmit = await this.app.container.make('transmit');
95
95
  }
96
96
  catch {
97
97
  // Transmit not installed — skip broadcasting
@@ -99,7 +99,7 @@ export default class ServerStatsProvider {
99
99
  }
100
100
  let prometheusCollector = null;
101
101
  try {
102
- const mod = await import("../prometheus/prometheus_collector.js");
102
+ const mod = await import('../prometheus/prometheus_collector.js');
103
103
  prometheusCollector = mod.ServerStatsCollector.instance;
104
104
  }
105
105
  catch {
@@ -123,19 +123,19 @@ export default class ServerStatsProvider {
123
123
  }
124
124
  async setupDevToolbar(toolbarConfig) {
125
125
  this.debugStore = new DebugStore(toolbarConfig);
126
- // Bind debug store to container
127
- this.app.container.singleton("debug.store", () => this.debugStore);
126
+ this.app.container.singleton('debug.store', () => this.debugStore);
128
127
  // Load persisted data before starting collectors
129
128
  if (toolbarConfig.persistDebugData) {
130
- this.persistPath = typeof toolbarConfig.persistDebugData === 'string'
131
- ? this.app.makePath(toolbarConfig.persistDebugData)
132
- : this.app.makePath('.adonisjs', 'server-stats', 'debug-data.json');
129
+ this.persistPath =
130
+ typeof toolbarConfig.persistDebugData === 'string'
131
+ ? this.app.makePath(toolbarConfig.persistDebugData)
132
+ : this.app.makePath('.adonisjs', 'server-stats', 'debug-data.json');
133
133
  await this.debugStore.loadFromDisk(this.persistPath);
134
134
  }
135
135
  // Get the emitter
136
136
  let emitter = null;
137
137
  try {
138
- emitter = await this.app.container.make("emitter");
138
+ emitter = await this.app.container.make('emitter');
139
139
  }
140
140
  catch {
141
141
  // Emitter not available
@@ -143,7 +143,7 @@ export default class ServerStatsProvider {
143
143
  // Get the router
144
144
  let router = null;
145
145
  try {
146
- router = await this.app.container.make("router");
146
+ router = await this.app.container.make('router');
147
147
  }
148
148
  catch {
149
149
  // Router not available
@@ -167,13 +167,13 @@ export default class ServerStatsProvider {
167
167
  // ── Transmit broadcasting for debug panel live updates ────────
168
168
  let debugTransmit = null;
169
169
  try {
170
- debugTransmit = await this.app.container.make("transmit");
170
+ debugTransmit = await this.app.container.make('transmit');
171
171
  }
172
172
  catch {
173
173
  // Transmit not installed — debug panel will use polling
174
174
  }
175
175
  if (debugTransmit) {
176
- const debugChannel = "server-stats/debug";
176
+ const debugChannel = 'server-stats/debug';
177
177
  const pendingTypes = new Set();
178
178
  this.debugStore.onNewItem((type) => {
179
179
  // Debounce: coalesce rapid events into a single broadcast
@@ -224,14 +224,15 @@ export default class ServerStatsProvider {
224
224
  throw err;
225
225
  }
226
226
  // Bind to container
227
- this.app.container.singleton("dashboard.store", () => this.dashboardStore);
227
+ ;
228
+ this.app.container.singleton('dashboard.store', () => this.dashboardStore);
228
229
  // Set dashboard path in middleware for self-exclusion
229
230
  setDashboardPath(toolbarConfig.dashboardPath);
230
231
  // Create the controller — this makes the routes registered in boot() functional
231
- const DashboardControllerClass = (await import("../dashboard/dashboard_controller.js")).default;
232
+ const DashboardControllerClass = (await import('../dashboard/dashboard_controller.js')).default;
232
233
  this.dashboardController = new DashboardControllerClass(this.dashboardStore, this.debugStore, this.app);
233
234
  // ── Log piping ────────────────────────────────────────────────
234
- const logPath = this.app.makePath("logs", "adonisjs.log");
235
+ const logPath = this.app.makePath('logs', 'adonisjs.log');
235
236
  this.dashboardLogStream = new LogStreamService(logPath, (entry) => {
236
237
  this.dashboardStore?.recordLog(entry);
237
238
  });
@@ -271,18 +272,18 @@ export default class ServerStatsProvider {
271
272
  // ── Transmit streaming for real-time dashboard updates ────────
272
273
  let transmit = null;
273
274
  try {
274
- transmit = await this.app.container.make("transmit");
275
+ transmit = await this.app.container.make('transmit');
275
276
  }
276
277
  catch {
277
278
  // Transmit not installed — skip real-time updates
278
279
  }
279
280
  if (transmit) {
280
- const dashChannel = "server-stats/dashboard";
281
+ const dashChannel = 'server-stats/dashboard';
281
282
  this.dashboardBroadcastTimer = setInterval(async () => {
282
283
  try {
283
284
  if (!dashStore.isReady())
284
285
  return;
285
- const overview = await dashStore.getOverviewMetrics("1h");
286
+ const overview = await dashStore.getOverviewMetrics('1h');
286
287
  transmit.broadcast(dashChannel, overview);
287
288
  }
288
289
  catch {
@@ -281,10 +281,10 @@ export interface DevToolbarOptions {
281
281
  *
282
282
  * @example
283
283
  * ```ts
284
- * excludeFromTracing: ['/admin/api/debug']
284
+ * excludeFromTracing: ['/admin/api/debug', '/admin/api/server-stats']
285
285
  * ```
286
286
  *
287
- * @default []
287
+ * @default ['/admin/api/debug', '/admin/api/server-stats']
288
288
  */
289
289
  excludeFromTracing?: string[];
290
290
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared JSON parsing utilities with safe fallbacks.
3
+ */
4
+ /** Safely parse a JSON string, returning the original value on failure. */
5
+ export declare function safeParseJson(value: any): any;
6
+ /** Safely parse a JSON string expected to be an array, returning [] on failure. */
7
+ export declare function safeParseJsonArray(value: any): any[];
8
+ //# sourceMappingURL=json_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json_helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/json_helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAQ7C;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,EAAE,CAGpD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared JSON parsing utilities with safe fallbacks.
3
+ */
4
+ /** Safely parse a JSON string, returning the original value on failure. */
5
+ export function safeParseJson(value) {
6
+ if (value === null || value === undefined)
7
+ return null;
8
+ if (typeof value !== 'string')
9
+ return value;
10
+ try {
11
+ return JSON.parse(value);
12
+ }
13
+ catch {
14
+ return value;
15
+ }
16
+ }
17
+ /** Safely parse a JSON string expected to be an array, returning [] on failure. */
18
+ export function safeParseJsonArray(value) {
19
+ const parsed = safeParseJson(value);
20
+ return Array.isArray(parsed) ? parsed : [];
21
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Shared email address extraction utilities.
3
+ */
4
+ /**
5
+ * Normalize various AdonisJS mail address formats to a comma-separated string.
6
+ *
7
+ * Handles:
8
+ * - A string: `"user@example.com"`
9
+ * - An object: `{ address: "user@example.com", name: "User" }`
10
+ * - An array of strings or objects
11
+ */
12
+ export declare function extractAddresses(value: any): string;
13
+ //# sourceMappingURL=mail_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail_helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/mail_helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAWnD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared email address extraction utilities.
3
+ */
4
+ /**
5
+ * Normalize various AdonisJS mail address formats to a comma-separated string.
6
+ *
7
+ * Handles:
8
+ * - A string: `"user@example.com"`
9
+ * - An object: `{ address: "user@example.com", name: "User" }`
10
+ * - An array of strings or objects
11
+ */
12
+ export function extractAddresses(value) {
13
+ if (!value)
14
+ return '';
15
+ if (typeof value === 'string')
16
+ return value;
17
+ if (Array.isArray(value)) {
18
+ return value
19
+ .map((v) => (typeof v === 'string' ? v : v?.address || ''))
20
+ .filter(Boolean)
21
+ .join(', ');
22
+ }
23
+ if (typeof value === 'object' && value.address)
24
+ return value.address;
25
+ return '';
26
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared math utilities used across dashboard, collectors, and chart aggregator.
3
+ */
4
+ /** Round a number to 2 decimal places. */
5
+ export declare function round(n: number): number;
6
+ /** Clamp a value between min and max. */
7
+ export declare function clamp(value: number, min: number, max: number): number;
8
+ //# sourceMappingURL=math_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math_helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/math_helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,0CAA0C;AAC1C,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,yCAAyC;AACzC,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared math utilities used across dashboard, collectors, and chart aggregator.
3
+ */
4
+ /** Round a number to 2 decimal places. */
5
+ export function round(n) {
6
+ return Math.round(n * 100) / 100;
7
+ }
8
+ /** Clamp a value between min and max. */
9
+ export function clamp(value, min, max) {
10
+ return Math.max(min, Math.min(max, value));
11
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared time/range utilities for dashboard store, controller, and chart aggregator.
3
+ */
4
+ /** Convert a range string (e.g. '1h', '7d') to total minutes. */
5
+ export declare function rangeToMinutes(range: string): number;
6
+ /** Convert a range string to a SQLite-compatible datetime cutoff. */
7
+ export declare function rangeToCutoff(range: string): string;
8
+ /** Convert a Date to a SQLite-compatible datetime string (YYYY-MM-DD HH:MM:SS). */
9
+ export declare function toSqliteTimestamp(date: Date): string;
10
+ /** Round a bucket timestamp string down to the nearest N minutes. */
11
+ export declare function roundBucket(bucket: string, minutes: number): string;
12
+ //# sourceMappingURL=time_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time_helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/time_helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEpD;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE"}