adonisjs-server-stats 1.6.1 → 1.6.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 (53) hide show
  1. package/dist/src/collectors/app_collector.d.ts.map +1 -1
  2. package/dist/src/collectors/app_collector.js +2 -1
  3. package/dist/src/collectors/auto_detect.d.ts.map +1 -1
  4. package/dist/src/collectors/auto_detect.js +7 -3
  5. package/dist/src/collectors/db_pool_collector.d.ts.map +1 -1
  6. package/dist/src/collectors/db_pool_collector.js +2 -1
  7. package/dist/src/collectors/http_collector.d.ts +4 -3
  8. package/dist/src/collectors/http_collector.d.ts.map +1 -1
  9. package/dist/src/collectors/http_collector.js +3 -5
  10. package/dist/src/collectors/redis_collector.d.ts.map +1 -1
  11. package/dist/src/collectors/redis_collector.js +2 -1
  12. package/dist/src/controller/debug_controller.d.ts +5 -0
  13. package/dist/src/controller/debug_controller.d.ts.map +1 -1
  14. package/dist/src/controller/debug_controller.js +24 -1
  15. package/dist/src/dashboard/chart_aggregator.d.ts.map +1 -1
  16. package/dist/src/dashboard/chart_aggregator.js +3 -2
  17. package/dist/src/dashboard/dashboard_store.d.ts.map +1 -1
  18. package/dist/src/dashboard/dashboard_store.js +47 -11
  19. package/dist/src/dashboard/migrator.d.ts +5 -0
  20. package/dist/src/dashboard/migrator.d.ts.map +1 -1
  21. package/dist/src/dashboard/migrator.js +44 -9
  22. package/dist/src/data/data_access.d.ts +4 -2
  23. package/dist/src/data/data_access.d.ts.map +1 -1
  24. package/dist/src/data/data_access.js +8 -3
  25. package/dist/src/define_config.d.ts.map +1 -1
  26. package/dist/src/define_config.js +7 -6
  27. package/dist/src/edge/client-vue/dashboard.js +1 -1
  28. package/dist/src/edge/client-vue/debug-panel-deferred.js +1 -1
  29. package/dist/src/edge/client-vue/debug-panel.js +1 -1
  30. package/dist/src/middleware/request_tracking_middleware.d.ts.map +1 -1
  31. package/dist/src/middleware/request_tracking_middleware.js +7 -0
  32. package/dist/src/provider/server_stats_provider.d.ts +9 -0
  33. package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
  34. package/dist/src/provider/server_stats_provider.js +196 -59
  35. package/dist/src/utils/app_import.d.ts +23 -0
  36. package/dist/src/utils/app_import.d.ts.map +1 -0
  37. package/dist/src/utils/app_import.js +44 -0
  38. package/dist/vue/{CacheSection-CkrIB4-j.js → CacheSection-C788Yfai.js} +1 -1
  39. package/dist/vue/{ConfigSection-gulpOiq1.js → ConfigSection-CRzYxqW2.js} +1 -1
  40. package/dist/vue/{CustomPaneTab-J57ED_bh.js → CustomPaneTab-BJxT5Dp7.js} +33 -33
  41. package/dist/vue/{EmailsSection-BlKvQDx8.js → EmailsSection-C8JFMtW7.js} +1 -1
  42. package/dist/vue/{EventsSection-BdzQvIVJ.js → EventsSection-C4wXUgxG.js} +1 -1
  43. package/dist/vue/{JobsSection-DOzuMrG3.js → JobsSection-CsKWTjgN.js} +1 -1
  44. package/dist/vue/{LogsSection-CNN4y92u.js → LogsSection-BFVjSZ24.js} +12 -12
  45. package/dist/vue/{LogsTab-CJerb22r.js → LogsTab-DpEQ7euu.js} +17 -17
  46. package/dist/vue/{OverviewSection-SITNR_dA.js → OverviewSection-CbMdAido.js} +1 -1
  47. package/dist/vue/{QueriesSection-BAebAHkD.js → QueriesSection-BPiv7u3r.js} +1 -1
  48. package/dist/vue/{RequestsSection-CIR0IX39.js → RequestsSection-LtImH4rD.js} +1 -1
  49. package/dist/vue/{RoutesSection-j1U2oa0g.js → RoutesSection-CrxOxmzx.js} +1 -1
  50. package/dist/vue/{TimelineSection-Dw980UPg.js → TimelineSection-DLxMW2J_.js} +1 -1
  51. package/dist/vue/{index-COgsk_nv.js → index-qCQpBftQ.js} +2 -2
  52. package/dist/vue/index.js +1 -1
  53. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"app_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/app_collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAKrD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,IAAI,eAAe,CAgE9C"}
1
+ {"version":3,"file":"app_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/app_collector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAKrD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,IAAI,eAAe,CAgE9C"}
@@ -1,3 +1,4 @@
1
+ import { appImport } from '../utils/app_import.js';
1
2
  import { log, dim, bold } from '../utils/logger.js';
2
3
  let warnedLucidMissing = false;
3
4
  let warnedSessionsTable = false;
@@ -24,7 +25,7 @@ export function appCollector() {
24
25
  },
25
26
  async collect() {
26
27
  try {
27
- const { default: db } = await import('@adonisjs/lucid/services/db');
28
+ const { default: db } = await appImport('@adonisjs/lucid/services/db');
28
29
  const [sessions, webhooks, emails] = await Promise.all([
29
30
  db
30
31
  .from('sessions')
@@ -1 +1 @@
1
- {"version":3,"file":"auto_detect.d.ts","sourceRoot":"","sources":["../../../src/collectors/auto_detect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAkCrD,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAwGtE"}
1
+ {"version":3,"file":"auto_detect.d.ts","sourceRoot":"","sources":["../../../src/collectors/auto_detect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAqCrD,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAwGtE"}
@@ -1,13 +1,17 @@
1
+ import { appImport } from '../utils/app_import.js';
1
2
  import { log, dim, green, bold } from '../utils/logger.js';
2
3
  /**
3
4
  * Probe whether a package is importable at runtime.
4
5
  *
5
- * Uses dynamic `import()` wrapped in try/catch so a missing
6
- * optional dependency simply returns `false` instead of crashing.
6
+ * Uses {@link appImport} which resolves from `process.cwd()` first,
7
+ * handling the common case where adonisjs-server-stats is symlinked
8
+ * (e.g. `file:../../adonisjs-server-stats` in package.json). Without
9
+ * this, `import(pkg)` resolves from the symlink *target* directory,
10
+ * which may have devDependency stubs instead of the real packages.
7
11
  */
8
12
  async function isInstalled(pkg) {
9
13
  try {
10
- await import(pkg);
14
+ await appImport(pkg);
11
15
  return true;
12
16
  }
13
17
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"db_pool_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/db_pool_collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAUrD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,sBAAsB,GAAG,eAAe,CA8D9E"}
1
+ {"version":3,"file":"db_pool_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/db_pool_collector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAUrD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,sBAAsB,GAAG,eAAe,CA8D9E"}
@@ -1,3 +1,4 @@
1
+ import { appImport } from '../utils/app_import.js';
1
2
  import { log, dim, bold } from '../utils/logger.js';
2
3
  /**
3
4
  * Monitors the Knex connection pool for a Lucid database connection.
@@ -33,7 +34,7 @@ export function dbPoolCollector(opts) {
33
34
  },
34
35
  async collect() {
35
36
  try {
36
- const { default: db } = await import('@adonisjs/lucid/services/db');
37
+ const { default: db } = await appImport('@adonisjs/lucid/services/db');
37
38
  const connection = db.manager.get(connectionName);
38
39
  if (!connection) {
39
40
  if (!warnedConnectionNotFound) {
@@ -27,12 +27,13 @@ export interface HttpCollectorOptions {
27
27
  * Returns the shared {@link RequestMetrics} instance created by
28
28
  * `httpCollector()`.
29
29
  *
30
+ * Returns `null` if `httpCollector()` has not been called yet
31
+ * (e.g. during the startup window before collectors initialize).
32
+ *
30
33
  * Useful for accessing request metrics outside of the collector
31
34
  * (e.g. in custom middleware or controllers).
32
- *
33
- * @throws If `httpCollector()` has not been included in the config.
34
35
  */
35
- export declare function getRequestMetrics(): RequestMetrics;
36
+ export declare function getRequestMetrics(): RequestMetrics | null;
36
37
  /**
37
38
  * Tracks HTTP request throughput, response times, and error rates.
38
39
  *
@@ -1 +1 @@
1
- {"version":3,"file":"http_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/http_collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAG,eAAe,CAmC1E"}
1
+ {"version":3,"file":"http_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/http_collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAG,eAAe,CAmC1E"}
@@ -5,15 +5,13 @@ let sharedInstance = null;
5
5
  * Returns the shared {@link RequestMetrics} instance created by
6
6
  * `httpCollector()`.
7
7
  *
8
+ * Returns `null` if `httpCollector()` has not been called yet
9
+ * (e.g. during the startup window before collectors initialize).
10
+ *
8
11
  * Useful for accessing request metrics outside of the collector
9
12
  * (e.g. in custom middleware or controllers).
10
- *
11
- * @throws If `httpCollector()` has not been included in the config.
12
13
  */
13
14
  export function getRequestMetrics() {
14
- if (!sharedInstance) {
15
- throw new Error('RequestMetrics not initialized. Ensure httpCollector() is included in your collectors config.');
16
- }
17
15
  return sharedInstance;
18
16
  }
19
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"redis_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/redis_collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAMrD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,IAAI,eAAe,CAoGhD"}
1
+ {"version":3,"file":"redis_collector.d.ts","sourceRoot":"","sources":["../../../src/collectors/redis_collector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAMrD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,IAAI,eAAe,CAoGhD"}
@@ -1,3 +1,4 @@
1
+ import { appImport } from '../utils/app_import.js';
1
2
  import { log, dim, bold } from '../utils/logger.js';
2
3
  let warnedNotInstalled = false;
3
4
  let warnedPingFailed = false;
@@ -34,7 +35,7 @@ export function redisCollector() {
34
35
  };
35
36
  let redis;
36
37
  try {
37
- const mod = await import('@adonisjs/redis/services/main');
38
+ const mod = await appImport('@adonisjs/redis/services/main');
38
39
  redis = mod.default;
39
40
  }
40
41
  catch {
@@ -2,18 +2,23 @@ import type { DashboardStore } from '../dashboard/dashboard_store.js';
2
2
  import type { DebugStore } from '../debug/debug_store.js';
3
3
  import type { StatsEngine } from '../engine/stats_engine.js';
4
4
  import type { ResolvedServerStatsConfig } from '../types.js';
5
+ import type { ApplicationService } from '@adonisjs/core/types';
5
6
  import type { HttpContext } from '@adonisjs/core/http';
6
7
  interface DiagnosticsDeps {
7
8
  getEngine?: () => StatsEngine | null;
8
9
  getDashboardStore?: () => DashboardStore | null;
9
10
  getProviderDiagnostics?: () => Record<string, unknown>;
11
+ getApp?: () => ApplicationService;
10
12
  }
11
13
  export default class DebugController {
12
14
  private store;
13
15
  private serverConfig?;
14
16
  private diagnosticsDeps;
17
+ private configInspector;
15
18
  constructor(store: DebugStore, serverConfig?: ResolvedServerStatsConfig | undefined, diagnosticsDeps?: DiagnosticsDeps);
16
19
  config({ response }: HttpContext): Promise<void>;
20
+ /** Lazily create a ConfigInspector from the app reference. */
21
+ private getConfigInspector;
17
22
  diagnostics({ response }: HttpContext): Promise<void>;
18
23
  }
19
24
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"debug_controller.d.ts","sourceRoot":"","sources":["../../../src/controller/debug_controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAA;IACpC,iBAAiB,CAAC,EAAE,MAAM,cAAc,GAAG,IAAI,CAAA;IAC/C,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvD;AAED,MAAM,CAAC,OAAO,OAAO,eAAe;IAIhC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,YAAY,CAAC;IAJvB,OAAO,CAAC,eAAe,CAAiB;gBAG9B,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,yBAAyB,YAAA,EAChD,eAAe,CAAC,EAAE,eAAe;IAK7B,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW;IAkDhC,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW;CA+D5C"}
1
+ {"version":3,"file":"debug_controller.d.ts","sourceRoot":"","sources":["../../../src/controller/debug_controller.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAA;IACpC,iBAAiB,CAAC,EAAE,MAAM,cAAc,GAAG,IAAI,CAAA;IAC/C,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtD,MAAM,CAAC,EAAE,MAAM,kBAAkB,CAAA;CAClC;AAED,MAAM,CAAC,OAAO,OAAO,eAAe;IAKhC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,YAAY,CAAC;IALvB,OAAO,CAAC,eAAe,CAAiB;IACxC,OAAO,CAAC,eAAe,CAA+B;gBAG5C,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,yBAAyB,YAAA,EAChD,eAAe,CAAC,EAAE,eAAe;IAK7B,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW;IA8DtC,8DAA8D;IAC9D,OAAO,CAAC,kBAAkB;IAQpB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW;CA+D5C"}
@@ -1,9 +1,11 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { fileURLToPath } from 'node:url';
3
+ import { ConfigInspector } from '../dashboard/integrations/config_inspector.js';
3
4
  export default class DebugController {
4
5
  store;
5
6
  serverConfig;
6
7
  diagnosticsDeps;
8
+ configInspector = null;
7
9
  constructor(store, serverConfig, diagnosticsDeps) {
8
10
  this.store = store;
9
11
  this.serverConfig = serverConfig;
@@ -46,7 +48,28 @@ export default class DebugController {
46
48
  const transmit = {
47
49
  channelName: cfg?.channelName ?? 'admin/server-stats',
48
50
  };
49
- return response.json({ features, customPanes, endpoints, transmit });
51
+ // App config + env vars (for the Config tab's APP CONFIG / ENV view)
52
+ const inspector = this.getConfigInspector();
53
+ const appConfig = inspector ? inspector.getConfig().config : {};
54
+ const envVars = inspector ? inspector.getEnvVars().env : {};
55
+ return response.json({
56
+ features,
57
+ customPanes,
58
+ endpoints,
59
+ transmit,
60
+ app: appConfig,
61
+ env: envVars,
62
+ });
63
+ }
64
+ /** Lazily create a ConfigInspector from the app reference. */
65
+ getConfigInspector() {
66
+ if (this.configInspector)
67
+ return this.configInspector;
68
+ const app = this.diagnosticsDeps.getApp?.();
69
+ if (!app)
70
+ return null;
71
+ this.configInspector = new ConfigInspector(app);
72
+ return this.configInspector;
50
73
  }
51
74
  async diagnostics({ response }) {
52
75
  const engine = this.diagnosticsDeps.getEngine?.();
@@ -1 +1 @@
1
- {"version":3,"file":"chart_aggregator.d.ts","sourceRoot":"","sources":["../../../src/dashboard/chart_aggregator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,KAAK,CAA8C;gBAE/C,EAAE,EAAE,IAAI;IAIpB,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;YAOE,SAAS;CA6DxB"}
1
+ {"version":3,"file":"chart_aggregator.d.ts","sourceRoot":"","sources":["../../../src/dashboard/chart_aggregator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,KAAK,CAA8C;gBAE/C,EAAE,EAAE,IAAI;IAIpB,KAAK,IAAI,IAAI;IASb,IAAI,IAAI,IAAI;YAOE,SAAS;CA6DxB"}
@@ -18,8 +18,9 @@ export class ChartAggregator {
18
18
  this.db = db;
19
19
  }
20
20
  start() {
21
- // Run immediately on startup, then every 60s
22
- this.aggregate().catch(() => { });
21
+ // Defer the first aggregation so the event loop stays responsive
22
+ // during dashboard initialization. Then run every 60s.
23
+ setTimeout(() => this.aggregate().catch(() => { }), 2_000);
23
24
  this.timer = setInterval(() => {
24
25
  this.aggregate().catch(() => { });
25
26
  }, 60_000);
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard_store.d.ts","sourceRoot":"","sources":["../../../src/dashboard/dashboard_store.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAMhC,UAAU,YAAY;IACpB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAC9D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;CAChE;AAMD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAChG;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB;AAYD;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAA4D;IAC5E,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAsB;gBAE/B,MAAM,EAAE,gBAAgB;IASpC;;;OAGG;IACG,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C5F,kEAAkE;IAC5D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B3B,sEAAsE;IACtE,KAAK,IAAI,IAAI,GAAG,IAAI;IAIpB,kDAAkD;IAClD,OAAO,IAAI,OAAO;IAIlB,kEAAkE;IAC5D,eAAe,IAAI,OAAO,CAAC;QAC/B,KAAK,EAAE,OAAO,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QACjD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B,CAAC;IAgEF;;;OAGG;IACG,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwBhE,uFAAuF;IACjF,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC7E,yCAAyC;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB3E,6BAA6B;IACvB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BrD,yDAAyD;IACnD,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB9D,oCAAoC;IAC9B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBvE;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwBxE,uDAAuD;IACjD,WAAW,CACf,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAkBpD,qDAAqD;IAC/C,UAAU,CACd,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAmBpD;;;OAGG;IACG,iBAAiB,CACrB,KAAK,GAAE,MAAY,EACnB,IAAI,GAAE,MAAyB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IA8BrC,qDAAqD;IAC/C,SAAS,CACb,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IASpD,qDAAqD;IAC/C,SAAS,CACb,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,YAAY,EACtB,WAAW,GAAE,OAAe,GAC3B,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAkCpD,iEAAiE;IAC3D,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUtD;;;;;OAKG;IACG,OAAO,CACX,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IA0BpD,qDAAqD;IAC/C,SAAS,CACb,IAAI,GAAE,MAAU,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAepD,wCAAwC;IAClC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAazE,iEAAiE;IAC3D,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IA8B3E;;;;OAIG;IACG,kBAAkB,CAAC,KAAK,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAoFvF;;;;OAIG;IACG,YAAY,CAAC,KAAK,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAgE5E;;;;OAIG;IACG,kBAAkB,CAAC,KAAK,GAAE,MAAa,GAAG,OAAO,CAAC;QACtD,SAAS,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QACjD,aAAa,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;QAC/D,iBAAiB,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;QAC/E,kBAAkB,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;QAClF,cAAc,EAAE;YAAE,aAAa,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAChF,CAAC;IAsHF,6DAA6D;IACvD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAenE,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAQrE,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAYpC,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrD;;;;;;OAMG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAyB1F,oDAAoD;YACtC,QAAQ;IA+BtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAuC3B"}
1
+ {"version":3,"file":"dashboard_store.d.ts","sourceRoot":"","sources":["../../../src/dashboard/dashboard_store.ts"],"names":[],"mappings":"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"}
@@ -50,35 +50,71 @@ export class DashboardStore {
50
50
  await mkdir(dirname(dbFilePath), { recursive: true });
51
51
  // Create a standalone Knex connection to SQLite — bypasses Lucid's
52
52
  // connection manager entirely so we never pollute the app's pool.
53
- const knexModule = await import('knex');
53
+ //
54
+ // Must use appImport — bare import('knex') resolves to this package's
55
+ // devDep copy when symlinked (file: dependency), which may have
56
+ // different native bindings or conflict with the app's copies.
57
+ log.info('dashboard: loading knex...');
58
+ const { appImportWithPath } = await import('../utils/app_import.js');
59
+ let knexModule;
60
+ let knexPath;
61
+ try {
62
+ const result = await appImportWithPath('knex');
63
+ knexModule = result.module;
64
+ knexPath = result.resolvedPath;
65
+ }
66
+ catch (err) {
67
+ throw new Error(`Could not load knex: ${err?.message}. ` +
68
+ 'Install it with: npm install knex better-sqlite3');
69
+ }
70
+ let sqlite3Path;
71
+ try {
72
+ const result = await appImportWithPath('better-sqlite3');
73
+ sqlite3Path = result.resolvedPath;
74
+ }
75
+ catch (err) {
76
+ throw new Error(`Could not load better-sqlite3: ${err?.message}. ` +
77
+ 'Install it with: npm install better-sqlite3');
78
+ }
79
+ log.info(`dashboard: knex resolved from ${knexPath}`);
80
+ log.info(`dashboard: better-sqlite3 resolved from ${sqlite3Path}`);
54
81
  const knexFactory = knexModule.default ?? knexModule;
55
- this.db = knexFactory({
82
+ log.info(`dashboard: opening SQLite database at ${dbFilePath}`);
83
+ const db = knexFactory({
56
84
  client: 'better-sqlite3',
57
85
  connection: { filename: dbFilePath },
58
86
  useNullAsDefault: true,
59
87
  });
60
- await this.db.raw('PRAGMA journal_mode=WAL');
61
- await this.db.raw('PRAGMA foreign_keys=ON');
62
- await autoMigrate(this.db);
63
- await runRetentionCleanup(this.db, this.config.retentionDays);
64
- this.lastCleanupAt = Date.now();
65
- // Hourly retention cleanup
66
- this.retentionTimer = setInterval(async () => {
88
+ this.db = db;
89
+ log.info('dashboard: setting PRAGMA...');
90
+ await db.raw('PRAGMA journal_mode=WAL');
91
+ await db.raw('PRAGMA foreign_keys=ON');
92
+ log.info('dashboard: PRAGMA set');
93
+ log.info('dashboard: running migrations...');
94
+ await autoMigrate(db);
95
+ log.info('dashboard: migrations complete');
96
+ // Defer retention cleanup — not critical during startup.
97
+ // Run first cleanup after 30s, then hourly.
98
+ const runCleanup = async () => {
67
99
  try {
68
100
  if (this.db) {
69
101
  await runRetentionCleanup(this.db, this.config.retentionDays);
70
102
  this.lastCleanupAt = Date.now();
103
+ log.info('dashboard: retention cleanup complete');
71
104
  }
72
105
  }
73
106
  catch (err) {
74
107
  log.warn('dashboard: retention cleanup failed — ' + err?.message);
75
108
  }
76
- }, 60 * 60 * 1000);
109
+ };
110
+ setTimeout(() => runCleanup(), 30_000);
111
+ this.retentionTimer = setInterval(() => runCleanup(), 60 * 60 * 1000);
77
112
  // Start chart aggregation (every 60s)
78
- this.chartAggregator = new ChartAggregator(this.db);
113
+ this.chartAggregator = new ChartAggregator(db);
79
114
  this.chartAggregator.start();
80
115
  // Wire email event listeners
81
116
  this.wireEventListeners();
117
+ log.info('dashboard: store initialized');
82
118
  }
83
119
  /** Shut down timers, event listeners, and database connection. */
84
120
  async stop() {
@@ -5,6 +5,9 @@ import type { Knex } from 'knex';
5
5
  * Uses raw SQL (not Lucid migrations) so we never pollute the host
6
6
  * application's migration history. Each `CREATE TABLE` / `CREATE INDEX`
7
7
  * uses `IF NOT EXISTS` so the function is idempotent.
8
+ *
9
+ * Yields to the event loop between each table so the server can
10
+ * continue processing HTTP requests during migration.
8
11
  */
9
12
  export declare function autoMigrate(db: Knex): Promise<void>;
10
13
  /**
@@ -13,6 +16,8 @@ export declare function autoMigrate(db: Knex): Promise<void>;
13
16
  * Foreign-key cascades on `server_stats_requests` handle the child
14
17
  * tables (queries, events, traces). Standalone tables (logs, emails,
15
18
  * metrics, saved_filters) are pruned individually.
19
+ *
20
+ * Yields between each DELETE so the event loop stays responsive.
16
21
  */
17
22
  export declare function runRetentionCleanup(db: Knex, retentionDays: number): Promise<void>;
18
23
  //# sourceMappingURL=migrator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../../src/dashboard/migrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA6IzD;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYxF"}
1
+ {"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../../src/dashboard/migrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAahC;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAoJzD;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BxF"}
@@ -1,9 +1,22 @@
1
+ /**
2
+ * Yield control back to the event loop so Node.js can process pending
3
+ * I/O (incoming HTTP requests, timers, etc.).
4
+ *
5
+ * `better-sqlite3` is fully synchronous — when Knex wraps it, each
6
+ * `await db.raw(...)` resolves via the microtask queue, never actually
7
+ * yielding to the I/O phase. Without explicit yields, 25+ sequential
8
+ * migration statements block the event loop for their entire duration.
9
+ */
10
+ const yieldToEventLoop = () => new Promise((resolve) => setImmediate(resolve));
1
11
  /**
2
12
  * Auto-migrate all dashboard SQLite tables.
3
13
  *
4
14
  * Uses raw SQL (not Lucid migrations) so we never pollute the host
5
15
  * application's migration history. Each `CREATE TABLE` / `CREATE INDEX`
6
16
  * uses `IF NOT EXISTS` so the function is idempotent.
17
+ *
18
+ * Yields to the event loop between each table so the server can
19
+ * continue processing HTTP requests during migration.
7
20
  */
8
21
  export async function autoMigrate(db) {
9
22
  // -- server_stats_requests --------------------------------------------------
@@ -21,6 +34,7 @@ export async function autoMigrate(db) {
21
34
  `);
22
35
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_requests_created ON server_stats_requests(created_at)`);
23
36
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_requests_url ON server_stats_requests(url)`);
37
+ await yieldToEventLoop();
24
38
  // -- server_stats_queries ---------------------------------------------------
25
39
  await db.raw(`
26
40
  CREATE TABLE IF NOT EXISTS server_stats_queries (
@@ -40,6 +54,7 @@ export async function autoMigrate(db) {
40
54
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_queries_created ON server_stats_queries(created_at)`);
41
55
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_queries_normalized ON server_stats_queries(sql_normalized)`);
42
56
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_queries_request ON server_stats_queries(request_id)`);
57
+ await yieldToEventLoop();
43
58
  // -- server_stats_events ----------------------------------------------------
44
59
  await db.raw(`
45
60
  CREATE TABLE IF NOT EXISTS server_stats_events (
@@ -51,6 +66,7 @@ export async function autoMigrate(db) {
51
66
  )
52
67
  `);
53
68
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_events_created ON server_stats_events(created_at)`);
69
+ await yieldToEventLoop();
54
70
  // -- server_stats_emails ----------------------------------------------------
55
71
  await db.raw(`
56
72
  CREATE TABLE IF NOT EXISTS server_stats_emails (
@@ -70,6 +86,7 @@ export async function autoMigrate(db) {
70
86
  )
71
87
  `);
72
88
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_emails_created ON server_stats_emails(created_at)`);
89
+ await yieldToEventLoop();
73
90
  // -- server_stats_logs ------------------------------------------------------
74
91
  await db.raw(`
75
92
  CREATE TABLE IF NOT EXISTS server_stats_logs (
@@ -84,6 +101,7 @@ export async function autoMigrate(db) {
84
101
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_logs_created ON server_stats_logs(created_at)`);
85
102
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_logs_level ON server_stats_logs(level)`);
86
103
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_logs_request ON server_stats_logs(request_id)`);
104
+ await yieldToEventLoop();
87
105
  // -- server_stats_traces ----------------------------------------------------
88
106
  await db.raw(`
89
107
  CREATE TABLE IF NOT EXISTS server_stats_traces (
@@ -100,6 +118,7 @@ export async function autoMigrate(db) {
100
118
  )
101
119
  `);
102
120
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_traces_created ON server_stats_traces(created_at)`);
121
+ await yieldToEventLoop();
103
122
  // -- server_stats_metrics ---------------------------------------------------
104
123
  await db.raw(`
105
124
  CREATE TABLE IF NOT EXISTS server_stats_metrics (
@@ -115,6 +134,7 @@ export async function autoMigrate(db) {
115
134
  )
116
135
  `);
117
136
  await db.raw(`CREATE INDEX IF NOT EXISTS idx_ss_metrics_bucket ON server_stats_metrics(bucket)`);
137
+ await yieldToEventLoop();
118
138
  // -- server_stats_saved_filters ---------------------------------------------
119
139
  await db.raw(`
120
140
  CREATE TABLE IF NOT EXISTS server_stats_saved_filters (
@@ -132,15 +152,30 @@ export async function autoMigrate(db) {
132
152
  * Foreign-key cascades on `server_stats_requests` handle the child
133
153
  * tables (queries, events, traces). Standalone tables (logs, emails,
134
154
  * metrics, saved_filters) are pruned individually.
155
+ *
156
+ * Yields between each DELETE so the event loop stays responsive.
135
157
  */
136
158
  export async function runRetentionCleanup(db, retentionDays) {
137
- const modifier = `-${retentionDays} days`;
138
- // Cascade deletes queries, events, traces via FK ON DELETE CASCADE
139
- await db.raw(`DELETE FROM server_stats_requests WHERE created_at < datetime('now', ?)`, [
140
- modifier,
141
- ]);
142
- // Standalone tables
143
- await db.raw(`DELETE FROM server_stats_logs WHERE created_at < datetime('now', ?)`, [modifier]);
144
- await db.raw(`DELETE FROM server_stats_emails WHERE created_at < datetime('now', ?)`, [modifier]);
145
- await db.raw(`DELETE FROM server_stats_metrics WHERE created_at < datetime('now', ?)`, [modifier]);
159
+ // Use string interpolation instead of parameterized bindings.
160
+ // Knex + better-sqlite3 can hang on parameterized db.raw() calls,
161
+ // while non-parameterized queries (used in migrations) work fine.
162
+ // Safe here — retentionDays is always a controlled integer.
163
+ const days = Math.max(1, Math.floor(retentionDays));
164
+ const cutoff = `datetime('now', '-${days} days')`;
165
+ try {
166
+ // Cascade deletes queries, events, traces via FK ON DELETE CASCADE
167
+ await db.raw(`DELETE FROM server_stats_requests WHERE created_at < ${cutoff}`);
168
+ await yieldToEventLoop();
169
+ // Standalone tables
170
+ await db.raw(`DELETE FROM server_stats_logs WHERE created_at < ${cutoff}`);
171
+ await yieldToEventLoop();
172
+ await db.raw(`DELETE FROM server_stats_emails WHERE created_at < ${cutoff}`);
173
+ await yieldToEventLoop();
174
+ await db.raw(`DELETE FROM server_stats_metrics WHERE created_at < ${cutoff}`);
175
+ }
176
+ catch (err) {
177
+ // Log but don't throw — retention cleanup failure shouldn't block init
178
+ const { log } = await import('../utils/logger.js');
179
+ log.warn(`dashboard: retention cleanup error — ${err?.message}`);
180
+ }
146
181
  }
@@ -37,11 +37,13 @@ export interface PaginatedResult<T = Record<string, unknown>> {
37
37
  */
38
38
  export declare class DataAccess {
39
39
  private debugStore;
40
- private dashboardStore;
40
+ private getDashboardStore;
41
41
  private logPath?;
42
- constructor(debugStore: DebugStore, dashboardStore: DashboardStore | null, logPath?: string | undefined);
42
+ constructor(debugStore: DebugStore, dashboardStore: DashboardStore | null | (() => DashboardStore | null), logPath?: string);
43
43
  /** Whether SQLite persistence is available and initialised. */
44
44
  get hasPersistence(): boolean;
45
+ /** Resolve the dashboard store (may be null if not yet initialized). */
46
+ private get dashboardStore();
45
47
  getQueries(opts?: ListOptions): Promise<PaginatedResult<QueryRecord>>;
46
48
  getQuerySummary(): {
47
49
  total: number;
@@ -1 +1 @@
1
- {"version":3,"file":"data_access.d.ts","sourceRoot":"","sources":["../../../src/data/data_access.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAM1B,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEjC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAkED;;;;;;;GAOG;AACH,qBAAa,UAAU;IAEnB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,OAAO,CAAC;gBAFR,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,GAAG,IAAI,EACrC,OAAO,CAAC,EAAE,MAAM,YAAA;IAG1B,+DAA+D;IAC/D,IAAI,cAAc,IAAI,OAAO,CAE5B;IAMK,UAAU,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAsB/E,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAQrF,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAsB9E;;;;;OAKG;IACG,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAwBjE;;;;;OAKG;IACG,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYrF;;;;;OAKG;IACG,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IA4BjE;;;;OAIG;IACG,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAazF;;;;;OAKG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC;IA8BxD;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAyB/D;;;;;OAKG;YACW,WAAW;CAoC1B"}
1
+ {"version":3,"file":"data_access.d.ts","sourceRoot":"","sources":["../../../src/data/data_access.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAM1B,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEjC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAkED;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,OAAO,CAAC,CAAQ;gBAGtB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,EACrE,OAAO,CAAC,EAAE,MAAM;IAQlB,+DAA+D;IAC/D,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,wEAAwE;IACxE,OAAO,KAAK,cAAc,GAEzB;IAMK,UAAU,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAsB/E,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAQrF,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAsB9E;;;;;OAKG;IACG,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAwBjE;;;;;OAKG;IACG,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYrF;;;;;OAKG;IACG,SAAS,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IA4BjE;;;;OAIG;IACG,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAazF;;;;;OAKG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC;IA8BxD;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAyB/D;;;;;OAKG;YACW,WAAW;CAoC1B"}
@@ -56,16 +56,21 @@ function fromDashboardResult(result) {
56
56
  */
57
57
  export class DataAccess {
58
58
  debugStore;
59
- dashboardStore;
59
+ getDashboardStore;
60
60
  logPath;
61
61
  constructor(debugStore, dashboardStore, logPath) {
62
62
  this.debugStore = debugStore;
63
- this.dashboardStore = dashboardStore;
63
+ this.getDashboardStore =
64
+ typeof dashboardStore === 'function' ? dashboardStore : () => dashboardStore;
64
65
  this.logPath = logPath;
65
66
  }
66
67
  /** Whether SQLite persistence is available and initialised. */
67
68
  get hasPersistence() {
68
- return this.dashboardStore?.isReady() ?? false;
69
+ return this.getDashboardStore()?.isReady() ?? false;
70
+ }
71
+ /** Resolve the dashboard store (may be null if not yet initialized). */
72
+ get dashboardStore() {
73
+ return this.getDashboardStore();
69
74
  }
70
75
  // =========================================================================
71
76
  // Queries
@@ -1 +1 @@
1
- {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAqB,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA2RjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG,yBAAyB,CA0CjF"}
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAqB,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA4RjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG,yBAAyB,CA0CjF"}
@@ -1,4 +1,4 @@
1
- import { bold, dim, yellow } from './utils/logger.js';
1
+ import { bold, dim } from './utils/logger.js';
2
2
  /**
3
3
  * Resolve `toolbar`, `dashboard`, and `advanced` aliases into a
4
4
  * {@link DevToolbarOptions} object, merging with any existing
@@ -260,20 +260,21 @@ function logDeprecationWarnings(config) {
260
260
  const TAG = '\x1b[36m[ \x1b[1m\uD83D\uDD0D server-stats\x1b[0m\x1b[36m ]\x1b[0m';
261
261
  const lines = [];
262
262
  lines.push('');
263
- lines.push(`${TAG} ${yellow('\u26A0 deprecated config options detected:')}`);
263
+ lines.push(`${TAG} Some config options have been renamed — here's how to update:`);
264
264
  lines.push('');
265
265
  for (const entry of entries) {
266
- lines.push(` ${bold(entry.old)} ${dim('\u2192')} ${bold(entry.new)}`);
266
+ lines.push(` ${dim(entry.old)} ${dim('\u2192')} ${bold(entry.new)}`);
267
+ lines.push('');
267
268
  for (const line of entry.before) {
268
269
  lines.push(` ${dim('before:')} ${dim(line)}`);
269
270
  }
270
271
  for (const line of entry.after) {
271
- lines.push(` ${yellow('after:')} ${line}`);
272
+ lines.push(` ${dim('after:')} ${line}`);
272
273
  }
273
274
  lines.push('');
274
275
  }
275
- lines.push(` ${dim('These old names still work but will be removed in the next major version.')}`);
276
- lines.push(` ${dim('Update your')} ${bold('config/server_stats.ts')} ${dim('to silence these warnings.')}`);
276
+ lines.push(` ${dim('No rush — the old names still work. They will be removed in the next major version.')}`);
277
+ lines.push(` ${dim('Update')} ${bold('config/server_stats.ts')} ${dim('when you get a chance.')}`);
277
278
  lines.push('');
278
279
  console.log(lines.join('\n'));
279
280
  }