adonisjs-server-stats 1.10.0 → 1.11.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 (248) hide show
  1. package/README.md +23 -14
  2. package/dist/core/config-utils.d.ts +8 -0
  3. package/dist/core/constants.d.ts +4 -0
  4. package/dist/core/dashboard-data-controller.d.ts +16 -0
  5. package/dist/core/dashboard-data-helpers.d.ts +12 -0
  6. package/dist/core/debug-data-controller.d.ts +4 -0
  7. package/dist/core/define-config-helpers.d.ts +25 -0
  8. package/dist/core/feature-detect-helpers.d.ts +36 -0
  9. package/dist/core/field-resolvers.d.ts +64 -0
  10. package/dist/core/formatters-helpers.d.ts +23 -0
  11. package/dist/core/formatters.d.ts +15 -0
  12. package/dist/core/index.d.ts +1 -1
  13. package/dist/core/index.js +599 -509
  14. package/dist/core/log-utils-helpers.d.ts +13 -0
  15. package/dist/core/metrics.d.ts +3 -28
  16. package/dist/core/pagination.d.ts +0 -9
  17. package/dist/core/server-stats-controller.d.ts +6 -0
  18. package/dist/core/transmit-helpers.d.ts +7 -0
  19. package/dist/core/types-dashboard.d.ts +178 -0
  20. package/dist/core/types-diagnostics.d.ts +85 -0
  21. package/dist/core/types.d.ts +10 -442
  22. package/dist/react/CacheSection-BYN53kYO.js +135 -0
  23. package/dist/react/CacheStatsBar-CRodCOeP.js +27 -0
  24. package/dist/react/CacheTab-DOhuK05d.js +106 -0
  25. package/dist/react/{ConfigSection-DfFd-WRq.js → ConfigSection-B9EHh4Rp.js} +1 -1
  26. package/dist/react/{ConfigTab-Bdg8YMer.js → ConfigTab-C8kriE2b.js} +1 -1
  27. package/dist/react/CustomPaneTab-CvzQS_Wh.js +99 -0
  28. package/dist/react/EmailPreviewOverlay-BmXOAvqG.js +58 -0
  29. package/dist/react/EmailsSection-BJyFJf7A.js +226 -0
  30. package/dist/react/EmailsTab-Ch8jp10B.js +110 -0
  31. package/dist/react/{EventsSection-ByQ-9blq.js → EventsSection-DJPwHeT8.js} +28 -27
  32. package/dist/react/EventsTab-B-FoehXC.js +58 -0
  33. package/dist/react/{FilterBar-DQRXpWrb.js → FilterBar-CQ7bD669.js} +15 -15
  34. package/dist/react/{InternalsContent-DBzsI0CG.js → InternalsContent-O8ino9oM.js} +133 -109
  35. package/dist/react/InternalsSection-B6VlVx5f.js +22 -0
  36. package/dist/react/InternalsTab-CkEKpRMU.js +17 -0
  37. package/dist/react/JobStatsBar-C7RslAFE.js +30 -0
  38. package/dist/react/JobsSection-DWF4i1t_.js +167 -0
  39. package/dist/react/JobsTab-DqnifQXV.js +129 -0
  40. package/dist/react/LogEntryRow-CMMkqA9M.js +43 -0
  41. package/dist/react/LogsSection-C1xC5aP4.js +198 -0
  42. package/dist/react/LogsTab-CS4sLfLw.js +79 -0
  43. package/dist/react/{OverviewSection-C4T1ur51.js → OverviewSection-CxvfOR0v.js} +70 -80
  44. package/dist/react/QueriesSection-CrMdU5Ax.js +458 -0
  45. package/dist/react/{QueriesTab-osLUWd4L.js → QueriesTab-x85PjkyS.js} +38 -40
  46. package/dist/react/RequestsSection-DETN9oZb.js +321 -0
  47. package/dist/react/{RoutesSection-BUSkM6PY.js → RoutesSection-CmorkJeC.js} +2 -2
  48. package/dist/react/RoutesTab-CbzBOzpc.js +68 -0
  49. package/dist/react/SplitPaneWrapper-BiIgT4ND.js +49 -0
  50. package/dist/react/TimeAgoCell-o3KigGfM.js +8 -0
  51. package/dist/react/{TimelineTab-Covg5weo.js → TimelineTab-Ue9tUD_n.js} +76 -102
  52. package/dist/react/index-DwDK-4oX.js +1121 -0
  53. package/dist/react/index.js +6 -6
  54. package/dist/react/react/components/shared/CacheStatsBar.d.ts +13 -0
  55. package/dist/react/react/components/shared/EmailPreviewOverlay.d.ts +29 -0
  56. package/dist/react/react/components/{Dashboard/shared → shared}/FilterBar.d.ts +4 -3
  57. package/dist/react/react/components/shared/JobStatsBar.d.ts +12 -0
  58. package/dist/react/react/components/shared/LogEntryRow.d.ts +9 -0
  59. package/dist/react/react/components/shared/RelatedLogs.d.ts +2 -2
  60. package/dist/react/react/components/shared/SplitPaneWrapper.d.ts +7 -0
  61. package/dist/react/react/components/shared/TimeAgoCell.d.ts +17 -0
  62. package/dist/react/react/hooks/useDashboardData.d.ts +4 -8
  63. package/dist/react/react/hooks/useDiagnosticsData.d.ts +14 -0
  64. package/dist/react/style.css +1 -1
  65. package/dist/src/collectors/app_collector.d.ts +0 -8
  66. package/dist/src/collectors/app_collector.js +45 -52
  67. package/dist/src/collectors/auto_detect.d.ts +0 -23
  68. package/dist/src/collectors/auto_detect.js +33 -55
  69. package/dist/src/collectors/db_pool_collector.d.ts +14 -16
  70. package/dist/src/collectors/db_pool_collector.js +72 -57
  71. package/dist/src/collectors/log_collector.d.ts +0 -47
  72. package/dist/src/collectors/log_collector.js +36 -65
  73. package/dist/src/collectors/queue_collector.d.ts +0 -20
  74. package/dist/src/collectors/queue_collector.js +60 -76
  75. package/dist/src/collectors/redis_collector.d.ts +10 -10
  76. package/dist/src/collectors/redis_collector.js +69 -66
  77. package/dist/src/config/deprecation_migration.d.ts +7 -0
  78. package/dist/src/config/deprecation_migration.js +201 -0
  79. package/dist/src/controller/debug_controller.d.ts +1 -1
  80. package/dist/src/controller/debug_controller.js +87 -81
  81. package/dist/src/dashboard/cache_handlers.d.ts +14 -0
  82. package/dist/src/dashboard/cache_handlers.js +52 -0
  83. package/dist/src/dashboard/chart_aggregator.d.ts +0 -7
  84. package/dist/src/dashboard/chart_aggregator.js +68 -50
  85. package/dist/src/dashboard/coalesce_cache.d.ts +25 -0
  86. package/dist/src/dashboard/coalesce_cache.js +47 -0
  87. package/dist/src/dashboard/dashboard_controller.d.ts +11 -37
  88. package/dist/src/dashboard/dashboard_controller.js +51 -544
  89. package/dist/src/dashboard/dashboard_page_assets.d.ts +17 -0
  90. package/dist/src/dashboard/dashboard_page_assets.js +51 -0
  91. package/dist/src/dashboard/dashboard_store.d.ts +19 -218
  92. package/dist/src/dashboard/dashboard_store.js +115 -1116
  93. package/dist/src/dashboard/dashboard_types.d.ts +83 -0
  94. package/dist/src/dashboard/dashboard_types.js +4 -0
  95. package/dist/src/dashboard/detail_queries.d.ts +19 -0
  96. package/dist/src/dashboard/detail_queries.js +98 -0
  97. package/dist/src/dashboard/email_event_builder.d.ts +8 -0
  98. package/dist/src/dashboard/email_event_builder.js +65 -0
  99. package/dist/src/dashboard/explain_query.d.ts +8 -0
  100. package/dist/src/dashboard/explain_query.js +22 -0
  101. package/dist/src/dashboard/filter_handlers.d.ts +23 -0
  102. package/dist/src/dashboard/filter_handlers.js +56 -0
  103. package/dist/src/dashboard/filtered_queries.d.ts +15 -0
  104. package/dist/src/dashboard/filtered_queries.js +155 -0
  105. package/dist/src/dashboard/flush_manager.d.ts +25 -0
  106. package/dist/src/dashboard/flush_manager.js +107 -0
  107. package/dist/src/dashboard/format_helpers.d.ts +126 -0
  108. package/dist/src/dashboard/format_helpers.js +140 -0
  109. package/dist/src/dashboard/inspector_manager.d.ts +36 -0
  110. package/dist/src/dashboard/inspector_manager.js +102 -0
  111. package/dist/src/dashboard/integrations/config_inspector.js +11 -13
  112. package/dist/src/dashboard/integrations/queue_inspector.d.ts +3 -3
  113. package/dist/src/dashboard/integrations/queue_inspector.js +13 -10
  114. package/dist/src/dashboard/jobs_handlers.d.ts +14 -0
  115. package/dist/src/dashboard/jobs_handlers.js +61 -0
  116. package/dist/src/dashboard/knex_factory.d.ts +18 -0
  117. package/dist/src/dashboard/knex_factory.js +91 -0
  118. package/dist/src/dashboard/migrator.js +30 -159
  119. package/dist/src/dashboard/migrator_tables.d.ts +19 -0
  120. package/dist/src/dashboard/migrator_tables.js +153 -0
  121. package/dist/src/dashboard/overview_queries.d.ts +66 -0
  122. package/dist/src/dashboard/overview_queries.js +155 -0
  123. package/dist/src/dashboard/overview_query_runners.d.ts +25 -0
  124. package/dist/src/dashboard/overview_query_runners.js +84 -0
  125. package/dist/src/dashboard/overview_store_queries.d.ts +40 -0
  126. package/dist/src/dashboard/overview_store_queries.js +69 -0
  127. package/dist/src/dashboard/paginate_helper.d.ts +12 -0
  128. package/dist/src/dashboard/paginate_helper.js +33 -0
  129. package/dist/src/dashboard/query_explain_handler.d.ts +10 -0
  130. package/dist/src/dashboard/query_explain_handler.js +80 -0
  131. package/dist/src/dashboard/read_queries.d.ts +32 -0
  132. package/dist/src/dashboard/read_queries.js +107 -0
  133. package/dist/src/dashboard/saved_filter_queries.d.ts +10 -0
  134. package/dist/src/dashboard/saved_filter_queries.js +24 -0
  135. package/dist/src/dashboard/storage_stats.d.ts +41 -0
  136. package/dist/src/dashboard/storage_stats.js +81 -0
  137. package/dist/src/dashboard/write_queue.d.ts +106 -0
  138. package/dist/src/dashboard/write_queue.js +225 -0
  139. package/dist/src/data/data_access.d.ts +2 -39
  140. package/dist/src/data/data_access.js +17 -193
  141. package/dist/src/data/data_access_helpers.d.ts +130 -0
  142. package/dist/src/data/data_access_helpers.js +212 -0
  143. package/dist/src/debug/debug_store.js +37 -32
  144. package/dist/src/debug/email_collector.d.ts +1 -10
  145. package/dist/src/debug/email_collector.js +78 -81
  146. package/dist/src/debug/event_collector.d.ts +0 -9
  147. package/dist/src/debug/event_collector.js +79 -62
  148. package/dist/src/debug/query_collector.js +23 -19
  149. package/dist/src/debug/route_inspector.d.ts +1 -5
  150. package/dist/src/debug/route_inspector.js +50 -51
  151. package/dist/src/debug/trace_collector.d.ts +9 -1
  152. package/dist/src/debug/trace_collector.js +21 -15
  153. package/dist/src/debug/types.d.ts +1 -1
  154. package/dist/src/define_config.d.ts +0 -65
  155. package/dist/src/define_config.js +93 -333
  156. package/dist/src/edge/client/dashboard.js +2 -2
  157. package/dist/src/edge/client/debug-panel-deferred.js +1 -1
  158. package/dist/src/edge/client/stats-bar.js +1 -1
  159. package/dist/src/edge/client-vue/dashboard.js +5 -5
  160. package/dist/src/edge/client-vue/debug-panel-deferred.js +4 -4
  161. package/dist/src/edge/client-vue/stats-bar.js +3 -3
  162. package/dist/src/edge/plugin.d.ts +0 -16
  163. package/dist/src/edge/plugin.js +57 -64
  164. package/dist/src/engine/request_metrics.d.ts +1 -0
  165. package/dist/src/engine/request_metrics.js +32 -42
  166. package/dist/src/middleware/request_tracking_middleware.d.ts +2 -8
  167. package/dist/src/middleware/request_tracking_middleware.js +65 -93
  168. package/dist/src/provider/auth_middleware_detector.d.ts +16 -0
  169. package/dist/src/provider/auth_middleware_detector.js +97 -0
  170. package/dist/src/provider/boot_helpers.d.ts +20 -0
  171. package/dist/src/provider/boot_helpers.js +91 -0
  172. package/dist/src/provider/boot_initializer.d.ts +28 -0
  173. package/dist/src/provider/boot_initializer.js +35 -0
  174. package/dist/src/provider/dashboard_init.d.ts +30 -0
  175. package/dist/src/provider/dashboard_init.js +138 -0
  176. package/dist/src/provider/dashboard_setup.d.ts +25 -0
  177. package/dist/src/provider/dashboard_setup.js +78 -0
  178. package/dist/src/provider/diagnostics.d.ts +134 -0
  179. package/dist/src/provider/diagnostics.js +127 -0
  180. package/dist/src/provider/email_bridge.d.ts +43 -0
  181. package/dist/src/provider/email_bridge.js +80 -0
  182. package/dist/src/provider/email_helpers.d.ts +13 -0
  183. package/dist/src/provider/email_helpers.js +68 -0
  184. package/dist/src/provider/pino_hook.d.ts +17 -0
  185. package/dist/src/provider/pino_hook.js +35 -0
  186. package/dist/src/provider/provider_helpers_extra.d.ts +47 -0
  187. package/dist/src/provider/provider_helpers_extra.js +177 -0
  188. package/dist/src/provider/server_stats_provider.d.ts +39 -85
  189. package/dist/src/provider/server_stats_provider.js +132 -951
  190. package/dist/src/provider/shutdown_helpers.d.ts +43 -0
  191. package/dist/src/provider/shutdown_helpers.js +70 -0
  192. package/dist/src/provider/toolbar_setup.d.ts +57 -0
  193. package/dist/src/provider/toolbar_setup.js +141 -0
  194. package/dist/src/routes/dashboard_routes.d.ts +14 -0
  195. package/dist/src/routes/dashboard_routes.js +197 -0
  196. package/dist/src/routes/debug_routes.d.ts +14 -0
  197. package/dist/src/routes/debug_routes.js +101 -0
  198. package/dist/src/routes/register_routes.d.ts +0 -78
  199. package/dist/src/routes/register_routes.js +22 -352
  200. package/dist/src/routes/stats_routes.d.ts +5 -0
  201. package/dist/src/routes/stats_routes.js +14 -0
  202. package/dist/src/styles/components.css +163 -0
  203. package/dist/src/styles/dashboard.css +13 -105
  204. package/dist/src/styles/debug-panel.css +2 -53
  205. package/dist/src/styles/utilities.css +3 -1
  206. package/dist/src/types.d.ts +305 -14
  207. package/dist/vue/{CacheSection-oFAJL3mo.js → CacheSection-DT2Mwf_s.js} +1 -1
  208. package/dist/vue/{ConfigSection-BhfJ4KqL.js → ConfigSection-BwKwS9lh.js} +1 -1
  209. package/dist/vue/CustomPaneTab-Hr1IBHfz.js +172 -0
  210. package/dist/vue/{EmailsSection-BcNyhyHs.js → EmailsSection-B65g0FVS.js} +1 -1
  211. package/dist/vue/{EventsSection-r60Q5Lmu.js → EventsSection-CxqtVF-o.js} +1 -1
  212. package/dist/vue/{JobsSection-BHL-hkQw.js → JobsSection-rMIyMb-g.js} +1 -1
  213. package/dist/vue/{LogsSection-DRMGzJmg.js → LogsSection-DmmZVJ7D.js} +9 -3
  214. package/dist/vue/{LogsTab-Bg3o0Mm6.js → LogsTab-47zEK7jL.js} +4 -1
  215. package/dist/vue/{OverviewSection-CXh6Ja1B.js → OverviewSection-BMabyqw-.js} +49 -50
  216. package/dist/vue/{QueriesSection-IodIsCJ-.js → QueriesSection-BfDFwGqH.js} +44 -45
  217. package/dist/vue/{QueriesTab-C8_7oprC.js → QueriesTab-DuTG7cpC.js} +30 -31
  218. package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-Py1iu9GU.js +77 -0
  219. package/dist/vue/{RequestsSection-BPuMdmMc.js → RequestsSection-CTu4jPZ_.js} +143 -147
  220. package/dist/vue/{RoutesSection-NKo3Rbq3.js → RoutesSection-zQZDedL7.js} +1 -1
  221. package/dist/vue/TimelineTab-DHfXsX7t.js +334 -0
  222. package/dist/vue/components/shared/RelatedLogs.vue.d.ts +1 -4
  223. package/dist/vue/composables/useDashboardData.d.ts +12 -23
  224. package/dist/vue/index-CM3yNVUR.js +1232 -0
  225. package/dist/vue/index.js +1 -1
  226. package/dist/vue/style.css +1 -1
  227. package/package.json +1 -1
  228. package/dist/react/CacheSection-UCMptWyn.js +0 -146
  229. package/dist/react/CacheTab-CA8LB1J5.js +0 -123
  230. package/dist/react/CustomPaneTab-Bxtv_8Rw.js +0 -104
  231. package/dist/react/EmailsSection-CM7stSyh.js +0 -262
  232. package/dist/react/EmailsTab-BDhEiomM.js +0 -153
  233. package/dist/react/EventsTab-CMfY98Rl.js +0 -63
  234. package/dist/react/InternalsSection-t7ihcWO-.js +0 -32
  235. package/dist/react/InternalsTab-Oij0A2fN.js +0 -30
  236. package/dist/react/JobsSection-DF3qEv9O.js +0 -187
  237. package/dist/react/JobsTab-BbrBWIOb.js +0 -141
  238. package/dist/react/LogsSection-DcFTZY7b.js +0 -227
  239. package/dist/react/LogsTab-CicucmVk.js +0 -103
  240. package/dist/react/QueriesSection-PswteoF9.js +0 -461
  241. package/dist/react/RelatedLogs-DFDOyUMr.js +0 -40
  242. package/dist/react/RequestsSection-Nag30rEA.js +0 -341
  243. package/dist/react/RoutesTab-DgVzd2PZ.js +0 -74
  244. package/dist/react/index-Cflz9Ebj.js +0 -1069
  245. package/dist/vue/CustomPaneTab-BJxT5Dp7.js +0 -172
  246. package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-CB2_TzYW.js +0 -84
  247. package/dist/vue/TimelineTab-zj5Z5OdT.js +0 -338
  248. package/dist/vue/index-Dtgysd26.js +0 -1229
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shutdown helper functions extracted from ServerStatsProvider.
3
+ */
4
+ /** Timer references that need to be cleared on shutdown. */
5
+ export interface TimerRefs {
6
+ intervalId: ReturnType<typeof setInterval> | null;
7
+ flushTimer: ReturnType<typeof setInterval> | null;
8
+ dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
9
+ debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
10
+ }
11
+ /**
12
+ * Clear all active timers and null out the references.
13
+ * Returns the (now-nulled) timer refs for convenience.
14
+ */
15
+ export declare function clearAllTimers(timers: TimerRefs): TimerRefs;
16
+ /** Minimal interface for debug store persistence. */
17
+ interface Persistable {
18
+ saveToDisk(path: string): Promise<void>;
19
+ }
20
+ /**
21
+ * Persist debug data to disk. Logs a warning on failure.
22
+ */
23
+ export declare function persistDebugData(store: Persistable | null, path: string | null): Promise<void>;
24
+ /**
25
+ * Unsubscribe from the Redis email bridge channel.
26
+ * Returns null so callers can clear their reference in one step.
27
+ */
28
+ export declare function unsubscribeEmailBridge(redis: unknown, channel: string): null;
29
+ /** Stoppable service interface. */
30
+ interface Stoppable {
31
+ stop(): void | Promise<void>;
32
+ }
33
+ /**
34
+ * Clean up log stream, dashboard, and middleware resources.
35
+ */
36
+ export declare function cleanupResources(deps: {
37
+ logStreamService: Stoppable | null;
38
+ dashboardLogStream: Stoppable | null;
39
+ dashboardStore: Stoppable | null;
40
+ debugStore: Stoppable | null;
41
+ engine: Stoppable | null;
42
+ }): Promise<void>;
43
+ export {};
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shutdown helper functions extracted from ServerStatsProvider.
3
+ */
4
+ import { setOnRequestComplete, setDashboardPath, setExcludedPrefixes, } from '../middleware/request_tracking_middleware.js';
5
+ import { log } from '../utils/logger.js';
6
+ /**
7
+ * Clear all active timers and null out the references.
8
+ * Returns the (now-nulled) timer refs for convenience.
9
+ */
10
+ export function clearAllTimers(timers) {
11
+ if (timers.intervalId) {
12
+ clearInterval(timers.intervalId);
13
+ timers.intervalId = null;
14
+ }
15
+ if (timers.flushTimer) {
16
+ clearInterval(timers.flushTimer);
17
+ timers.flushTimer = null;
18
+ }
19
+ if (timers.dashboardBroadcastTimer) {
20
+ clearInterval(timers.dashboardBroadcastTimer);
21
+ timers.dashboardBroadcastTimer = null;
22
+ }
23
+ if (timers.debugBroadcastTimer) {
24
+ clearTimeout(timers.debugBroadcastTimer);
25
+ timers.debugBroadcastTimer = null;
26
+ }
27
+ return timers;
28
+ }
29
+ /**
30
+ * Persist debug data to disk. Logs a warning on failure.
31
+ */
32
+ export async function persistDebugData(store, path) {
33
+ if (!path || !store)
34
+ return;
35
+ try {
36
+ await store.saveToDisk(path);
37
+ }
38
+ catch (err) {
39
+ log.warn('could not save debug data on shutdown — ' + err?.message);
40
+ }
41
+ }
42
+ /**
43
+ * Unsubscribe from the Redis email bridge channel.
44
+ * Returns null so callers can clear their reference in one step.
45
+ */
46
+ export function unsubscribeEmailBridge(redis, channel) {
47
+ if (!redis)
48
+ return null;
49
+ try {
50
+ ;
51
+ redis.unsubscribe(channel);
52
+ }
53
+ catch {
54
+ // Ignore cleanup errors
55
+ }
56
+ return null;
57
+ }
58
+ /**
59
+ * Clean up log stream, dashboard, and middleware resources.
60
+ */
61
+ export async function cleanupResources(deps) {
62
+ deps.logStreamService?.stop();
63
+ deps.dashboardLogStream?.stop();
64
+ setOnRequestComplete(null);
65
+ setDashboardPath(null);
66
+ setExcludedPrefixes([]);
67
+ await deps.dashboardStore?.stop();
68
+ deps.debugStore?.stop();
69
+ await deps.engine?.stop();
70
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Dev toolbar and dashboard setup helpers extracted from provider.
3
+ */
4
+ import type DebugController from '../controller/debug_controller.js';
5
+ import type DashboardController from '../dashboard/dashboard_controller.js';
6
+ import type { DashboardStore } from '../dashboard/dashboard_store.js';
7
+ import type { DebugStore } from '../debug/debug_store.js';
8
+ import type { DevToolbarConfig } from '../debug/types.js';
9
+ import type { StatsEngine } from '../engine/stats_engine.js';
10
+ import type { LogStreamService } from '../log_stream/log_stream_service.js';
11
+ import type { ResolvedServerStatsConfig } from '../types.js';
12
+ import type { ApplicationService } from '@adonisjs/core/types';
13
+ export { initDashboardStore } from './dashboard_init.js';
14
+ export interface ToolbarCoreResult {
15
+ debugStore: DebugStore;
16
+ debugController: DebugController;
17
+ persistPath: string | null;
18
+ flushTimer: ReturnType<typeof setInterval> | null;
19
+ debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
20
+ transmitAvailable: boolean;
21
+ transmitChannels: string[];
22
+ dashboardStore: DashboardStore | null;
23
+ dashboardController: DashboardController | null;
24
+ dashboardLogStream: LogStreamService | null;
25
+ dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
26
+ emailBridgeRedis: unknown;
27
+ emitter: unknown;
28
+ }
29
+ interface ToolbarCoreOptions {
30
+ tc: DevToolbarConfig;
31
+ config: ResolvedServerStatsConfig;
32
+ app: ApplicationService;
33
+ resolve: (binding: string) => Promise<unknown>;
34
+ getDiagnostics: () => unknown;
35
+ }
36
+ /** Core dev toolbar setup: debug store, controllers, broadcasting, dashboard. */
37
+ export declare function setupDevToolbarCore(opts: ToolbarCoreOptions): Promise<ToolbarCoreResult | null>;
38
+ export interface ProviderFields {
39
+ debugStore: DebugStore | null;
40
+ debugController: DebugController | null;
41
+ persistPath: string | null;
42
+ flushTimer: ReturnType<typeof setInterval> | null;
43
+ debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
44
+ transmitAvailable: boolean;
45
+ transmitChannels: string[];
46
+ dashboardStore: DashboardStore | null;
47
+ dashboardController: DashboardController | null;
48
+ dashboardLogStream: LogStreamService | null;
49
+ dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
50
+ emailBridgeRedis: unknown;
51
+ dashboardDepsAvailable: boolean;
52
+ engine: StatsEngine | null;
53
+ pinoHookActive: boolean;
54
+ app: ApplicationService;
55
+ }
56
+ /** Apply the toolbar core result back onto the provider instance. */
57
+ export declare function applyToolbarResult(result: ToolbarCoreResult, tc: DevToolbarConfig, provider: ProviderFields): void;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Dev toolbar and dashboard setup helpers extracted from provider.
3
+ */
4
+ import { setTraceCollector } from '../middleware/request_tracking_middleware.js';
5
+ import { log } from '../utils/logger.js';
6
+ import { initDashboardStore } from './dashboard_init.js';
7
+ import { setupFullEmailBridge } from './email_bridge.js';
8
+ export { initDashboardStore } from './dashboard_init.js';
9
+ /** Core dev toolbar setup: debug store, controllers, broadcasting, dashboard. */
10
+ export async function setupDevToolbarCore(opts) {
11
+ const { tc, config, app, resolve, getDiagnostics } = opts;
12
+ const { DebugStore: DS } = await import('../debug/debug_store.js');
13
+ const debugStore = new DS(tc);
14
+ const container = app.container;
15
+ container.singleton('debug.store', () => debugStore);
16
+ const persistPath = await loadPersistedData(tc, app, debugStore);
17
+ const em = await resolve('emitter');
18
+ if (!em)
19
+ log.warn('emitter not available — query/event collection disabled');
20
+ await debugStore.start(em, await resolve('router'));
21
+ const emailBridgeRedis = await setupBridgeInternal(em, debugStore);
22
+ const debugController = await createDebugController(debugStore, config, getDiagnostics, app);
23
+ if (debugStore.traces)
24
+ setTraceCollector(debugStore.traces);
25
+ const flushTimer = persistPath ? createFlushTimer(debugStore, persistPath) : null;
26
+ const broadcast = await setupDebugBroadcastInternal(debugStore, resolve);
27
+ return {
28
+ debugStore,
29
+ debugController,
30
+ persistPath,
31
+ flushTimer,
32
+ debugBroadcastTimer: broadcast.timer,
33
+ transmitAvailable: broadcast.transmitAvailable,
34
+ transmitChannels: broadcast.channels,
35
+ dashboardStore: null,
36
+ dashboardController: null,
37
+ dashboardLogStream: null,
38
+ dashboardBroadcastTimer: null,
39
+ emailBridgeRedis,
40
+ emitter: em,
41
+ };
42
+ }
43
+ async function loadPersistedData(tc, app, debugStore) {
44
+ if (!tc.persistDebugData)
45
+ return null;
46
+ const path = typeof tc.persistDebugData === 'string'
47
+ ? app.makePath(tc.persistDebugData)
48
+ : app.makePath('.adonisjs', 'server-stats', 'debug-data.json');
49
+ await debugStore.loadFromDisk(path);
50
+ return path;
51
+ }
52
+ async function createDebugController(debugStore, config, getDiagnostics, app) {
53
+ const DC = (await import('../controller/debug_controller.js')).default;
54
+ return new DC(debugStore, config, {
55
+ getEngine: () => null,
56
+ getDashboardStore: () => null,
57
+ getProviderDiagnostics: getDiagnostics,
58
+ getApp: () => app,
59
+ });
60
+ }
61
+ function createFlushTimer(debugStore, persistPath) {
62
+ return setInterval(async () => {
63
+ try {
64
+ await debugStore.saveToDisk(persistPath);
65
+ }
66
+ catch { }
67
+ }, 30_000);
68
+ }
69
+ async function setupBridgeInternal(emitter, debugStore) {
70
+ if (!emitter)
71
+ return null;
72
+ try {
73
+ const { appImport } = await import('../utils/app_import.js');
74
+ const mod = await appImport('@adonisjs/redis/services/main');
75
+ const redis = mod.default;
76
+ return await setupFullEmailBridge(emitter, redis, 'adonisjs-server-stats:emails', { debugEmails: debugStore.emails ?? null, dashboardStore: null });
77
+ }
78
+ catch {
79
+ return null;
80
+ }
81
+ }
82
+ async function setupDebugBroadcastInternal(debugStore, resolve) {
83
+ const t = await resolve('transmit');
84
+ if (!t)
85
+ return { timer: null, transmitAvailable: false, channels: [] };
86
+ const ch = 'server-stats/debug';
87
+ const pending = new Set();
88
+ let timer = null;
89
+ debugStore.onNewItem((type) => {
90
+ pending.add(type);
91
+ if (timer)
92
+ return;
93
+ timer = setTimeout(() => {
94
+ timer = null;
95
+ const ts = [...pending];
96
+ pending.clear();
97
+ try {
98
+ ;
99
+ t.broadcast(ch, { types: ts });
100
+ }
101
+ catch { }
102
+ }, 200);
103
+ });
104
+ return { timer: null, transmitAvailable: true, channels: [ch] };
105
+ }
106
+ /** Apply the toolbar core result back onto the provider instance. */
107
+ export function applyToolbarResult(result, tc, provider) {
108
+ provider.debugStore = result.debugStore;
109
+ provider.debugController = result.debugController;
110
+ provider.persistPath = result.persistPath;
111
+ provider.flushTimer = result.flushTimer;
112
+ provider.debugBroadcastTimer = result.debugBroadcastTimer;
113
+ if (result.transmitAvailable)
114
+ provider.transmitAvailable = true;
115
+ for (const ch of result.transmitChannels) {
116
+ if (!provider.transmitChannels.includes(ch))
117
+ provider.transmitChannels.push(ch);
118
+ }
119
+ provider.emailBridgeRedis = result.emailBridgeRedis;
120
+ if (!tc.dashboard || !provider.dashboardDepsAvailable)
121
+ return;
122
+ setImmediate(() => {
123
+ initDashboardStore({
124
+ tc,
125
+ emitter: result.emitter,
126
+ app: provider.app,
127
+ debugStore: result.debugStore,
128
+ engine: provider.engine,
129
+ pinoHookActive: provider.pinoHookActive,
130
+ transmitChannels: provider.transmitChannels,
131
+ onResult: (r) => {
132
+ provider.dashboardStore = r.dashboardStore;
133
+ provider.dashboardController = r.dashboardController;
134
+ provider.dashboardLogStream = r.dashboardLogStream;
135
+ provider.dashboardBroadcastTimer = r.dashboardBroadcastTimer;
136
+ },
137
+ }).catch((e) => {
138
+ log.warn(`dashboard setup failed: ${e?.message ?? e}`);
139
+ });
140
+ });
141
+ }
@@ -0,0 +1,14 @@
1
+ import type { ApiController } from '../controller/api_controller.js';
2
+ import type DashboardController from '../dashboard/dashboard_controller.js';
3
+ import type { AdonisRouter } from './router_types.js';
4
+ import type { HttpContext } from '@adonisjs/core/http';
5
+ interface DashboardRoutesOpts {
6
+ router: AdonisRouter;
7
+ dashboardPath: string;
8
+ getDashboardController: () => DashboardController | null;
9
+ getApiController: () => ApiController | null;
10
+ middleware: Array<(ctx: HttpContext, next: () => Promise<void>) => Promise<void>>;
11
+ }
12
+ /** Register dashboard routes. */
13
+ export declare function registerDashboardRoutes(opts: DashboardRoutesOpts): void;
14
+ export {};
@@ -0,0 +1,197 @@
1
+ function bindDash(getController, method) {
2
+ return async (ctx) => {
3
+ const controller = getController();
4
+ if (!controller)
5
+ return ctx.response.serviceUnavailable({ error: 'Dashboard is starting up, please retry' });
6
+ return controller[method].call(controller, ctx);
7
+ };
8
+ }
9
+ function bindApi(getApi, fn) {
10
+ return async (ctx) => {
11
+ const api = getApi();
12
+ if (!api)
13
+ return ctx.response.serviceUnavailable({ error: 'Dashboard is starting up, please retry' });
14
+ return fn(api, ctx);
15
+ };
16
+ }
17
+ function registerQueryRoutes(router, getApi) {
18
+ router
19
+ .get('/api/queries', bindApi(getApi, async (api, ctx) => {
20
+ const qs = ctx.request.qs();
21
+ return ctx.response.json(await api.getQueries({
22
+ page: Number(qs.page) || 1,
23
+ perPage: Number(qs.perPage) || 25,
24
+ search: qs.search || undefined,
25
+ filters: {
26
+ durationMin: qs.duration_min ? Number(qs.duration_min) : undefined,
27
+ model: qs.model || undefined,
28
+ method: qs.method || undefined,
29
+ connection: qs.connection || undefined,
30
+ },
31
+ }));
32
+ }))
33
+ .as('server-stats.queries');
34
+ }
35
+ function registerEventRoutes(router, getApi) {
36
+ router
37
+ .get('/api/events', bindApi(getApi, async (api, ctx) => {
38
+ const qs = ctx.request.qs();
39
+ return ctx.response.json(await api.getEvents({
40
+ page: Number(qs.page) || 1,
41
+ perPage: Number(qs.perPage) || 25,
42
+ search: qs.search || undefined,
43
+ filters: { eventName: qs.event_name || undefined },
44
+ }));
45
+ }))
46
+ .as('server-stats.events');
47
+ }
48
+ function registerRouteApiRoutes(router, getApi) {
49
+ router
50
+ .get('/api/routes', bindApi(getApi, (api, ctx) => ctx.response.json(api.getRoutes(ctx.request.qs().search || undefined))))
51
+ .as('server-stats.routes');
52
+ }
53
+ function registerLogRoutes(router, getApi) {
54
+ router
55
+ .get('/api/logs', bindApi(getApi, async (api, ctx) => {
56
+ const qs = ctx.request.qs();
57
+ return ctx.response.json(await api.getLogs({
58
+ page: Number(qs.page) || 1,
59
+ perPage: Number(qs.perPage) || 50,
60
+ search: qs.message || qs.search || undefined,
61
+ filters: {
62
+ level: qs.level || undefined,
63
+ requestId: qs.request_id || qs.requestId || undefined,
64
+ },
65
+ }));
66
+ }))
67
+ .as('server-stats.logs');
68
+ }
69
+ function registerEmailRoutes(router, getApi) {
70
+ router
71
+ .get('/api/emails', bindApi(getApi, async (api, ctx) => {
72
+ const qs = ctx.request.qs();
73
+ return ctx.response.json(await api.getEmails({
74
+ page: Number(qs.page) || 1,
75
+ perPage: Number(qs.perPage) || 25,
76
+ search: qs.search || undefined,
77
+ filters: {
78
+ from: qs.from || undefined,
79
+ to: qs.to || undefined,
80
+ subject: qs.subject || undefined,
81
+ status: qs.status || undefined,
82
+ mailer: qs.mailer || undefined,
83
+ },
84
+ }));
85
+ }))
86
+ .as('server-stats.emails');
87
+ router
88
+ .get('/api/emails/:id/preview', bindApi(getApi, async (api, ctx) => {
89
+ const html = await api.getEmailPreview(Number(ctx.params.id));
90
+ if (!html)
91
+ return ctx.response.notFound({ error: 'Email not found' });
92
+ return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
93
+ }))
94
+ .as('server-stats.emails.preview');
95
+ }
96
+ function registerTraceRoutes(router, getApi) {
97
+ router
98
+ .get('/api/traces', bindApi(getApi, async (api, ctx) => {
99
+ const qs = ctx.request.qs();
100
+ return ctx.response.json(await api.getTraces({
101
+ page: Number(qs.page) || 1,
102
+ perPage: Number(qs.perPage) || 25,
103
+ search: qs.search || undefined,
104
+ filters: {
105
+ method: qs.method ? qs.method.toUpperCase() : undefined,
106
+ url: qs.url || undefined,
107
+ statusMin: qs.status_min ? Number(qs.status_min) : undefined,
108
+ statusMax: qs.status_max ? Number(qs.status_max) : undefined,
109
+ },
110
+ }));
111
+ }))
112
+ .as('server-stats.traces');
113
+ router
114
+ .get('/api/traces/:id', bindApi(getApi, async (api, ctx) => {
115
+ const trace = await api.getTraceDetail(Number(ctx.params.id));
116
+ if (!trace)
117
+ return ctx.response.notFound({ error: 'Trace not found' });
118
+ return ctx.response.json(trace);
119
+ }))
120
+ .as('server-stats.traces.show');
121
+ }
122
+ function registerDashboardPageRoutes(router, getDashboardController) {
123
+ router.get('/', bindDash(getDashboardController, 'page')).as('server-stats.dashboard');
124
+ router
125
+ .get('/api/overview', bindDash(getDashboardController, 'overview'))
126
+ .as('server-stats.overview');
127
+ router
128
+ .get('/api/overview/chart', bindDash(getDashboardController, 'overviewChart'))
129
+ .as('server-stats.overview.chart');
130
+ router
131
+ .get('/api/requests', bindDash(getDashboardController, 'requests'))
132
+ .as('server-stats.requests');
133
+ router
134
+ .get('/api/requests/:id', bindDash(getDashboardController, 'requestDetail'))
135
+ .as('server-stats.requests.show');
136
+ }
137
+ function registerQueryDashboardRoutes(router, getDashboardController) {
138
+ router
139
+ .get('/api/queries/grouped', bindDash(getDashboardController, 'queriesGrouped'))
140
+ .as('server-stats.queries.grouped');
141
+ router
142
+ .get('/api/queries/:id/explain', bindDash(getDashboardController, 'queryExplain'))
143
+ .as('server-stats.queries.explain');
144
+ }
145
+ function registerCacheRoutes(router, getDashboardController) {
146
+ router.get('/api/cache', bindDash(getDashboardController, 'cacheStats')).as('server-stats.cache');
147
+ router
148
+ .get('/api/cache/:key', bindDash(getDashboardController, 'cacheKey'))
149
+ .as('server-stats.cache.show')
150
+ .where('key', /.*/);
151
+ router
152
+ .delete('/api/cache/:key', bindDash(getDashboardController, 'cacheKeyDelete'))
153
+ .as('server-stats.cache.delete')
154
+ .where('key', /.*/);
155
+ }
156
+ function registerJobRoutes(router, getDashboardController) {
157
+ router.get('/api/jobs', bindDash(getDashboardController, 'jobs')).as('server-stats.jobs');
158
+ router
159
+ .get('/api/jobs/:id', bindDash(getDashboardController, 'jobDetail'))
160
+ .as('server-stats.jobs.show');
161
+ router
162
+ .post('/api/jobs/:id/retry', bindDash(getDashboardController, 'jobRetry'))
163
+ .as('server-stats.jobs.retry');
164
+ }
165
+ function registerConfigAndFilterRoutes(router, getDashboardController) {
166
+ router.get('/api/config', bindDash(getDashboardController, 'config')).as('server-stats.config');
167
+ router
168
+ .get('/api/filters', bindDash(getDashboardController, 'savedFilters'))
169
+ .as('server-stats.filters');
170
+ router
171
+ .post('/api/filters', bindDash(getDashboardController, 'createSavedFilter'))
172
+ .as('server-stats.filters.create');
173
+ router
174
+ .delete('/api/filters/:id', bindDash(getDashboardController, 'deleteSavedFilter'))
175
+ .as('server-stats.filters.delete');
176
+ }
177
+ /** Register dashboard routes. */
178
+ export function registerDashboardRoutes(opts) {
179
+ const { router, dashboardPath, getDashboardController, getApiController, middleware } = opts;
180
+ const base = dashboardPath.replace(/\/+$/, '');
181
+ router
182
+ .group(() => {
183
+ registerDashboardPageRoutes(router, getDashboardController);
184
+ registerQueryRoutes(router, getApiController);
185
+ registerEventRoutes(router, getApiController);
186
+ registerRouteApiRoutes(router, getApiController);
187
+ registerLogRoutes(router, getApiController);
188
+ registerEmailRoutes(router, getApiController);
189
+ registerTraceRoutes(router, getApiController);
190
+ registerQueryDashboardRoutes(router, getDashboardController);
191
+ registerCacheRoutes(router, getDashboardController);
192
+ registerJobRoutes(router, getDashboardController);
193
+ registerConfigAndFilterRoutes(router, getDashboardController);
194
+ })
195
+ .prefix(base)
196
+ .use(middleware);
197
+ }
@@ -0,0 +1,14 @@
1
+ import type { ApiController } from '../controller/api_controller.js';
2
+ import type DebugController from '../controller/debug_controller.js';
3
+ import type { AdonisRouter } from './router_types.js';
4
+ import type { HttpContext } from '@adonisjs/core/http';
5
+ interface DebugRoutesOpts {
6
+ router: AdonisRouter;
7
+ debugEndpoint: string;
8
+ getDebugController: () => DebugController | null;
9
+ getApiController: () => ApiController | null;
10
+ middleware: Array<(ctx: HttpContext, next: () => Promise<void>) => Promise<void>>;
11
+ }
12
+ /** Register debug panel API routes. */
13
+ export declare function registerDebugRoutes(opts: DebugRoutesOpts): void;
14
+ export {};
@@ -0,0 +1,101 @@
1
+ function bindDebug(getController, method) {
2
+ return async (ctx) => {
3
+ const controller = getController();
4
+ if (!controller)
5
+ return ctx.response.serviceUnavailable({
6
+ error: 'Debug toolbar is starting up, please retry',
7
+ });
8
+ return controller[method].call(controller, ctx);
9
+ };
10
+ }
11
+ function bindApi(getApi, fn) {
12
+ return async (ctx) => {
13
+ const api = getApi();
14
+ if (!api)
15
+ return ctx.response.serviceUnavailable({
16
+ error: 'Debug toolbar is starting up, please retry',
17
+ });
18
+ return fn(api, ctx);
19
+ };
20
+ }
21
+ function registerDebugConfigRoutes(router, getDebugController) {
22
+ router.get('/config', bindDebug(getDebugController, 'config')).as('server-stats.debug.config');
23
+ router
24
+ .get('/diagnostics', bindDebug(getDebugController, 'diagnostics'))
25
+ .as('server-stats.debug.diagnostics');
26
+ }
27
+ function registerDebugQueryAndEventRoutes(router, getApiController) {
28
+ router
29
+ .get('/queries', bindApi(getApiController, async (api, ctx) => {
30
+ const queries = await api.getQueries({ source: 'memory' });
31
+ return ctx.response.json({ queries: queries.data, summary: api.getQuerySummary() });
32
+ }))
33
+ .as('server-stats.debug.queries');
34
+ router
35
+ .get('/events', bindApi(getApiController, async (api, ctx) => {
36
+ const result = await api.getEvents({ source: 'memory' });
37
+ return ctx.response.json({ events: result.data, total: result.meta.total });
38
+ }))
39
+ .as('server-stats.debug.events');
40
+ router
41
+ .get('/routes', bindApi(getApiController, (api, ctx) => {
42
+ const result = api.getRoutes();
43
+ return ctx.response.json({ routes: result.data, total: result.meta.total });
44
+ }))
45
+ .as('server-stats.debug.routes');
46
+ }
47
+ function registerDebugLogRoutes(router, getApiController) {
48
+ router
49
+ .get('/logs', bindApi(getApiController, async (api, ctx) => {
50
+ const result = await api.getLogs({ source: 'auto', perPage: 200 });
51
+ return ctx.response.json(result.data);
52
+ }))
53
+ .as('server-stats.debug.logs');
54
+ }
55
+ function registerDebugEmailRoutes(router, getApiController) {
56
+ router
57
+ .get('/emails', bindApi(getApiController, async (api, ctx) => {
58
+ const result = await api.getEmails({});
59
+ return ctx.response.json({ emails: result.data, total: result.meta.total });
60
+ }))
61
+ .as('server-stats.debug.emails');
62
+ router
63
+ .get('/emails/:id/preview', bindApi(getApiController, async (api, ctx) => {
64
+ const html = await api.getEmailPreview(Number(ctx.params.id));
65
+ if (!html)
66
+ return ctx.response.notFound({ error: 'Email not found' });
67
+ return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
68
+ }))
69
+ .as('server-stats.debug.emailPreview');
70
+ }
71
+ function registerDebugTraceRoutes(router, getApiController) {
72
+ router
73
+ .get('/traces', bindApi(getApiController, async (api, ctx) => {
74
+ const result = await api.getTraces({ source: 'memory' });
75
+ return ctx.response.json({ traces: result.data, total: result.meta.total });
76
+ }))
77
+ .as('server-stats.debug.traces');
78
+ router
79
+ .get('/traces/:id', bindApi(getApiController, async (api, ctx) => {
80
+ const trace = await api.getTraceDetail(Number(ctx.params.id), 'memory');
81
+ if (!trace)
82
+ return ctx.response.notFound({ error: 'Trace not found' });
83
+ return ctx.response.json(trace);
84
+ }))
85
+ .as('server-stats.debug.traceDetail');
86
+ }
87
+ /** Register debug panel API routes. */
88
+ export function registerDebugRoutes(opts) {
89
+ const { router, debugEndpoint, getDebugController, getApiController, middleware } = opts;
90
+ const base = debugEndpoint.replace(/\/+$/, '');
91
+ router
92
+ .group(() => {
93
+ registerDebugConfigRoutes(router, getDebugController);
94
+ registerDebugQueryAndEventRoutes(router, getApiController);
95
+ registerDebugLogRoutes(router, getApiController);
96
+ registerDebugEmailRoutes(router, getApiController);
97
+ registerDebugTraceRoutes(router, getApiController);
98
+ })
99
+ .prefix(base)
100
+ .use(middleware);
101
+ }