adonisjs-server-stats 1.5.4 → 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 (527) hide show
  1. package/README.md +351 -171
  2. package/dist/configure.d.ts.map +1 -1
  3. package/dist/core/api-client.d.ts +73 -0
  4. package/dist/core/api-client.d.ts.map +1 -0
  5. package/dist/core/config-utils.d.ts +109 -0
  6. package/dist/core/config-utils.d.ts.map +1 -0
  7. package/dist/core/constants.d.ts +11 -0
  8. package/dist/core/constants.d.ts.map +1 -0
  9. package/dist/core/dashboard-api.d.ts +65 -0
  10. package/dist/core/dashboard-api.d.ts.map +1 -0
  11. package/dist/core/dashboard-data-controller.d.ts +157 -0
  12. package/dist/core/dashboard-data-controller.d.ts.map +1 -0
  13. package/dist/core/debug-data-controller.d.ts +89 -0
  14. package/dist/core/debug-data-controller.d.ts.map +1 -0
  15. package/dist/core/feature-detect.d.ts +67 -0
  16. package/dist/core/feature-detect.d.ts.map +1 -0
  17. package/dist/core/formatters.d.ts +189 -0
  18. package/dist/core/formatters.d.ts.map +1 -0
  19. package/dist/core/history-buffer.d.ts +23 -0
  20. package/dist/core/history-buffer.d.ts.map +1 -0
  21. package/dist/core/icons.d.ts +36 -0
  22. package/dist/core/icons.d.ts.map +1 -0
  23. package/dist/core/index.d.ts +39 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +1961 -0
  26. package/dist/core/internals-utils.d.ts +71 -0
  27. package/dist/core/internals-utils.d.ts.map +1 -0
  28. package/dist/core/job-utils.d.ts +45 -0
  29. package/dist/core/job-utils.d.ts.map +1 -0
  30. package/dist/core/log-utils.d.ts +34 -0
  31. package/dist/core/log-utils.d.ts.map +1 -0
  32. package/dist/core/metrics.d.ts +41 -0
  33. package/dist/core/metrics.d.ts.map +1 -0
  34. package/dist/core/pagination.d.ts +128 -0
  35. package/dist/core/pagination.d.ts.map +1 -0
  36. package/dist/core/query-utils.d.ts +35 -0
  37. package/dist/core/query-utils.d.ts.map +1 -0
  38. package/dist/core/resizable-columns.d.ts +18 -0
  39. package/dist/core/resizable-columns.d.ts.map +1 -0
  40. package/dist/core/routes.d.ts +12 -0
  41. package/dist/core/routes.d.ts.map +1 -0
  42. package/dist/core/server-stats-controller.d.ts +106 -0
  43. package/dist/core/server-stats-controller.d.ts.map +1 -0
  44. package/dist/core/sparkline.d.ts +80 -0
  45. package/dist/core/sparkline.d.ts.map +1 -0
  46. package/dist/core/theme.d.ts +42 -0
  47. package/dist/core/theme.d.ts.map +1 -0
  48. package/dist/core/trace-utils.d.ts +62 -0
  49. package/dist/core/trace-utils.d.ts.map +1 -0
  50. package/dist/core/transmit-adapter.d.ts +59 -0
  51. package/dist/core/transmit-adapter.d.ts.map +1 -0
  52. package/dist/core/types.d.ts +619 -0
  53. package/dist/core/types.d.ts.map +1 -0
  54. package/dist/react/CacheSection-DGxMDlWK.js +146 -0
  55. package/dist/react/CacheTab-CnVW5PLs.js +123 -0
  56. package/dist/react/ConfigContent-CnsEI4j3.js +397 -0
  57. package/dist/react/ConfigSection-DPcrfqXY.js +11 -0
  58. package/dist/react/ConfigTab-BSWq_o2p.js +15 -0
  59. package/dist/react/CustomPaneTab-xjkYwTvH.js +104 -0
  60. package/dist/react/DataTable-YyShr5B-.js +55 -0
  61. package/dist/react/EmailsSection-CSyTg1aX.js +262 -0
  62. package/dist/react/EmailsTab-Dh2YSa_f.js +131 -0
  63. package/dist/react/EventsSection-C1pbJDfW.js +86 -0
  64. package/dist/react/EventsTab-eCh02cdd.js +63 -0
  65. package/dist/react/FilterBar-DQRXpWrb.js +50 -0
  66. package/dist/react/InternalsContent-DBzsI0CG.js +346 -0
  67. package/dist/react/InternalsSection-t7ihcWO-.js +32 -0
  68. package/dist/react/InternalsTab-Oij0A2fN.js +30 -0
  69. package/dist/react/JobsSection-CLAin5vU.js +187 -0
  70. package/dist/react/JobsTab-Dl5nrj2z.js +141 -0
  71. package/dist/react/LogsSection-C1p81fXO.js +212 -0
  72. package/dist/react/LogsTab-D-kR7PjX.js +88 -0
  73. package/dist/react/OverviewSection-nm3xdACz.js +539 -0
  74. package/dist/react/Pagination-BkmzUDY8.js +64 -0
  75. package/dist/react/QueriesSection-DB12HMfQ.js +461 -0
  76. package/dist/react/QueriesTab-fyBB1u_Y.js +90 -0
  77. package/dist/react/RequestsSection-DTqB81ac.js +209 -0
  78. package/dist/react/RoutesSection-DJWa4NPV.js +74 -0
  79. package/dist/react/RoutesTab-D3l8TOpu.js +74 -0
  80. package/dist/react/TimelineSection-C4d-jRX1.js +158 -0
  81. package/dist/react/TimelineTab-C5TFaSmQ.js +193 -0
  82. package/dist/react/WaterfallChart-Cj73WdfM.js +100 -0
  83. package/dist/react/core/api-client.d.ts +73 -0
  84. package/dist/react/core/api-client.d.ts.map +1 -0
  85. package/dist/react/core/config-utils.d.ts +109 -0
  86. package/dist/react/core/config-utils.d.ts.map +1 -0
  87. package/dist/react/core/constants.d.ts +11 -0
  88. package/dist/react/core/constants.d.ts.map +1 -0
  89. package/dist/react/core/dashboard-api.d.ts +65 -0
  90. package/dist/react/core/dashboard-api.d.ts.map +1 -0
  91. package/dist/react/core/dashboard-data-controller.d.ts +157 -0
  92. package/dist/react/core/dashboard-data-controller.d.ts.map +1 -0
  93. package/dist/react/core/debug-data-controller.d.ts +89 -0
  94. package/dist/react/core/debug-data-controller.d.ts.map +1 -0
  95. package/dist/react/core/feature-detect.d.ts +67 -0
  96. package/dist/react/core/feature-detect.d.ts.map +1 -0
  97. package/dist/react/core/formatters.d.ts +189 -0
  98. package/dist/react/core/formatters.d.ts.map +1 -0
  99. package/dist/react/core/history-buffer.d.ts +23 -0
  100. package/dist/react/core/history-buffer.d.ts.map +1 -0
  101. package/dist/react/core/icons.d.ts +36 -0
  102. package/dist/react/core/icons.d.ts.map +1 -0
  103. package/dist/react/core/index.d.ts +39 -0
  104. package/dist/react/core/index.d.ts.map +1 -0
  105. package/dist/react/core/internals-utils.d.ts +71 -0
  106. package/dist/react/core/internals-utils.d.ts.map +1 -0
  107. package/dist/react/core/job-utils.d.ts +45 -0
  108. package/dist/react/core/job-utils.d.ts.map +1 -0
  109. package/dist/react/core/log-utils.d.ts +34 -0
  110. package/dist/react/core/log-utils.d.ts.map +1 -0
  111. package/dist/react/core/metrics.d.ts +41 -0
  112. package/dist/react/core/metrics.d.ts.map +1 -0
  113. package/dist/react/core/pagination.d.ts +128 -0
  114. package/dist/react/core/pagination.d.ts.map +1 -0
  115. package/dist/react/core/query-utils.d.ts +35 -0
  116. package/dist/react/core/query-utils.d.ts.map +1 -0
  117. package/dist/react/core/resizable-columns.d.ts +18 -0
  118. package/dist/react/core/resizable-columns.d.ts.map +1 -0
  119. package/dist/react/core/routes.d.ts +12 -0
  120. package/dist/react/core/routes.d.ts.map +1 -0
  121. package/dist/react/core/server-stats-controller.d.ts +106 -0
  122. package/dist/react/core/server-stats-controller.d.ts.map +1 -0
  123. package/dist/react/core/sparkline.d.ts +80 -0
  124. package/dist/react/core/sparkline.d.ts.map +1 -0
  125. package/dist/react/core/theme.d.ts +42 -0
  126. package/dist/react/core/theme.d.ts.map +1 -0
  127. package/dist/react/core/trace-utils.d.ts +62 -0
  128. package/dist/react/core/trace-utils.d.ts.map +1 -0
  129. package/dist/react/core/transmit-adapter.d.ts +59 -0
  130. package/dist/react/core/transmit-adapter.d.ts.map +1 -0
  131. package/dist/react/core/types.d.ts +619 -0
  132. package/dist/react/core/types.d.ts.map +1 -0
  133. package/dist/react/index-UdTfSvtO.js +1074 -0
  134. package/dist/react/index.js +18 -0
  135. package/dist/react/react/components/Dashboard/DashboardPage.d.ts +17 -0
  136. package/dist/react/react/components/Dashboard/DashboardPage.d.ts.map +1 -0
  137. package/dist/react/react/components/Dashboard/sections/CacheSection.d.ts +7 -0
  138. package/dist/react/react/components/Dashboard/sections/CacheSection.d.ts.map +1 -0
  139. package/dist/react/react/components/Dashboard/sections/ConfigSection.d.ts +7 -0
  140. package/dist/react/react/components/Dashboard/sections/ConfigSection.d.ts.map +1 -0
  141. package/dist/react/react/components/Dashboard/sections/EmailsSection.d.ts +7 -0
  142. package/dist/react/react/components/Dashboard/sections/EmailsSection.d.ts.map +1 -0
  143. package/dist/react/react/components/Dashboard/sections/EventsSection.d.ts +7 -0
  144. package/dist/react/react/components/Dashboard/sections/EventsSection.d.ts.map +1 -0
  145. package/dist/react/react/components/Dashboard/sections/InternalsSection.d.ts +14 -0
  146. package/dist/react/react/components/Dashboard/sections/InternalsSection.d.ts.map +1 -0
  147. package/dist/react/react/components/Dashboard/sections/JobsSection.d.ts +7 -0
  148. package/dist/react/react/components/Dashboard/sections/JobsSection.d.ts.map +1 -0
  149. package/dist/react/react/components/Dashboard/sections/LogsSection.d.ts +7 -0
  150. package/dist/react/react/components/Dashboard/sections/LogsSection.d.ts.map +1 -0
  151. package/dist/react/react/components/Dashboard/sections/OverviewSection.d.ts +7 -0
  152. package/dist/react/react/components/Dashboard/sections/OverviewSection.d.ts.map +1 -0
  153. package/dist/react/react/components/Dashboard/sections/QueriesSection.d.ts +7 -0
  154. package/dist/react/react/components/Dashboard/sections/QueriesSection.d.ts.map +1 -0
  155. package/dist/react/react/components/Dashboard/sections/RequestsSection.d.ts +7 -0
  156. package/dist/react/react/components/Dashboard/sections/RequestsSection.d.ts.map +1 -0
  157. package/dist/react/react/components/Dashboard/sections/RoutesSection.d.ts +7 -0
  158. package/dist/react/react/components/Dashboard/sections/RoutesSection.d.ts.map +1 -0
  159. package/dist/react/react/components/Dashboard/sections/TimelineSection.d.ts +9 -0
  160. package/dist/react/react/components/Dashboard/sections/TimelineSection.d.ts.map +1 -0
  161. package/dist/react/react/components/Dashboard/shared/DataTable.d.ts +27 -0
  162. package/dist/react/react/components/Dashboard/shared/DataTable.d.ts.map +1 -0
  163. package/dist/react/react/components/Dashboard/shared/FilterBar.d.ts +17 -0
  164. package/dist/react/react/components/Dashboard/shared/FilterBar.d.ts.map +1 -0
  165. package/dist/react/react/components/Dashboard/shared/Pagination.d.ts +13 -0
  166. package/dist/react/react/components/Dashboard/shared/Pagination.d.ts.map +1 -0
  167. package/dist/react/react/components/Dashboard/shared/TimeRangeSelector.d.ts +12 -0
  168. package/dist/react/react/components/Dashboard/shared/TimeRangeSelector.d.ts.map +1 -0
  169. package/dist/react/react/components/Dashboard/shared/WaterfallChart.d.ts +16 -0
  170. package/dist/react/react/components/Dashboard/shared/WaterfallChart.d.ts.map +1 -0
  171. package/dist/react/react/components/DebugPanel/DebugPanel.d.ts +16 -0
  172. package/dist/react/react/components/DebugPanel/DebugPanel.d.ts.map +1 -0
  173. package/dist/react/react/components/DebugPanel/tabs/CacheTab.d.ts +8 -0
  174. package/dist/react/react/components/DebugPanel/tabs/CacheTab.d.ts.map +1 -0
  175. package/dist/react/react/components/DebugPanel/tabs/ConfigTab.d.ts +8 -0
  176. package/dist/react/react/components/DebugPanel/tabs/ConfigTab.d.ts.map +1 -0
  177. package/dist/react/react/components/DebugPanel/tabs/CustomPaneTab.d.ts +14 -0
  178. package/dist/react/react/components/DebugPanel/tabs/CustomPaneTab.d.ts.map +1 -0
  179. package/dist/react/react/components/DebugPanel/tabs/EmailsTab.d.ts +7 -0
  180. package/dist/react/react/components/DebugPanel/tabs/EmailsTab.d.ts.map +1 -0
  181. package/dist/react/react/components/DebugPanel/tabs/EventsTab.d.ts +7 -0
  182. package/dist/react/react/components/DebugPanel/tabs/EventsTab.d.ts.map +1 -0
  183. package/dist/react/react/components/DebugPanel/tabs/InternalsTab.d.ts +12 -0
  184. package/dist/react/react/components/DebugPanel/tabs/InternalsTab.d.ts.map +1 -0
  185. package/dist/react/react/components/DebugPanel/tabs/JobsTab.d.ts +9 -0
  186. package/dist/react/react/components/DebugPanel/tabs/JobsTab.d.ts.map +1 -0
  187. package/dist/react/react/components/DebugPanel/tabs/LogsTab.d.ts +7 -0
  188. package/dist/react/react/components/DebugPanel/tabs/LogsTab.d.ts.map +1 -0
  189. package/dist/react/react/components/DebugPanel/tabs/QueriesTab.d.ts +7 -0
  190. package/dist/react/react/components/DebugPanel/tabs/QueriesTab.d.ts.map +1 -0
  191. package/dist/react/react/components/DebugPanel/tabs/RoutesTab.d.ts +8 -0
  192. package/dist/react/react/components/DebugPanel/tabs/RoutesTab.d.ts.map +1 -0
  193. package/dist/react/react/components/DebugPanel/tabs/TimelineTab.d.ts +7 -0
  194. package/dist/react/react/components/DebugPanel/tabs/TimelineTab.d.ts.map +1 -0
  195. package/dist/react/react/components/StatsBar/MetricCard.d.ts +21 -0
  196. package/dist/react/react/components/StatsBar/MetricCard.d.ts.map +1 -0
  197. package/dist/react/react/components/StatsBar/Sparkline.d.ts +15 -0
  198. package/dist/react/react/components/StatsBar/Sparkline.d.ts.map +1 -0
  199. package/dist/react/react/components/StatsBar/StatsBar.d.ts +22 -0
  200. package/dist/react/react/components/StatsBar/StatsBar.d.ts.map +1 -0
  201. package/dist/react/react/components/shared/Badge.d.ts +32 -0
  202. package/dist/react/react/components/shared/Badge.d.ts.map +1 -0
  203. package/dist/react/react/components/shared/ConfigContent.d.ts +13 -0
  204. package/dist/react/react/components/shared/ConfigContent.d.ts.map +1 -0
  205. package/dist/react/react/components/shared/InternalsContent.d.ts +10 -0
  206. package/dist/react/react/components/shared/InternalsContent.d.ts.map +1 -0
  207. package/dist/react/react/components/shared/JsonViewer.d.ts +12 -0
  208. package/dist/react/react/components/shared/JsonViewer.d.ts.map +1 -0
  209. package/dist/react/react/components/shared/ThemeToggle.d.ts +13 -0
  210. package/dist/react/react/components/shared/ThemeToggle.d.ts.map +1 -0
  211. package/dist/react/react/components/shared/Tooltip.d.ts +16 -0
  212. package/dist/react/react/components/shared/Tooltip.d.ts.map +1 -0
  213. package/dist/react/react/hooks/useApiClient.d.ts +10 -0
  214. package/dist/react/react/hooks/useApiClient.d.ts.map +1 -0
  215. package/dist/react/react/hooks/useDashboardApiBase.d.ts +19 -0
  216. package/dist/react/react/hooks/useDashboardApiBase.d.ts.map +1 -0
  217. package/dist/react/react/hooks/useDashboardData.d.ts +27 -0
  218. package/dist/react/react/hooks/useDashboardData.d.ts.map +1 -0
  219. package/dist/react/react/hooks/useDebugData.d.ts +17 -0
  220. package/dist/react/react/hooks/useDebugData.d.ts.map +1 -0
  221. package/dist/react/react/hooks/useFeatures.d.ts +13 -0
  222. package/dist/react/react/hooks/useFeatures.d.ts.map +1 -0
  223. package/dist/react/react/hooks/useResizableTable.d.ts +13 -0
  224. package/dist/react/react/hooks/useResizableTable.d.ts.map +1 -0
  225. package/dist/react/react/hooks/useServerStats.d.ts +21 -0
  226. package/dist/react/react/hooks/useServerStats.d.ts.map +1 -0
  227. package/dist/react/react/hooks/useTheme.d.ts +12 -0
  228. package/dist/react/react/hooks/useTheme.d.ts.map +1 -0
  229. package/dist/react/react/index.d.ts +14 -0
  230. package/dist/react/react/index.d.ts.map +1 -0
  231. package/dist/react/style.css +1 -0
  232. package/dist/react/useApiClient-BVtNCmnL.js +9 -0
  233. package/dist/react/useDashboardApiBase-Bi36pJ2L.js +14 -0
  234. package/dist/react/useResizableTable-CNJmACdt.js +13 -0
  235. package/dist/src/collectors/app_collector.d.ts.map +1 -1
  236. package/dist/src/collectors/app_collector.js +30 -2
  237. package/dist/src/collectors/auto_detect.d.ts +31 -0
  238. package/dist/src/collectors/auto_detect.d.ts.map +1 -0
  239. package/dist/src/collectors/auto_detect.js +120 -0
  240. package/dist/src/collectors/collector.d.ts +17 -0
  241. package/dist/src/collectors/collector.d.ts.map +1 -1
  242. package/dist/src/collectors/db_pool_collector.d.ts.map +1 -1
  243. package/dist/src/collectors/db_pool_collector.js +35 -1
  244. package/dist/src/collectors/http_collector.d.ts +4 -3
  245. package/dist/src/collectors/http_collector.d.ts.map +1 -1
  246. package/dist/src/collectors/http_collector.js +28 -11
  247. package/dist/src/collectors/index.d.ts +2 -0
  248. package/dist/src/collectors/index.d.ts.map +1 -1
  249. package/dist/src/collectors/index.js +1 -0
  250. package/dist/src/collectors/log_collector.d.ts +11 -4
  251. package/dist/src/collectors/log_collector.d.ts.map +1 -1
  252. package/dist/src/collectors/log_collector.js +51 -5
  253. package/dist/src/collectors/process_collector.d.ts.map +1 -1
  254. package/dist/src/collectors/process_collector.js +4 -0
  255. package/dist/src/collectors/queue_collector.d.ts.map +1 -1
  256. package/dist/src/collectors/queue_collector.js +55 -1
  257. package/dist/src/collectors/redis_collector.d.ts.map +1 -1
  258. package/dist/src/collectors/redis_collector.js +42 -3
  259. package/dist/src/collectors/system_collector.d.ts.map +1 -1
  260. package/dist/src/collectors/system_collector.js +4 -0
  261. package/dist/src/controller/api_controller.d.ts +101 -0
  262. package/dist/src/controller/api_controller.d.ts.map +1 -0
  263. package/dist/src/controller/api_controller.js +131 -0
  264. package/dist/src/controller/debug_controller.d.ts +19 -10
  265. package/dist/src/controller/debug_controller.d.ts.map +1 -1
  266. package/dist/src/controller/debug_controller.js +118 -101
  267. package/dist/src/core/theme.d.ts +42 -0
  268. package/dist/src/core/theme.d.ts.map +1 -0
  269. package/dist/src/core/theme.js +115 -0
  270. package/dist/src/dashboard/chart_aggregator.d.ts.map +1 -1
  271. package/dist/src/dashboard/chart_aggregator.js +3 -2
  272. package/dist/src/dashboard/dashboard_controller.d.ts +10 -14
  273. package/dist/src/dashboard/dashboard_controller.d.ts.map +1 -1
  274. package/dist/src/dashboard/dashboard_controller.js +132 -250
  275. package/dist/src/dashboard/dashboard_store.d.ts +62 -19
  276. package/dist/src/dashboard/dashboard_store.d.ts.map +1 -1
  277. package/dist/src/dashboard/dashboard_store.js +242 -53
  278. package/dist/src/dashboard/integrations/cache_inspector.d.ts +19 -1
  279. package/dist/src/dashboard/integrations/cache_inspector.d.ts.map +1 -1
  280. package/dist/src/dashboard/integrations/config_inspector.d.ts +1 -1
  281. package/dist/src/dashboard/integrations/config_inspector.d.ts.map +1 -1
  282. package/dist/src/dashboard/integrations/config_inspector.js +3 -2
  283. package/dist/src/dashboard/integrations/queue_inspector.d.ts +55 -10
  284. package/dist/src/dashboard/integrations/queue_inspector.d.ts.map +1 -1
  285. package/dist/src/dashboard/integrations/queue_inspector.js +70 -24
  286. package/dist/src/dashboard/migrator.d.ts +5 -0
  287. package/dist/src/dashboard/migrator.d.ts.map +1 -1
  288. package/dist/src/dashboard/migrator.js +44 -9
  289. package/dist/src/dashboard/models/stats_event.d.ts +1 -1
  290. package/dist/src/dashboard/models/stats_event.d.ts.map +1 -1
  291. package/dist/src/dashboard/models/stats_log.d.ts +1 -1
  292. package/dist/src/dashboard/models/stats_log.d.ts.map +1 -1
  293. package/dist/src/dashboard/models/stats_query.d.ts +1 -1
  294. package/dist/src/dashboard/models/stats_query.d.ts.map +1 -1
  295. package/dist/src/dashboard/models/stats_saved_filter.d.ts +1 -1
  296. package/dist/src/dashboard/models/stats_saved_filter.d.ts.map +1 -1
  297. package/dist/src/dashboard/models/stats_trace.d.ts +2 -1
  298. package/dist/src/dashboard/models/stats_trace.d.ts.map +1 -1
  299. package/dist/src/data/data_access.d.ts +105 -0
  300. package/dist/src/data/data_access.d.ts.map +1 -0
  301. package/dist/src/data/data_access.js +310 -0
  302. package/dist/src/data/index.d.ts +3 -0
  303. package/dist/src/data/index.d.ts.map +1 -0
  304. package/dist/src/data/index.js +1 -0
  305. package/dist/src/debug/debug_store.d.ts +20 -1
  306. package/dist/src/debug/debug_store.d.ts.map +1 -1
  307. package/dist/src/debug/debug_store.js +43 -15
  308. package/dist/src/debug/email_collector.d.ts +6 -2
  309. package/dist/src/debug/email_collector.d.ts.map +1 -1
  310. package/dist/src/debug/email_collector.js +3 -0
  311. package/dist/src/debug/event_collector.d.ts +6 -2
  312. package/dist/src/debug/event_collector.d.ts.map +1 -1
  313. package/dist/src/debug/event_collector.js +12 -8
  314. package/dist/src/debug/query_collector.d.ts +6 -2
  315. package/dist/src/debug/query_collector.d.ts.map +1 -1
  316. package/dist/src/debug/query_collector.js +3 -0
  317. package/dist/src/debug/ring_buffer.d.ts +1 -0
  318. package/dist/src/debug/ring_buffer.d.ts.map +1 -1
  319. package/dist/src/debug/ring_buffer.js +5 -2
  320. package/dist/src/debug/route_inspector.d.ts +2 -2
  321. package/dist/src/debug/route_inspector.d.ts.map +1 -1
  322. package/dist/src/debug/route_inspector.js +4 -3
  323. package/dist/src/debug/trace_collector.d.ts +7 -3
  324. package/dist/src/debug/trace_collector.d.ts.map +1 -1
  325. package/dist/src/debug/trace_collector.js +7 -5
  326. package/dist/src/debug/types.d.ts +107 -2
  327. package/dist/src/debug/types.d.ts.map +1 -1
  328. package/dist/src/debug/types.js +1 -1
  329. package/dist/src/define_config.d.ts +49 -5
  330. package/dist/src/define_config.d.ts.map +1 -1
  331. package/dist/src/define_config.js +361 -4
  332. package/dist/src/edge/bootstrap.d.ts +17 -0
  333. package/dist/src/edge/bootstrap.d.ts.map +1 -0
  334. package/dist/src/edge/bootstrap.js +29 -0
  335. package/dist/src/edge/client/dashboard.js +2 -3619
  336. package/dist/src/edge/client/debug-panel-deferred.js +1 -0
  337. package/dist/src/edge/client/debug-panel.js +1 -2140
  338. package/dist/src/edge/client/stats-bar.js +1 -801
  339. package/dist/src/edge/client-vue/dashboard.js +5 -0
  340. package/dist/src/edge/client-vue/debug-panel-deferred.js +4 -0
  341. package/dist/src/edge/client-vue/debug-panel.js +4 -0
  342. package/dist/src/edge/client-vue/stats-bar.js +4 -0
  343. package/dist/src/edge/plugin.d.ts +35 -2
  344. package/dist/src/edge/plugin.d.ts.map +1 -1
  345. package/dist/src/edge/plugin.js +30 -66
  346. package/dist/src/edge/types.d.ts +46 -0
  347. package/dist/src/edge/types.d.ts.map +1 -0
  348. package/dist/src/edge/types.js +4 -0
  349. package/dist/src/edge/views/dashboard.edge +1 -358
  350. package/dist/src/edge/views/debug-panel.edge +2 -154
  351. package/dist/src/edge/views/stats-bar.edge +15 -48
  352. package/dist/src/engine/stats_engine.d.ts +18 -0
  353. package/dist/src/engine/stats_engine.d.ts.map +1 -1
  354. package/dist/src/engine/stats_engine.js +45 -2
  355. package/dist/src/index.d.ts +1 -1
  356. package/dist/src/index.d.ts.map +1 -1
  357. package/dist/src/log_stream/log_stream_provider.d.ts.map +1 -1
  358. package/dist/src/log_stream/log_stream_provider.js +21 -4
  359. package/dist/src/log_stream/log_stream_service.d.ts +8 -1
  360. package/dist/src/log_stream/log_stream_service.d.ts.map +1 -1
  361. package/dist/src/log_stream/log_stream_service.js +27 -3
  362. package/dist/src/middleware/request_tracking_middleware.d.ts +1 -1
  363. package/dist/src/middleware/request_tracking_middleware.d.ts.map +1 -1
  364. package/dist/src/middleware/request_tracking_middleware.js +21 -6
  365. package/dist/src/prometheus/prometheus_collector.d.ts +2 -1
  366. package/dist/src/prometheus/prometheus_collector.d.ts.map +1 -1
  367. package/dist/src/provider/server_stats_provider.d.ts +100 -0
  368. package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
  369. package/dist/src/provider/server_stats_provider.js +460 -104
  370. package/dist/src/routes/access_middleware.d.ts +2 -1
  371. package/dist/src/routes/access_middleware.d.ts.map +1 -1
  372. package/dist/src/routes/access_middleware.js +7 -1
  373. package/dist/src/routes/index.d.ts +4 -0
  374. package/dist/src/routes/index.d.ts.map +1 -0
  375. package/dist/src/routes/index.js +1 -0
  376. package/dist/src/routes/register_routes.d.ts +103 -0
  377. package/dist/src/routes/register_routes.d.ts.map +1 -0
  378. package/dist/src/routes/register_routes.js +356 -0
  379. package/dist/src/routes/router_types.d.ts +29 -0
  380. package/dist/src/routes/router_types.d.ts.map +1 -0
  381. package/dist/src/routes/router_types.js +1 -0
  382. package/dist/src/stubs/config.stub +12 -32
  383. package/dist/src/styles/components.css +1048 -0
  384. package/dist/src/{edge/client → styles}/dashboard.css +299 -736
  385. package/dist/src/{edge/client → styles}/debug-panel.css +117 -633
  386. package/dist/src/{edge/client → styles}/stats-bar.css +28 -10
  387. package/dist/src/styles/tokens.css +153 -0
  388. package/dist/src/styles/utilities.css +75 -0
  389. package/dist/src/types.d.ts +119 -16
  390. package/dist/src/types.d.ts.map +1 -1
  391. package/dist/src/utils/app_import.d.ts +23 -0
  392. package/dist/src/utils/app_import.d.ts.map +1 -0
  393. package/dist/src/utils/app_import.js +44 -0
  394. package/dist/src/utils/json_helpers.d.ts +2 -2
  395. package/dist/src/utils/json_helpers.d.ts.map +1 -1
  396. package/dist/src/utils/logger.d.ts +17 -0
  397. package/dist/src/utils/logger.d.ts.map +1 -0
  398. package/dist/src/utils/logger.js +27 -0
  399. package/dist/src/utils/mail_helpers.d.ts +1 -1
  400. package/dist/src/utils/mail_helpers.d.ts.map +1 -1
  401. package/dist/src/utils/mail_helpers.js +1 -1
  402. package/dist/vue/CacheSection-C788Yfai.js +149 -0
  403. package/dist/vue/CacheTab-BPisYYiQ.js +104 -0
  404. package/dist/vue/ConfigSection-CRzYxqW2.js +576 -0
  405. package/dist/vue/ConfigTab-C8cafGUj.js +361 -0
  406. package/dist/vue/CustomPaneTab-BJxT5Dp7.js +172 -0
  407. package/dist/vue/EmailsSection-C8JFMtW7.js +206 -0
  408. package/dist/vue/EmailsTab-DhFhoNmU.js +157 -0
  409. package/dist/vue/EventsSection-C4wXUgxG.js +107 -0
  410. package/dist/vue/EventsTab-DQ4Nd6AK.js +97 -0
  411. package/dist/vue/FilterBar.vue_vue_type_script_setup_true_lang-ClJ37hhT.js +62 -0
  412. package/dist/vue/InternalsSection-BJUXE-5F.js +468 -0
  413. package/dist/vue/InternalsTab-DEMjqtlw.js +471 -0
  414. package/dist/vue/JobsSection-CsKWTjgN.js +187 -0
  415. package/dist/vue/JobsTab-BCvhOARO.js +117 -0
  416. package/dist/vue/JsonViewer.vue_vue_type_script_setup_true_lang-Vsqar1zx.js +67 -0
  417. package/dist/vue/LogsSection-BFVjSZ24.js +227 -0
  418. package/dist/vue/LogsTab-DpEQ7euu.js +122 -0
  419. package/dist/vue/OverviewSection-CbMdAido.js +849 -0
  420. package/dist/vue/PaginationControls.vue_vue_type_script_setup_true_lang-CuN7g_8Z.js +50 -0
  421. package/dist/vue/QueriesSection-BPiv7u3r.js +429 -0
  422. package/dist/vue/QueriesTab-C8_7oprC.js +107 -0
  423. package/dist/vue/RequestsSection-LtImH4rD.js +243 -0
  424. package/dist/vue/RoutesSection-CrxOxmzx.js +106 -0
  425. package/dist/vue/RoutesTab-Dz0MkZuF.js +80 -0
  426. package/dist/vue/TimelineSection-DLxMW2J_.js +186 -0
  427. package/dist/vue/TimelineTab-Db6lKKsD.js +250 -0
  428. package/dist/vue/WaterfallChart.vue_vue_type_script_setup_true_lang-tZ13cNj1.js +118 -0
  429. package/dist/vue/components/Dashboard/DashboardPage.vue.d.ts +18 -0
  430. package/dist/vue/components/Dashboard/DashboardPage.vue.d.ts.map +1 -0
  431. package/dist/vue/components/Dashboard/sections/CacheSection.vue.d.ts +5 -0
  432. package/dist/vue/components/Dashboard/sections/CacheSection.vue.d.ts.map +1 -0
  433. package/dist/vue/components/Dashboard/sections/ConfigSection.vue.d.ts +3 -0
  434. package/dist/vue/components/Dashboard/sections/ConfigSection.vue.d.ts.map +1 -0
  435. package/dist/vue/components/Dashboard/sections/EmailsSection.vue.d.ts +5 -0
  436. package/dist/vue/components/Dashboard/sections/EmailsSection.vue.d.ts.map +1 -0
  437. package/dist/vue/components/Dashboard/sections/EventsSection.vue.d.ts +5 -0
  438. package/dist/vue/components/Dashboard/sections/EventsSection.vue.d.ts.map +1 -0
  439. package/dist/vue/components/Dashboard/sections/InternalsSection.vue.d.ts +3 -0
  440. package/dist/vue/components/Dashboard/sections/InternalsSection.vue.d.ts.map +1 -0
  441. package/dist/vue/components/Dashboard/sections/JobsSection.vue.d.ts +5 -0
  442. package/dist/vue/components/Dashboard/sections/JobsSection.vue.d.ts.map +1 -0
  443. package/dist/vue/components/Dashboard/sections/LogsSection.vue.d.ts +3 -0
  444. package/dist/vue/components/Dashboard/sections/LogsSection.vue.d.ts.map +1 -0
  445. package/dist/vue/components/Dashboard/sections/OverviewSection.vue.d.ts +5 -0
  446. package/dist/vue/components/Dashboard/sections/OverviewSection.vue.d.ts.map +1 -0
  447. package/dist/vue/components/Dashboard/sections/QueriesSection.vue.d.ts +45 -0
  448. package/dist/vue/components/Dashboard/sections/QueriesSection.vue.d.ts.map +1 -0
  449. package/dist/vue/components/Dashboard/sections/RequestsSection.vue.d.ts +5 -0
  450. package/dist/vue/components/Dashboard/sections/RequestsSection.vue.d.ts.map +1 -0
  451. package/dist/vue/components/Dashboard/sections/RoutesSection.vue.d.ts +5 -0
  452. package/dist/vue/components/Dashboard/sections/RoutesSection.vue.d.ts.map +1 -0
  453. package/dist/vue/components/Dashboard/sections/TimelineSection.vue.d.ts +11 -0
  454. package/dist/vue/components/Dashboard/sections/TimelineSection.vue.d.ts.map +1 -0
  455. package/dist/vue/components/Dashboard/shared/FilterBar.vue.d.ts +29 -0
  456. package/dist/vue/components/Dashboard/shared/FilterBar.vue.d.ts.map +1 -0
  457. package/dist/vue/components/Dashboard/shared/PaginationControls.vue.d.ts +12 -0
  458. package/dist/vue/components/Dashboard/shared/PaginationControls.vue.d.ts.map +1 -0
  459. package/dist/vue/components/Dashboard/shared/TimeRangeSelector.vue.d.ts +11 -0
  460. package/dist/vue/components/Dashboard/shared/TimeRangeSelector.vue.d.ts.map +1 -0
  461. package/dist/vue/components/Dashboard/shared/WaterfallChart.vue.d.ts +10 -0
  462. package/dist/vue/components/Dashboard/shared/WaterfallChart.vue.d.ts.map +1 -0
  463. package/dist/vue/components/DebugPanel/DebugPanel.vue.d.ts +21 -0
  464. package/dist/vue/components/DebugPanel/DebugPanel.vue.d.ts.map +1 -0
  465. package/dist/vue/components/DebugPanel/tabs/CacheTab.vue.d.ts +12 -0
  466. package/dist/vue/components/DebugPanel/tabs/CacheTab.vue.d.ts.map +1 -0
  467. package/dist/vue/components/DebugPanel/tabs/ConfigTab.vue.d.ts +11 -0
  468. package/dist/vue/components/DebugPanel/tabs/ConfigTab.vue.d.ts.map +1 -0
  469. package/dist/vue/components/DebugPanel/tabs/CustomPaneTab.vue.d.ts +11 -0
  470. package/dist/vue/components/DebugPanel/tabs/CustomPaneTab.vue.d.ts.map +1 -0
  471. package/dist/vue/components/DebugPanel/tabs/EmailsTab.vue.d.ts +12 -0
  472. package/dist/vue/components/DebugPanel/tabs/EmailsTab.vue.d.ts.map +1 -0
  473. package/dist/vue/components/DebugPanel/tabs/EventsTab.vue.d.ts +12 -0
  474. package/dist/vue/components/DebugPanel/tabs/EventsTab.vue.d.ts.map +1 -0
  475. package/dist/vue/components/DebugPanel/tabs/InternalsTab.vue.d.ts +11 -0
  476. package/dist/vue/components/DebugPanel/tabs/InternalsTab.vue.d.ts.map +1 -0
  477. package/dist/vue/components/DebugPanel/tabs/JobsTab.vue.d.ts +13 -0
  478. package/dist/vue/components/DebugPanel/tabs/JobsTab.vue.d.ts.map +1 -0
  479. package/dist/vue/components/DebugPanel/tabs/LogsTab.vue.d.ts +15 -0
  480. package/dist/vue/components/DebugPanel/tabs/LogsTab.vue.d.ts.map +1 -0
  481. package/dist/vue/components/DebugPanel/tabs/QueriesTab.vue.d.ts +12 -0
  482. package/dist/vue/components/DebugPanel/tabs/QueriesTab.vue.d.ts.map +1 -0
  483. package/dist/vue/components/DebugPanel/tabs/RoutesTab.vue.d.ts +12 -0
  484. package/dist/vue/components/DebugPanel/tabs/RoutesTab.vue.d.ts.map +1 -0
  485. package/dist/vue/components/DebugPanel/tabs/TimelineTab.vue.d.ts +15 -0
  486. package/dist/vue/components/DebugPanel/tabs/TimelineTab.vue.d.ts.map +1 -0
  487. package/dist/vue/components/StatsBar/MetricCard.vue.d.ts +19 -0
  488. package/dist/vue/components/StatsBar/MetricCard.vue.d.ts.map +1 -0
  489. package/dist/vue/components/StatsBar/Sparkline.vue.d.ts +17 -0
  490. package/dist/vue/components/StatsBar/Sparkline.vue.d.ts.map +1 -0
  491. package/dist/vue/components/StatsBar/StatsBar.vue.d.ts +22 -0
  492. package/dist/vue/components/StatsBar/StatsBar.vue.d.ts.map +1 -0
  493. package/dist/vue/components/shared/JsonViewer.vue.d.ts +13 -0
  494. package/dist/vue/components/shared/JsonViewer.vue.d.ts.map +1 -0
  495. package/dist/vue/components/shared/ThemeToggle.vue.d.ts +8 -0
  496. package/dist/vue/components/shared/ThemeToggle.vue.d.ts.map +1 -0
  497. package/dist/vue/composables/useApiClient.d.ts +9 -0
  498. package/dist/vue/composables/useApiClient.d.ts.map +1 -0
  499. package/dist/vue/composables/useDashboardData.d.ts +53 -0
  500. package/dist/vue/composables/useDashboardData.d.ts.map +1 -0
  501. package/dist/vue/composables/useDebugData.d.ts +25 -0
  502. package/dist/vue/composables/useDebugData.d.ts.map +1 -0
  503. package/dist/vue/composables/useFeatures.d.ts +80 -0
  504. package/dist/vue/composables/useFeatures.d.ts.map +1 -0
  505. package/dist/vue/composables/useResizableTable.d.ts +16 -0
  506. package/dist/vue/composables/useResizableTable.d.ts.map +1 -0
  507. package/dist/vue/composables/useServerStats.d.ts +104 -0
  508. package/dist/vue/composables/useServerStats.d.ts.map +1 -0
  509. package/dist/vue/composables/useTheme.d.ts +6 -0
  510. package/dist/vue/composables/useTheme.d.ts.map +1 -0
  511. package/dist/vue/index-qCQpBftQ.js +1233 -0
  512. package/dist/vue/index.d.ts +10 -0
  513. package/dist/vue/index.d.ts.map +1 -0
  514. package/dist/vue/index.js +11 -0
  515. package/dist/vue/style.css +1 -0
  516. package/dist/vue/useApiClient-BQQ9CF-q.js +10 -0
  517. package/dist/vue/useResizableTable-BoivAevK.js +17 -0
  518. package/package.json +72 -10
  519. package/dist/src/dashboard/dashboard_routes.d.ts +0 -16
  520. package/dist/src/dashboard/dashboard_routes.d.ts.map +0 -1
  521. package/dist/src/dashboard/dashboard_routes.js +0 -77
  522. package/dist/src/routes/debug_routes.d.ts +0 -14
  523. package/dist/src/routes/debug_routes.d.ts.map +0 -1
  524. package/dist/src/routes/debug_routes.js +0 -42
  525. package/dist/src/routes/stats_routes.d.ts +0 -14
  526. package/dist/src/routes/stats_routes.d.ts.map +0 -1
  527. package/dist/src/routes/stats_routes.js +0 -27
@@ -1,2140 +1 @@
1
- /**
2
- * Client-side script for the debug panel.
3
- *
4
- * Handles panel toggle, tab switching, lazy data fetching,
5
- * query/event/route table rendering, and log streaming.
6
- *
7
- * Config is read from data-* attributes on #ss-dbg-panel:
8
- * data-logs-endpoint — logs API URL
9
- */
10
- ;(function () {
11
- const REFRESH_INTERVAL = 3000
12
- const panel = document.getElementById('ss-dbg-panel')
13
- const wrench = document.getElementById('ss-dbg-wrench')
14
- const BASE = (panel && panel.dataset.debugEndpoint) || '/admin/api/debug'
15
- const closeBtn = document.getElementById('ss-dbg-close')
16
-
17
- if (!panel || !wrench) return
18
-
19
- // ── Theme detection & toggle ────────────────────────────────────
20
- let themeOverride = localStorage.getItem('ss-dash-theme')
21
- const themeBtn = document.getElementById('ss-dbg-theme-btn')
22
-
23
- const applyPanelTheme = () => {
24
- if (themeOverride) {
25
- panel.setAttribute('data-ss-theme', themeOverride)
26
- } else {
27
- panel.removeAttribute('data-ss-theme')
28
- }
29
- if (themeBtn) {
30
- const isDark =
31
- themeOverride === 'dark' ||
32
- (!themeOverride && window.matchMedia('(prefers-color-scheme: dark)').matches)
33
- themeBtn.textContent = isDark ? '\u2600' : '\u263D'
34
- themeBtn.title = isDark ? 'Switch to light theme' : 'Switch to dark theme'
35
- }
36
- }
37
-
38
- if (themeBtn) {
39
- themeBtn.addEventListener('click', function () {
40
- const isDark =
41
- themeOverride === 'dark' ||
42
- (!themeOverride && window.matchMedia('(prefers-color-scheme: dark)').matches)
43
- themeOverride = isDark ? 'light' : 'dark'
44
- localStorage.setItem('ss-dash-theme', themeOverride)
45
- applyPanelTheme()
46
- // Sync stats bar if applyBarTheme exists globally
47
- if (typeof window.__ssApplyBarTheme === 'function') window.__ssApplyBarTheme()
48
- })
49
- }
50
-
51
- applyPanelTheme()
52
-
53
- // Listen for cross-tab theme changes
54
- window.addEventListener('storage', function (e) {
55
- if (e.key === 'ss-dash-theme') {
56
- themeOverride = e.newValue
57
- applyPanelTheme()
58
- }
59
- })
60
-
61
- const LOGS_ENDPOINT = panel.dataset.logsEndpoint || BASE + '/logs'
62
-
63
- const tracingEnabled = panel.dataset.tracing === '1'
64
- const dashboardPath = panel.dataset.dashboardPath || null
65
- const DASH_API = dashboardPath ? dashboardPath.replace(/\/+$/, '') + '/api' : null
66
-
67
- /** Build an SVG external-link icon for deep links. */
68
- const deepLinkSvg =
69
- '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>'
70
-
71
- /** Build a deep link anchor element HTML string. */
72
- const deepLink = (section, id) => {
73
- if (!dashboardPath) return ''
74
- const href = dashboardPath + '#' + section + (id != null ? '?id=' + id : '')
75
- return (
76
- ' <a href="' +
77
- esc(href) +
78
- '" target="_blank" class="ss-dbg-deeplink" title="Open in dashboard" onclick="event.stopPropagation()">' +
79
- deepLinkSvg +
80
- '</a>'
81
- )
82
- }
83
-
84
- let isOpen = false
85
- let activeTab = tracingEnabled ? 'timeline' : 'queries'
86
- const fetched = {}
87
- let refreshTimer = null
88
- let logFilter = 'all'
89
- let cachedLogs = []
90
- const currentPath = window.location.pathname
91
- let isLive = false
92
- let transmitSub = null
93
-
94
- // ── Helpers ──────────────────────────────────────────────────────
95
- const esc = (s) => {
96
- if (typeof s !== 'string') s = '' + s
97
- return s
98
- .replace(/&/g, '&amp;')
99
- .replace(/</g, '&lt;')
100
- .replace(/>/g, '&gt;')
101
- .replace(/"/g, '&quot;')
102
- }
103
-
104
- const timeAgo = (ts) => {
105
- const diff = Math.floor((Date.now() - ts) / 1000)
106
- if (diff < 60) return diff + 's ago'
107
- if (diff < 3600) return Math.floor(diff / 60) + 'm ago'
108
- return Math.floor(diff / 3600) + 'h ago'
109
- }
110
-
111
- const formatTime = (ts) => {
112
- const d = new Date(ts)
113
- return (
114
- d.toLocaleTimeString('en-US', {
115
- hour12: false,
116
- hour: '2-digit',
117
- minute: '2-digit',
118
- second: '2-digit',
119
- }) +
120
- '.' +
121
- String(d.getMilliseconds()).padStart(3, '0')
122
- )
123
- }
124
-
125
- const eventPreview = (data) => {
126
- if (!data) return '-'
127
- try {
128
- const parsed = JSON.parse(data)
129
- return compactPreview(parsed, 100)
130
- } catch {
131
- return data.length > 100 ? data.slice(0, 100) + '...' : data
132
- }
133
- }
134
-
135
- const compactPreview = (val, maxLen) => {
136
- if (val === null) return 'null'
137
- if (typeof val === 'string')
138
- return '"' + (val.length > 40 ? val.slice(0, 40) + '...' : val) + '"'
139
- if (typeof val === 'number' || typeof val === 'boolean') return String(val)
140
- if (Array.isArray(val)) {
141
- if (val.length === 0) return '[]'
142
- const items = val.slice(0, 3).map((v) => compactPreview(v, 30))
143
- const s =
144
- '[' + items.join(', ') + (val.length > 3 ? ', ...' + val.length + ' items' : '') + ']'
145
- return s.length > maxLen ? '[' + val.length + ' items]' : s
146
- }
147
- if (typeof val === 'object') {
148
- const keys = Object.keys(val)
149
- if (keys.length === 0) return '{}'
150
- const pairs = []
151
- for (let i = 0; i < Math.min(keys.length, 4); i++) {
152
- const k = keys[i]
153
- const v = compactPreview(val[k], 30)
154
- pairs.push(k + ': ' + v)
155
- }
156
- const s =
157
- '{ ' + pairs.join(', ') + (keys.length > 4 ? ', ...+' + (keys.length - 4) : '') + ' }'
158
- return s.length > maxLen
159
- ? '{ ' + keys.slice(0, 6).join(', ') + (keys.length > 6 ? ', ...' : '') + ' }'
160
- : s
161
- }
162
- return String(val)
163
- }
164
-
165
- const methodClass = (m) =>
166
- 'ss-dbg-method ss-dbg-method-' + (typeof m === 'string' ? m.toLowerCase() : '')
167
-
168
- const durationClass = (ms) => {
169
- if (ms > 500) return 'ss-dbg-very-slow'
170
- if (ms > 100) return 'ss-dbg-slow'
171
- return ''
172
- }
173
-
174
- // ── Custom pane cell formatter ────────────────────────────────────
175
- const formatCell = (value, col) => {
176
- if (value === null || value === undefined) return '<span class="ss-dbg-c-dim">-</span>'
177
- const fmt = col.format || 'text'
178
- switch (fmt) {
179
- case 'time':
180
- return typeof value === 'number' ? formatTime(value) : esc(value)
181
- case 'timeAgo':
182
- return (
183
- '<span class="ss-dbg-event-time">' +
184
- (typeof value === 'number' ? timeAgo(value) : esc(value)) +
185
- '</span>'
186
- )
187
- case 'duration': {
188
- const ms = typeof value === 'number' ? value : parseFloat(value)
189
- if (isNaN(ms)) return esc(value)
190
- return (
191
- '<span class="ss-dbg-duration ' + durationClass(ms) + '">' + ms.toFixed(2) + 'ms</span>'
192
- )
193
- }
194
- case 'method':
195
- return '<span class="' + methodClass(value) + '">' + esc(value) + '</span>'
196
- case 'json': {
197
- if (typeof value === 'string') {
198
- try {
199
- value = JSON.parse(value)
200
- } catch {
201
- /* use as-is */
202
- }
203
- }
204
- const preview = typeof value === 'object' ? compactPreview(value, 100) : String(value)
205
- return (
206
- '<span class="ss-dbg-data-preview" style="cursor:default">' + esc(preview) + '</span>'
207
- )
208
- }
209
- case 'badge': {
210
- const sv = String(value).toLowerCase()
211
- const colorMap = col.badgeColorMap || {}
212
- const color = colorMap[sv] || 'muted'
213
- return (
214
- '<span class="ss-dbg-badge ss-dbg-badge-' + esc(color) + '">' + esc(value) + '</span>'
215
- )
216
- }
217
- default:
218
- return esc(value)
219
- }
220
- }
221
-
222
- // ── Toggle panel ────────────────────────────────────────────────
223
- const togglePanel = () => {
224
- isOpen = !isOpen
225
- panel.classList.toggle('ss-dbg-open', isOpen)
226
- wrench.classList.toggle('ss-dbg-active', isOpen)
227
-
228
- if (isOpen) {
229
- loadTab(activeTab)
230
- startRefresh()
231
- } else {
232
- stopRefresh()
233
- }
234
- }
235
-
236
- wrench.addEventListener('click', (e) => {
237
- e.stopPropagation()
238
- togglePanel()
239
- })
240
-
241
- if (closeBtn) {
242
- closeBtn.addEventListener('click', () => {
243
- if (isOpen) togglePanel()
244
- })
245
- }
246
-
247
- document.addEventListener('keydown', (e) => {
248
- if (e.key === 'Escape' && isOpen) togglePanel()
249
- })
250
-
251
- // ── Custom panes config ─────────────────────────────────────────
252
- let customPanes = []
253
- const customPaneState = {}
254
- try {
255
- const cfgEl = document.getElementById('ss-dbg-custom-panes-config')
256
- if (cfgEl) customPanes = JSON.parse(cfgEl.textContent || '[]')
257
- } catch {
258
- /* ignore */
259
- }
260
-
261
- for (let i = 0; i < customPanes.length; i++) {
262
- const cp = customPanes[i]
263
- customPaneState[cp.id] = { data: [], fetched: false, filter: '' }
264
- }
265
-
266
- // ── Tab switching ───────────────────────────────────────────────
267
- const tabs = panel.querySelectorAll('[data-ss-dbg-tab]')
268
- tabs.forEach((tab) => {
269
- tab.addEventListener('click', () => {
270
- const name = tab.getAttribute('data-ss-dbg-tab')
271
- if (name === activeTab) return
272
-
273
- tabs.forEach((t) => t.classList.remove('ss-dbg-active'))
274
- panel.querySelectorAll('.ss-dbg-pane').forEach((p) => p.classList.remove('ss-dbg-active'))
275
-
276
- tab.classList.add('ss-dbg-active')
277
- tab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })
278
- const pane = document.getElementById('ss-dbg-pane-' + name)
279
- if (pane) pane.classList.add('ss-dbg-active')
280
-
281
- activeTab = name
282
- loadTab(name)
283
- })
284
- })
285
-
286
- // ── Data loading ────────────────────────────────────────────────
287
- const loadTab = (name) => {
288
- if (name === 'timeline') fetchTraces()
289
- else if (name === 'queries') fetchQueries()
290
- else if (name === 'events') fetchEvents()
291
- else if (name === 'routes' && !fetched.routes) fetchRoutes()
292
- else if (name === 'logs') fetchLogs()
293
- else if (name === 'emails') fetchEmails()
294
- else if (name === 'cache') fetchCache()
295
- else if (name === 'jobs') fetchJobs()
296
- else if (name === 'config' && !fetched.config) fetchConfig()
297
- else {
298
- const cp = customPanes.find((p) => p.id === name)
299
- if (cp) {
300
- if (cp.fetchOnce && customPaneState[cp.id].fetched) return
301
- fetchCustomPane(cp)
302
- }
303
- }
304
- }
305
-
306
- const fetchJSON = (url) =>
307
- fetch(url, { credentials: 'same-origin' }).then((r) => {
308
- if (!r.ok) throw new Error(r.status)
309
- return r.json()
310
- })
311
-
312
- // ── Queries Tab ─────────────────────────────────────────────────
313
- const querySearchInput = document.getElementById('ss-dbg-search-queries')
314
- const querySummaryEl = document.getElementById('ss-dbg-queries-summary')
315
- const queryBodyEl = document.getElementById('ss-dbg-queries-body')
316
- const queryClearBtn = document.getElementById('ss-dbg-queries-clear')
317
- let cachedQueries = { queries: [], summary: {} }
318
-
319
- const fetchQueries = () => {
320
- fetchJSON(BASE + '/queries')
321
- .then((data) => {
322
- cachedQueries = data
323
- renderQueries()
324
- })
325
- .catch(() => {
326
- queryBodyEl.innerHTML = '<div class="ss-dbg-empty">Failed to load queries</div>'
327
- })
328
- }
329
-
330
- const renderQueries = () => {
331
- const filter = (querySearchInput ? querySearchInput.value : '').toLowerCase()
332
- const queries = cachedQueries.queries || []
333
- const summary = cachedQueries.summary || {}
334
-
335
- if (querySummaryEl) {
336
- querySummaryEl.textContent =
337
- summary.total +
338
- ' queries' +
339
- (summary.slow > 0 ? ', ' + summary.slow + ' slow' : '') +
340
- (summary.duplicates > 0 ? ', ' + summary.duplicates + ' dup' : '') +
341
- ', avg ' +
342
- (summary.avgDuration || 0).toFixed(1) +
343
- 'ms'
344
- }
345
-
346
- const badge = document.getElementById('ss-dbg-query-badge')
347
- if (badge && activeTab === 'queries') {
348
- badge.textContent =
349
- summary.total + ' queries, avg ' + (summary.avgDuration || 0).toFixed(1) + 'ms'
350
- }
351
-
352
- let filtered = queries
353
- if (filter) {
354
- filtered = queries.filter(
355
- (q) =>
356
- q.sql.toLowerCase().indexOf(filter) !== -1 ||
357
- (q.model || '').toLowerCase().indexOf(filter) !== -1 ||
358
- q.method.toLowerCase().indexOf(filter) !== -1
359
- )
360
- }
361
-
362
- if (filtered.length === 0) {
363
- queryBodyEl.innerHTML =
364
- '<div class="ss-dbg-empty">' +
365
- (filter ? 'No matching queries' : 'No queries recorded yet') +
366
- '</div>'
367
- return
368
- }
369
-
370
- const sqlCounts = {}
371
- for (let i = 0; i < queries.length; i++) {
372
- sqlCounts[queries[i].sql] = (sqlCounts[queries[i].sql] || 0) + 1
373
- }
374
-
375
- let html =
376
- '<table class="ss-dbg-table"><thead><tr>' +
377
- '<th style="width:64px">#</th>' +
378
- '<th>SQL</th>' +
379
- '<th style="width:70px">Duration</th>' +
380
- '<th style="width:60px">Method</th>' +
381
- '<th style="width:100px">Model</th>' +
382
- '<th style="width:60px">Time</th>' +
383
- '</tr></thead><tbody>'
384
-
385
- for (let j = 0; j < filtered.length; j++) {
386
- const q = filtered[j]
387
- const durClass = durationClass(q.duration)
388
- const dupCount = sqlCounts[q.sql] || 1
389
- html +=
390
- '<tr>' +
391
- '<td class="ss-dbg-c-dim" style="white-space:nowrap">' +
392
- q.id +
393
- deepLink('queries', q.id) +
394
- '</td>' +
395
- '<td><span class="ss-dbg-sql" title="Click to expand" onclick="this.classList.toggle(\'ss-dbg-expanded\')">' +
396
- esc(q.sql) +
397
- '</span>' +
398
- (dupCount > 1 ? ' <span class="ss-dbg-dup">x' + dupCount + '</span>' : '') +
399
- '</td>' +
400
- '<td class="ss-dbg-duration ' +
401
- durClass +
402
- '">' +
403
- q.duration.toFixed(2) +
404
- 'ms</td>' +
405
- '<td><span class="' +
406
- methodClass(q.method) +
407
- '">' +
408
- esc(q.method) +
409
- '</span></td>' +
410
- '<td class="ss-dbg-c-muted">' +
411
- esc(q.model || '-') +
412
- '</td>' +
413
- '<td class="ss-dbg-event-time">' +
414
- timeAgo(q.timestamp) +
415
- '</td>' +
416
- '</tr>'
417
- }
418
-
419
- html += '</tbody></table>'
420
- queryBodyEl.innerHTML = html
421
- }
422
-
423
- if (querySearchInput) querySearchInput.addEventListener('input', renderQueries)
424
- if (queryClearBtn) {
425
- queryClearBtn.addEventListener('click', () => {
426
- cachedQueries = { queries: [], summary: { total: 0, slow: 0, duplicates: 0, avgDuration: 0 } }
427
- renderQueries()
428
- })
429
- }
430
-
431
- // ── Events Tab ──────────────────────────────────────────────────
432
- const eventSearchInput = document.getElementById('ss-dbg-search-events')
433
- const eventSummaryEl = document.getElementById('ss-dbg-events-summary')
434
- const eventBodyEl = document.getElementById('ss-dbg-events-body')
435
- const eventClearBtn = document.getElementById('ss-dbg-events-clear')
436
- let cachedEvents = { events: [], total: 0 }
437
-
438
- const fetchEvents = () => {
439
- fetchJSON(BASE + '/events')
440
- .then((data) => {
441
- cachedEvents = data
442
- renderEvents()
443
- })
444
- .catch(() => {
445
- eventBodyEl.innerHTML = '<div class="ss-dbg-empty">Failed to load events</div>'
446
- })
447
- }
448
-
449
- const renderEvents = () => {
450
- const filter = (eventSearchInput ? eventSearchInput.value : '').toLowerCase()
451
- const events = cachedEvents.events || []
452
-
453
- if (eventSummaryEl) {
454
- eventSummaryEl.textContent = cachedEvents.total + ' events'
455
- }
456
-
457
- let filtered = events
458
- if (filter) {
459
- filtered = events.filter(
460
- (e) =>
461
- e.event.toLowerCase().indexOf(filter) !== -1 ||
462
- (e.data || '').toLowerCase().indexOf(filter) !== -1
463
- )
464
- }
465
-
466
- if (filtered.length === 0) {
467
- eventBodyEl.innerHTML =
468
- '<div class="ss-dbg-empty">' +
469
- (filter ? 'No matching events' : 'No events recorded yet') +
470
- '</div>'
471
- return
472
- }
473
-
474
- let html =
475
- '<table class="ss-dbg-table"><thead><tr>' +
476
- '<th style="width:64px">#</th>' +
477
- '<th>Event</th>' +
478
- '<th>Data</th>' +
479
- '<th style="width:100px">Time</th>' +
480
- '</tr></thead><tbody>'
481
-
482
- for (let i = 0; i < filtered.length; i++) {
483
- const ev = filtered[i]
484
- const hasData = ev.data && ev.data !== '-'
485
- const preview = hasData ? eventPreview(ev.data) : '-'
486
- html +=
487
- '<tr>' +
488
- '<td class="ss-dbg-c-dim" style="white-space:nowrap">' +
489
- ev.id +
490
- deepLink('events', ev.id) +
491
- '</td>' +
492
- '<td class="ss-dbg-event-name">' +
493
- esc(ev.event) +
494
- '</td>' +
495
- '<td class="ss-dbg-event-data">' +
496
- (hasData
497
- ? '<span class="ss-dbg-data-preview" data-ev-idx="' +
498
- i +
499
- '">' +
500
- esc(preview) +
501
- '</span>' +
502
- '<pre class="ss-dbg-data-full" id="ss-dbg-evdata-' +
503
- i +
504
- '" style="display:none">' +
505
- esc(ev.data) +
506
- '</pre>' +
507
- '<button type="button" class="ss-dbg-copy-btn" data-copy-idx="' +
508
- i +
509
- '" title="Copy JSON">&#x2398;</button>'
510
- : '<span class="ss-dbg-c-dim">-</span>') +
511
- '</td>' +
512
- '<td class="ss-dbg-event-time">' +
513
- formatTime(ev.timestamp) +
514
- '</td>' +
515
- '</tr>'
516
- }
517
-
518
- html += '</tbody></table>'
519
- eventBodyEl.innerHTML = html
520
-
521
- // Toggle expand on preview click
522
- eventBodyEl.querySelectorAll('.ss-dbg-data-preview').forEach((el) => {
523
- el.addEventListener('click', () => {
524
- const idx = el.getAttribute('data-ev-idx')
525
- const pre = document.getElementById('ss-dbg-evdata-' + idx)
526
- if (pre) {
527
- const open = pre.style.display !== 'none'
528
- pre.style.display = open ? 'none' : 'block'
529
- el.style.display = open ? '' : 'none'
530
- }
531
- })
532
- })
533
-
534
- // Collapse on full-data click
535
- eventBodyEl.querySelectorAll('.ss-dbg-data-full').forEach((el) => {
536
- el.addEventListener('click', () => {
537
- el.style.display = 'none'
538
- const idx = el.id.replace('ss-dbg-evdata-', '')
539
- const preview = eventBodyEl.querySelector('[data-ev-idx="' + idx + '"]')
540
- if (preview) preview.style.display = ''
541
- })
542
- })
543
-
544
- // Copy button
545
- eventBodyEl.querySelectorAll('.ss-dbg-copy-btn').forEach((btn) => {
546
- btn.addEventListener('click', (e) => {
547
- e.stopPropagation()
548
- const idx = btn.getAttribute('data-copy-idx')
549
- const data = filtered[idx]?.data || ''
550
- navigator.clipboard.writeText(data).then(() => {
551
- btn.textContent = '\u2713'
552
- setTimeout(() => {
553
- btn.innerHTML = '&#x2398;'
554
- }, 1200)
555
- })
556
- })
557
- })
558
- }
559
-
560
- if (eventSearchInput) eventSearchInput.addEventListener('input', renderEvents)
561
- if (eventClearBtn) {
562
- eventClearBtn.addEventListener('click', () => {
563
- cachedEvents = { events: [], total: 0 }
564
- renderEvents()
565
- })
566
- }
567
-
568
- // ── Routes Tab ──────────────────────────────────────────────────
569
- const routeSearchInput = document.getElementById('ss-dbg-search-routes')
570
- const routeSummaryEl = document.getElementById('ss-dbg-routes-summary')
571
- const routeBodyEl = document.getElementById('ss-dbg-routes-body')
572
- let cachedRoutes = { routes: [], total: 0 }
573
-
574
- const fetchRoutes = () => {
575
- fetchJSON(BASE + '/routes')
576
- .then((data) => {
577
- cachedRoutes = data
578
- fetched.routes = true
579
- renderRoutes()
580
- })
581
- .catch(() => {
582
- routeBodyEl.innerHTML = '<div class="ss-dbg-empty">Failed to load routes</div>'
583
- })
584
- }
585
-
586
- const renderRoutes = () => {
587
- const filter = (routeSearchInput ? routeSearchInput.value : '').toLowerCase()
588
- const routes = cachedRoutes.routes || []
589
-
590
- if (routeSummaryEl) {
591
- routeSummaryEl.textContent = cachedRoutes.total + ' routes'
592
- }
593
-
594
- let filtered = routes
595
- if (filter) {
596
- filtered = routes.filter(
597
- (r) =>
598
- r.pattern.toLowerCase().indexOf(filter) !== -1 ||
599
- r.method.toLowerCase().indexOf(filter) !== -1 ||
600
- (r.name || '').toLowerCase().indexOf(filter) !== -1 ||
601
- r.handler.toLowerCase().indexOf(filter) !== -1 ||
602
- r.middleware.join(' ').toLowerCase().indexOf(filter) !== -1
603
- )
604
- }
605
-
606
- if (filtered.length === 0) {
607
- routeBodyEl.innerHTML =
608
- '<div class="ss-dbg-empty">' +
609
- (filter ? 'No matching routes' : 'No routes available') +
610
- '</div>'
611
- return
612
- }
613
-
614
- let html =
615
- '<table class="ss-dbg-table"><thead><tr>' +
616
- '<th style="width:60px">Method</th>' +
617
- '<th>Pattern</th>' +
618
- '<th style="width:140px">Name</th>' +
619
- '<th>Handler</th>' +
620
- '<th>Middleware</th>' +
621
- '</tr></thead><tbody>'
622
-
623
- for (let i = 0; i < filtered.length; i++) {
624
- const r = filtered[i]
625
- const isCurrent =
626
- currentPath === r.pattern ||
627
- currentPath.match(new RegExp('^' + r.pattern.replace(/:[^/]+/g, '[^/]+') + '$'))
628
- html +=
629
- '<tr' +
630
- (isCurrent ? ' class="ss-dbg-current-route"' : '') +
631
- '>' +
632
- '<td><span class="' +
633
- methodClass(r.method) +
634
- '">' +
635
- esc(r.method) +
636
- '</span></td>' +
637
- '<td>' +
638
- esc(r.pattern) +
639
- '</td>' +
640
- '<td class="ss-dbg-c-muted">' +
641
- esc(r.name || '-') +
642
- '</td>' +
643
- '<td class="ss-dbg-c-sql">' +
644
- esc(r.handler) +
645
- '</td>' +
646
- '<td class="ss-dbg-c-dim" style="font-size:10px">' +
647
- (r.middleware.length ? esc(r.middleware.join(', ')) : '-') +
648
- '</td>' +
649
- '</tr>'
650
- }
651
-
652
- html += '</tbody></table>'
653
- routeBodyEl.innerHTML = html
654
- }
655
-
656
- if (routeSearchInput) routeSearchInput.addEventListener('input', renderRoutes)
657
-
658
- // ── Logs Tab ────────────────────────────────────────────────────
659
- const logBodyEl = document.getElementById('ss-dbg-logs-body')
660
- const logFilters = panel.querySelectorAll('[data-ss-dbg-level]')
661
- const logReqIdInput = document.getElementById('ss-dbg-log-reqid')
662
- const logReqIdClear = document.getElementById('ss-dbg-log-reqid-clear')
663
- let logReqIdFilter = ''
664
-
665
- const setReqIdFilter = (id) => {
666
- logReqIdFilter = id || ''
667
- if (logReqIdInput) logReqIdInput.value = logReqIdFilter
668
- if (logReqIdClear) logReqIdClear.style.display = logReqIdFilter ? '' : 'none'
669
- renderLogs()
670
- }
671
-
672
- if (logReqIdInput) {
673
- logReqIdInput.addEventListener('input', () => {
674
- logReqIdFilter = logReqIdInput.value.trim()
675
- if (logReqIdClear) logReqIdClear.style.display = logReqIdFilter ? '' : 'none'
676
- renderLogs()
677
- })
678
- }
679
- if (logReqIdClear) {
680
- logReqIdClear.addEventListener('click', () => setReqIdFilter(''))
681
- }
682
-
683
- const fetchLogs = () => {
684
- fetchJSON(LOGS_ENDPOINT)
685
- .then((data) => {
686
- cachedLogs = Array.isArray(data) ? data : data.logs || data.entries || []
687
- renderLogs()
688
- })
689
- .catch(() => {
690
- logBodyEl.innerHTML = '<div class="ss-dbg-empty">No log endpoint available</div>'
691
- })
692
- }
693
-
694
- const shortReqId = (id) => (id ? id.slice(0, 8) : '')
695
-
696
- const renderLogs = () => {
697
- let entries = cachedLogs
698
-
699
- if (logFilter !== 'all') {
700
- entries = entries.filter((e) => {
701
- const level = (e.levelName || e.level_name || '').toLowerCase()
702
- if (logFilter === 'error') return level === 'error' || level === 'fatal'
703
- return level === logFilter
704
- })
705
- }
706
-
707
- if (logReqIdFilter) {
708
- const f = logReqIdFilter.toLowerCase()
709
- entries = entries.filter((e) => {
710
- const rid = (e.request_id || e['x-request-id'] || '').toLowerCase()
711
- return rid.indexOf(f) !== -1
712
- })
713
- }
714
-
715
- if (entries.length === 0) {
716
- let hint = ''
717
- if (logReqIdFilter) hint = ' matching request ' + logReqIdFilter
718
- else if (logFilter !== 'all') hint = ' for ' + logFilter
719
- logBodyEl.innerHTML = '<div class="ss-dbg-empty">No log entries' + hint + '</div>'
720
- return
721
- }
722
-
723
- const shown = entries.slice(-200).reverse()
724
- let html = ''
725
-
726
- for (let i = 0; i < shown.length; i++) {
727
- const e = shown[i]
728
- const level = (e.levelName || e.level_name || 'info').toLowerCase()
729
- const msg = e.msg || e.message || JSON.stringify(e)
730
- const ts = e.time || e.timestamp || 0
731
- const reqId = e.request_id || e['x-request-id'] || ''
732
-
733
- html +=
734
- '<div class="ss-dbg-log-entry">' +
735
- '<span class="ss-dbg-log-level ss-dbg-log-level-' +
736
- esc(level) +
737
- '">' +
738
- esc(level.toUpperCase()) +
739
- '</span>' +
740
- '<span class="ss-dbg-log-time">' +
741
- (ts ? formatTime(ts) : '-') +
742
- '</span>' +
743
- (reqId
744
- ? '<span class="ss-dbg-log-reqid" data-reqid="' +
745
- esc(reqId) +
746
- '" title="' +
747
- esc(reqId) +
748
- '">' +
749
- esc(shortReqId(reqId)) +
750
- '</span>'
751
- : '<span class="ss-dbg-log-reqid-empty">-</span>') +
752
- '<span class="ss-dbg-log-msg">' +
753
- esc(msg) +
754
- '</span>' +
755
- '</div>'
756
- }
757
-
758
- logBodyEl.innerHTML = html
759
-
760
- // Click request ID to filter
761
- logBodyEl.querySelectorAll('.ss-dbg-log-reqid').forEach((el) => {
762
- el.addEventListener('click', () => {
763
- setReqIdFilter(el.getAttribute('data-reqid'))
764
- })
765
- })
766
- }
767
-
768
- logFilters.forEach((btn) => {
769
- btn.addEventListener('click', () => {
770
- logFilters.forEach((b) => b.classList.remove('ss-dbg-active'))
771
- btn.classList.add('ss-dbg-active')
772
- logFilter = btn.getAttribute('data-ss-dbg-level')
773
- renderLogs()
774
- })
775
- })
776
-
777
- // ── Emails Tab ─────────────────────────────────────────────────
778
- const emailSearchInput = document.getElementById('ss-dbg-search-emails')
779
- const emailSummaryEl = document.getElementById('ss-dbg-emails-summary')
780
- const emailBodyEl = document.getElementById('ss-dbg-emails-body')
781
- const emailClearBtn = document.getElementById('ss-dbg-emails-clear')
782
- const emailPreviewEl = document.getElementById('ss-dbg-email-preview')
783
- const emailPreviewMeta = document.getElementById('ss-dbg-email-preview-meta')
784
- const emailPreviewClose = document.getElementById('ss-dbg-email-preview-close')
785
- const emailIframe = document.getElementById('ss-dbg-email-iframe')
786
- let cachedEmails = { emails: [], total: 0 }
787
-
788
- const fetchEmails = () => {
789
- fetchJSON(BASE + '/emails')
790
- .then((data) => {
791
- cachedEmails = data
792
- renderEmails()
793
- })
794
- .catch(() => {
795
- if (emailBodyEl)
796
- emailBodyEl.innerHTML = '<div class="ss-dbg-empty">Failed to load emails</div>'
797
- })
798
- }
799
-
800
- const renderEmails = () => {
801
- if (!emailBodyEl) return
802
- const filter = (emailSearchInput ? emailSearchInput.value : '').toLowerCase()
803
- const emails = cachedEmails.emails || []
804
-
805
- if (emailSummaryEl) {
806
- emailSummaryEl.textContent = cachedEmails.total + ' emails'
807
- }
808
-
809
- let filtered = emails
810
- if (filter) {
811
- filtered = emails.filter(
812
- (e) =>
813
- (e.from || '').toLowerCase().indexOf(filter) !== -1 ||
814
- (e.to || '').toLowerCase().indexOf(filter) !== -1 ||
815
- (e.subject || '').toLowerCase().indexOf(filter) !== -1 ||
816
- (e.mailer || '').toLowerCase().indexOf(filter) !== -1
817
- )
818
- }
819
-
820
- if (filtered.length === 0) {
821
- emailBodyEl.innerHTML =
822
- '<div class="ss-dbg-empty">' +
823
- (filter ? 'No matching emails' : 'No emails captured yet') +
824
- '</div>'
825
- return
826
- }
827
-
828
- let html =
829
- '<table class="ss-dbg-table"><thead><tr>' +
830
- '<th style="width:64px">#</th>' +
831
- '<th style="width:160px">From</th>' +
832
- '<th style="width:160px">To</th>' +
833
- '<th>Subject</th>' +
834
- '<th style="width:60px">Status</th>' +
835
- '<th style="width:60px">Mailer</th>' +
836
- '<th style="width:30px" title="Attachments">&#x1F4CE;</th>' +
837
- '<th style="width:70px">Time</th>' +
838
- '</tr></thead><tbody>'
839
-
840
- for (let i = 0; i < filtered.length; i++) {
841
- const e = filtered[i]
842
- html +=
843
- '<tr class="ss-dbg-email-row" data-email-id="' +
844
- e.id +
845
- '">' +
846
- '<td class="ss-dbg-c-dim" style="white-space:nowrap">' +
847
- e.id +
848
- deepLink('emails', e.id) +
849
- '</td>' +
850
- '<td class="ss-dbg-c-secondary" style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:160px" title="' +
851
- esc(e.from) +
852
- '">' +
853
- esc(e.from) +
854
- '</td>' +
855
- '<td class="ss-dbg-c-secondary" style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:160px" title="' +
856
- esc(e.to) +
857
- '">' +
858
- esc(e.to) +
859
- '</td>' +
860
- '<td class="ss-dbg-c-sql" style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' +
861
- esc(e.subject) +
862
- '</td>' +
863
- '<td><span class="ss-dbg-email-status ss-dbg-email-status-' +
864
- esc(e.status) +
865
- '">' +
866
- esc(e.status) +
867
- '</span></td>' +
868
- '<td class="ss-dbg-c-muted">' +
869
- esc(e.mailer) +
870
- '</td>' +
871
- '<td class="ss-dbg-c-dim" style="text-align:center">' +
872
- (e.attachmentCount > 0 ? e.attachmentCount : '-') +
873
- '</td>' +
874
- '<td class="ss-dbg-event-time">' +
875
- timeAgo(e.timestamp) +
876
- '</td>' +
877
- '</tr>'
878
- }
879
-
880
- html += '</tbody></table>'
881
- emailBodyEl.innerHTML = html
882
-
883
- // Click row to open preview
884
- emailBodyEl.querySelectorAll('.ss-dbg-email-row').forEach((row) => {
885
- row.addEventListener('click', () => {
886
- const id = row.getAttribute('data-email-id')
887
- showEmailPreview(id, filtered)
888
- })
889
- })
890
- }
891
-
892
- const showEmailPreview = (id, emails) => {
893
- if (!emailPreviewEl || !emailIframe || !emailPreviewMeta) return
894
- const email = emails.find((e) => String(e.id) === String(id))
895
-
896
- if (emailPreviewMeta && email) {
897
- emailPreviewMeta.innerHTML =
898
- '<strong>Subject:</strong> ' +
899
- esc(email.subject) +
900
- '&nbsp;&nbsp;|&nbsp;&nbsp;<strong>From:</strong> ' +
901
- esc(email.from) +
902
- '&nbsp;&nbsp;|&nbsp;&nbsp;<strong>To:</strong> ' +
903
- esc(email.to) +
904
- (email.cc ? '&nbsp;&nbsp;|&nbsp;&nbsp;<strong>CC:</strong> ' + esc(email.cc) : '') +
905
- '&nbsp;&nbsp;|&nbsp;&nbsp;<strong>Status:</strong> <span class="ss-dbg-email-status ss-dbg-email-status-' +
906
- esc(email.status) +
907
- '">' +
908
- esc(email.status) +
909
- '</span>' +
910
- '&nbsp;&nbsp;|&nbsp;&nbsp;<strong>Mailer:</strong> ' +
911
- esc(email.mailer)
912
- }
913
-
914
- emailIframe.src = BASE + '/emails/' + id + '/preview'
915
- emailPreviewEl.style.display = 'flex'
916
- }
917
-
918
- if (emailPreviewClose) {
919
- emailPreviewClose.addEventListener('click', () => {
920
- if (emailPreviewEl) emailPreviewEl.style.display = 'none'
921
- if (emailIframe) emailIframe.src = 'about:blank'
922
- })
923
- }
924
-
925
- if (emailSearchInput) emailSearchInput.addEventListener('input', renderEmails)
926
- if (emailClearBtn) {
927
- emailClearBtn.addEventListener('click', () => {
928
- cachedEmails = { emails: [], total: 0 }
929
- renderEmails()
930
- })
931
- }
932
-
933
- // ── Timeline Tab ────────────────────────────────────────────────
934
- const tlSearchInput = document.getElementById('ss-dbg-search-timeline')
935
- const tlSummaryEl = document.getElementById('ss-dbg-timeline-summary')
936
- const tlBodyEl = document.getElementById('ss-dbg-timeline-body')
937
- const tlListEl = document.getElementById('ss-dbg-timeline-list')
938
- const tlDetailEl = document.getElementById('ss-dbg-timeline-detail')
939
- const tlBackBtn = document.getElementById('ss-dbg-tl-back')
940
- const tlDetailTitle = document.getElementById('ss-dbg-tl-detail-title')
941
- const tlWaterfall = document.getElementById('ss-dbg-tl-waterfall')
942
- let cachedTraces = { traces: [], total: 0 }
943
-
944
- const statusClass = (code) => {
945
- if (code >= 500) return 'ss-dbg-status-5xx'
946
- if (code >= 400) return 'ss-dbg-status-4xx'
947
- if (code >= 300) return 'ss-dbg-status-3xx'
948
- return 'ss-dbg-status-2xx'
949
- }
950
-
951
- const fetchTraces = () => {
952
- if (!tracingEnabled) return
953
- fetchJSON(BASE + '/traces')
954
- .then((data) => {
955
- cachedTraces = data
956
- renderTraces()
957
- })
958
- .catch(() => {
959
- if (tlBodyEl) tlBodyEl.innerHTML = '<div class="ss-dbg-empty">Failed to load traces</div>'
960
- })
961
- }
962
-
963
- const renderTraces = () => {
964
- if (!tlBodyEl) return
965
- const filter = (tlSearchInput ? tlSearchInput.value : '').toLowerCase()
966
- const traces = cachedTraces.traces || []
967
-
968
- if (tlSummaryEl) {
969
- tlSummaryEl.textContent = cachedTraces.total + ' requests'
970
- }
971
-
972
- let filtered = traces
973
- if (filter) {
974
- filtered = traces.filter(
975
- (t) =>
976
- t.url.toLowerCase().indexOf(filter) !== -1 ||
977
- t.method.toLowerCase().indexOf(filter) !== -1
978
- )
979
- }
980
-
981
- if (filtered.length === 0) {
982
- tlBodyEl.innerHTML =
983
- '<div class="ss-dbg-empty">' +
984
- (filter ? 'No matching requests' : 'No requests traced yet') +
985
- '</div>'
986
- return
987
- }
988
-
989
- let html =
990
- '<table class="ss-dbg-table"><thead><tr>' +
991
- '<th style="width:64px">#</th>' +
992
- '<th style="width:60px">Method</th>' +
993
- '<th>URL</th>' +
994
- '<th style="width:55px">Status</th>' +
995
- '<th style="width:70px">Duration</th>' +
996
- '<th style="width:50px">Spans</th>' +
997
- '<th style="width:30px" title="Warnings">&#x26A0;</th>' +
998
- '<th style="width:70px">Time</th>' +
999
- '</tr></thead><tbody>'
1000
-
1001
- for (let i = 0; i < filtered.length; i++) {
1002
- const t = filtered[i]
1003
- html +=
1004
- '<tr class="ss-dbg-email-row" data-trace-id="' +
1005
- t.id +
1006
- '">' +
1007
- '<td class="ss-dbg-c-dim" style="white-space:nowrap">' +
1008
- t.id +
1009
- deepLink('traces', t.id) +
1010
- '</td>' +
1011
- '<td><span class="' +
1012
- methodClass(t.method) +
1013
- '">' +
1014
- esc(t.method) +
1015
- '</span></td>' +
1016
- '<td style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px" title="' +
1017
- esc(t.url) +
1018
- '">' +
1019
- esc(t.url) +
1020
- '</td>' +
1021
- '<td><span class="ss-dbg-status ' +
1022
- statusClass(t.statusCode) +
1023
- '">' +
1024
- t.statusCode +
1025
- '</span></td>' +
1026
- '<td class="ss-dbg-duration ' +
1027
- durationClass(t.totalDuration) +
1028
- '">' +
1029
- t.totalDuration.toFixed(1) +
1030
- 'ms</td>' +
1031
- '<td class="ss-dbg-c-muted" style="text-align:center">' +
1032
- t.spanCount +
1033
- '</td>' +
1034
- '<td style="text-align:center">' +
1035
- (t.warningCount > 0
1036
- ? '<span class="ss-dbg-c-amber">' + t.warningCount + '</span>'
1037
- : '<span class="ss-dbg-c-border">-</span>') +
1038
- '</td>' +
1039
- '<td class="ss-dbg-event-time">' +
1040
- timeAgo(t.timestamp) +
1041
- '</td>' +
1042
- '</tr>'
1043
- }
1044
-
1045
- html += '</tbody></table>'
1046
- tlBodyEl.innerHTML = html
1047
-
1048
- // Click row to open detail
1049
- tlBodyEl.querySelectorAll('[data-trace-id]').forEach((row) => {
1050
- row.addEventListener('click', () => {
1051
- const id = row.getAttribute('data-trace-id')
1052
- fetchTraceDetail(id)
1053
- })
1054
- })
1055
- }
1056
-
1057
- const fetchTraceDetail = (id) => {
1058
- fetchJSON(BASE + '/traces/' + id)
1059
- .then((trace) => {
1060
- showTimeline(trace)
1061
- })
1062
- .catch(() => {
1063
- if (tlWaterfall)
1064
- tlWaterfall.innerHTML = '<div class="ss-dbg-empty">Failed to load trace</div>'
1065
- })
1066
- }
1067
-
1068
- const showTimeline = (trace) => {
1069
- if (!tlListEl || !tlDetailEl || !tlDetailTitle || !tlWaterfall) return
1070
-
1071
- tlListEl.style.display = 'none'
1072
- tlDetailEl.style.display = ''
1073
-
1074
- tlDetailTitle.innerHTML =
1075
- '<span class="' +
1076
- methodClass(trace.method) +
1077
- '">' +
1078
- esc(trace.method) +
1079
- '</span> ' +
1080
- esc(trace.url) +
1081
- ' ' +
1082
- '<span class="ss-dbg-status ' +
1083
- statusClass(trace.statusCode) +
1084
- '">' +
1085
- trace.statusCode +
1086
- '</span>' +
1087
- '<span class="ss-dbg-tl-meta">' +
1088
- trace.totalDuration.toFixed(1) +
1089
- 'ms &middot; ' +
1090
- trace.spanCount +
1091
- ' spans &middot; ' +
1092
- formatTime(trace.timestamp) +
1093
- '</span>'
1094
-
1095
- const spans = trace.spans || []
1096
- const total = trace.totalDuration || 1
1097
-
1098
- // Legend
1099
- let html =
1100
- '<div class="ss-dbg-tl-legend">' +
1101
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#6d28d9"></span>DB</div>' +
1102
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#1e3a5f"></span>Request</div>' +
1103
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#059669"></span>Mail</div>' +
1104
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#b45309"></span>Event</div>' +
1105
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#0e7490"></span>View</div>' +
1106
- '<div class="ss-dbg-tl-legend-item"><span class="ss-dbg-tl-legend-dot" style="background:#525252"></span>Custom</div>' +
1107
- '</div>'
1108
-
1109
- if (spans.length === 0) {
1110
- html += '<div class="ss-dbg-empty">No spans captured for this request</div>'
1111
- } else {
1112
- // Build nesting depth from parentId
1113
- const depthMap = {}
1114
- for (let i = 0; i < spans.length; i++) {
1115
- const s = spans[i]
1116
- if (!s.parentId) {
1117
- depthMap[s.id] = 0
1118
- } else {
1119
- depthMap[s.id] = (depthMap[s.parentId] || 0) + 1
1120
- }
1121
- }
1122
-
1123
- // Sort by startOffset
1124
- const sorted = spans.slice().sort((a, b) => a.startOffset - b.startOffset)
1125
-
1126
- for (let i = 0; i < sorted.length; i++) {
1127
- const s = sorted[i]
1128
- const depth = depthMap[s.id] || 0
1129
- const leftPct = ((s.startOffset / total) * 100).toFixed(2)
1130
- const widthPct = Math.max((s.duration / total) * 100, 0.5).toFixed(2)
1131
- const indent = depth * 16
1132
- const catLabel = s.category === 'db' ? 'DB' : s.category
1133
- const metaStr = s.metadata
1134
- ? Object.entries(s.metadata)
1135
- .filter(([, v]) => v != null)
1136
- .map(([k, v]) => k + '=' + v)
1137
- .join(', ')
1138
- : ''
1139
- const tooltip =
1140
- s.label + ' (' + s.duration.toFixed(2) + 'ms)' + (metaStr ? '\n' + metaStr : '')
1141
-
1142
- html +=
1143
- '<div class="ss-dbg-tl-row">' +
1144
- '<div class="ss-dbg-tl-label" style="padding-left:' +
1145
- (8 + indent) +
1146
- 'px" title="' +
1147
- esc(tooltip) +
1148
- '">' +
1149
- '<span class="ss-dbg-badge ss-dbg-badge-' +
1150
- (s.category === 'db'
1151
- ? 'purple'
1152
- : s.category === 'mail'
1153
- ? 'green'
1154
- : s.category === 'event'
1155
- ? 'amber'
1156
- : s.category === 'view'
1157
- ? 'blue'
1158
- : 'muted') +
1159
- '" style="font-size:9px;margin-right:4px">' +
1160
- esc(catLabel) +
1161
- '</span>' +
1162
- esc(s.label.length > 40 ? s.label.slice(0, 40) + '...' : s.label) +
1163
- '</div>' +
1164
- '<div class="ss-dbg-tl-track">' +
1165
- '<div class="ss-dbg-tl-bar ss-dbg-tl-bar-' +
1166
- esc(s.category) +
1167
- '" style="left:' +
1168
- leftPct +
1169
- '%;width:' +
1170
- widthPct +
1171
- '%" title="' +
1172
- esc(tooltip) +
1173
- '"></div>' +
1174
- '</div>' +
1175
- '<span class="ss-dbg-tl-dur">' +
1176
- s.duration.toFixed(2) +
1177
- 'ms</span>' +
1178
- '</div>'
1179
- }
1180
- }
1181
-
1182
- // Warnings
1183
- if (trace.warnings && trace.warnings.length > 0) {
1184
- html +=
1185
- '<div class="ss-dbg-tl-warnings">' +
1186
- '<div class="ss-dbg-tl-warnings-title">Warnings (' +
1187
- trace.warnings.length +
1188
- ')</div>'
1189
- for (let w = 0; w < trace.warnings.length; w++) {
1190
- html += '<div class="ss-dbg-tl-warning">' + esc(trace.warnings[w]) + '</div>'
1191
- }
1192
- html += '</div>'
1193
- }
1194
-
1195
- tlWaterfall.innerHTML = html
1196
- }
1197
-
1198
- if (tlBackBtn) {
1199
- tlBackBtn.addEventListener('click', () => {
1200
- if (tlListEl) tlListEl.style.display = ''
1201
- if (tlDetailEl) tlDetailEl.style.display = 'none'
1202
- })
1203
- }
1204
-
1205
- if (tlSearchInput) tlSearchInput.addEventListener('input', renderTraces)
1206
-
1207
- // ── Mini Stats Bar ─────────────────────────────────────────────
1208
- const miniStatsEl = document.getElementById('ss-dbg-mini-stats')
1209
- let miniStatsTimer = null
1210
-
1211
- const fetchMiniStats = () => {
1212
- if (!DASH_API || !miniStatsEl) return
1213
- fetchJSON(DASH_API + '/overview?range=1h')
1214
- .then((data) => {
1215
- const avg = data.avgResponseTime || 0
1216
- const err = data.errorRate || 0
1217
- const rpm = data.requestsPerMinute || 0
1218
- const hasData = (data.totalRequests || 0) > 0
1219
-
1220
- if (!hasData) {
1221
- miniStatsEl.innerHTML = ''
1222
- return
1223
- }
1224
-
1225
- const avgClass =
1226
- avg > 500 ? 'ss-dbg-stat-red' : avg > 200 ? 'ss-dbg-stat-amber' : 'ss-dbg-stat-green'
1227
- const errClass =
1228
- err > 5 ? 'ss-dbg-stat-red' : err > 1 ? 'ss-dbg-stat-amber' : 'ss-dbg-stat-green'
1229
-
1230
- miniStatsEl.innerHTML =
1231
- '<span class="ss-dbg-mini-stat"><span class="ss-dbg-mini-stat-value ' +
1232
- avgClass +
1233
- '">' +
1234
- avg.toFixed(1) +
1235
- 'ms</span> avg</span>' +
1236
- '<span class="ss-dbg-mini-stat"><span class="ss-dbg-mini-stat-value ' +
1237
- errClass +
1238
- '">' +
1239
- err.toFixed(1) +
1240
- '%</span> err</span>' +
1241
- '<span class="ss-dbg-mini-stat"><span class="ss-dbg-mini-stat-value">' +
1242
- Math.round(rpm) +
1243
- '</span> req/m</span>'
1244
- })
1245
- .catch(() => {
1246
- miniStatsEl.innerHTML = ''
1247
- })
1248
- }
1249
-
1250
- // ── Cache Tab ─────────────────────────────────────────────────
1251
- const cacheSearchInput = document.getElementById('ss-dbg-search-cache')
1252
- const cacheSummaryEl = document.getElementById('ss-dbg-cache-summary')
1253
- const cacheBodyEl = document.getElementById('ss-dbg-cache-body')
1254
- const cacheStatsArea = document.getElementById('ss-dbg-cache-stats-area')
1255
- let cachedCacheData = { stats: {}, keys: [] }
1256
-
1257
- const fetchCache = () => {
1258
- if (!DASH_API) return
1259
- fetchJSON(DASH_API + '/cache')
1260
- .then((data) => {
1261
- cachedCacheData = data
1262
- renderCache()
1263
- })
1264
- .catch(() => {
1265
- if (cacheBodyEl)
1266
- cacheBodyEl.innerHTML = '<div class="ss-dbg-empty">Cache not available</div>'
1267
- if (cacheStatsArea) cacheStatsArea.innerHTML = ''
1268
- })
1269
- }
1270
-
1271
- const renderCache = () => {
1272
- if (!cacheBodyEl) return
1273
- const stats = cachedCacheData.stats || {}
1274
- const keys = cachedCacheData.keys || cachedCacheData.data || []
1275
- const filter = (cacheSearchInput ? cacheSearchInput.value : '').toLowerCase()
1276
-
1277
- // Stats area
1278
- if (cacheStatsArea) {
1279
- cacheStatsArea.innerHTML =
1280
- '<div class="ss-dbg-cache-stat"><span class="ss-dbg-cache-stat-label">Hit Rate:</span><span class="ss-dbg-cache-stat-value">' +
1281
- (stats.hitRate || 0).toFixed(1) +
1282
- '%</span></div>' +
1283
- '<div class="ss-dbg-cache-stat"><span class="ss-dbg-cache-stat-label">Hits:</span><span class="ss-dbg-cache-stat-value">' +
1284
- (stats.hits || 0) +
1285
- '</span></div>' +
1286
- '<div class="ss-dbg-cache-stat"><span class="ss-dbg-cache-stat-label">Misses:</span><span class="ss-dbg-cache-stat-value">' +
1287
- (stats.misses || 0) +
1288
- '</span></div>' +
1289
- '<div class="ss-dbg-cache-stat"><span class="ss-dbg-cache-stat-label">Keys:</span><span class="ss-dbg-cache-stat-value">' +
1290
- (stats.keyCount || keys.length || 0) +
1291
- '</span></div>'
1292
- }
1293
-
1294
- if (cacheSummaryEl) {
1295
- cacheSummaryEl.textContent = (stats.keyCount || keys.length || 0) + ' keys'
1296
- }
1297
-
1298
- let filtered = keys
1299
- if (filter) {
1300
- filtered = keys.filter((k) => (k.key || '').toLowerCase().indexOf(filter) !== -1)
1301
- }
1302
-
1303
- if (filtered.length === 0) {
1304
- cacheBodyEl.innerHTML =
1305
- '<div class="ss-dbg-empty">' +
1306
- (filter ? 'No matching cache keys' : 'No cache keys found') +
1307
- '</div>'
1308
- return
1309
- }
1310
-
1311
- let html =
1312
- '<table class="ss-dbg-table"><thead><tr>' +
1313
- '<th>Key</th>' +
1314
- '<th style="width:80px">Type</th>' +
1315
- '<th style="width:80px">TTL</th>' +
1316
- '<th style="width:80px">Size</th>' +
1317
- '</tr></thead><tbody>'
1318
-
1319
- for (let i = 0; i < filtered.length; i++) {
1320
- const k = filtered[i]
1321
- html +=
1322
- '<tr class="ss-dbg-email-row" data-cache-key="' +
1323
- esc(k.key || '') +
1324
- '">' +
1325
- '<td class="ss-dbg-c-sql">' +
1326
- esc(k.key || '') +
1327
- '</td>' +
1328
- '<td class="ss-dbg-c-muted">' +
1329
- esc(k.type || '-') +
1330
- '</td>' +
1331
- '<td class="ss-dbg-c-muted">' +
1332
- (k.ttl != null ? k.ttl + 's' : '-') +
1333
- '</td>' +
1334
- '<td class="ss-dbg-c-dim">' +
1335
- (k.size != null ? k.size + 'B' : '-') +
1336
- '</td>' +
1337
- '</tr>'
1338
- }
1339
-
1340
- html += '</tbody></table>'
1341
- cacheBodyEl.innerHTML = html
1342
-
1343
- // Click row to show cache detail
1344
- cacheBodyEl.querySelectorAll('[data-cache-key]').forEach((row) => {
1345
- row.addEventListener('click', () => {
1346
- const key = row.getAttribute('data-cache-key')
1347
- fetchJSON(DASH_API + '/cache/' + encodeURIComponent(key))
1348
- .then((data) => {
1349
- cacheBodyEl.innerHTML =
1350
- '<div class="ss-dbg-cache-detail">' +
1351
- '<button type="button" class="ss-dbg-btn-clear" id="ss-dbg-cache-back">&larr; Back</button>' +
1352
- '&nbsp;&nbsp;<strong>' +
1353
- esc(key) +
1354
- '</strong>' +
1355
- '<pre>' +
1356
- esc(JSON.stringify(data.value || data, null, 2)) +
1357
- '</pre>' +
1358
- '</div>'
1359
- const backBtn = document.getElementById('ss-dbg-cache-back')
1360
- if (backBtn) backBtn.addEventListener('click', () => renderCache())
1361
- })
1362
- .catch(() => {
1363
- /* ignore */
1364
- })
1365
- })
1366
- })
1367
- }
1368
-
1369
- if (cacheSearchInput) cacheSearchInput.addEventListener('input', renderCache)
1370
-
1371
- // ── Jobs Tab ──────────────────────────────────────────────────
1372
- const jobsBodyEl = document.getElementById('ss-dbg-jobs-body')
1373
- const jobsSummaryEl = document.getElementById('ss-dbg-jobs-summary')
1374
- const jobsStatsArea = document.getElementById('ss-dbg-jobs-stats-area')
1375
- const jobFilters = panel.querySelectorAll('[data-ss-dbg-job-status]')
1376
- let jobStatusFilter = 'all'
1377
- let cachedJobsData = { data: [], stats: {} }
1378
-
1379
- const fetchJobs = () => {
1380
- if (!DASH_API) return
1381
- let url = DASH_API + '/jobs?limit=100'
1382
- if (jobStatusFilter && jobStatusFilter !== 'all') url += '&status=' + jobStatusFilter
1383
-
1384
- fetchJSON(url)
1385
- .then((data) => {
1386
- cachedJobsData = data
1387
- renderJobs()
1388
- })
1389
- .catch(() => {
1390
- if (jobsBodyEl)
1391
- jobsBodyEl.innerHTML = '<div class="ss-dbg-empty">Jobs/Queue not available</div>'
1392
- if (jobsStatsArea) jobsStatsArea.innerHTML = ''
1393
- })
1394
- }
1395
-
1396
- const renderJobs = () => {
1397
- if (!jobsBodyEl) return
1398
- const items = cachedJobsData.data || cachedJobsData.jobs || []
1399
- const stats = cachedJobsData.stats || {}
1400
-
1401
- // Stats area
1402
- if (jobsStatsArea) {
1403
- jobsStatsArea.innerHTML =
1404
- '<div class="ss-dbg-job-stats">' +
1405
- '<div class="ss-dbg-job-stat"><span class="ss-dbg-job-stat-label">Active:</span><span class="ss-dbg-job-stat-value">' +
1406
- (stats.active || 0) +
1407
- '</span></div>' +
1408
- '<div class="ss-dbg-job-stat"><span class="ss-dbg-job-stat-label">Waiting:</span><span class="ss-dbg-job-stat-value">' +
1409
- (stats.waiting || 0) +
1410
- '</span></div>' +
1411
- '<div class="ss-dbg-job-stat"><span class="ss-dbg-job-stat-label">Delayed:</span><span class="ss-dbg-job-stat-value">' +
1412
- (stats.delayed || 0) +
1413
- '</span></div>' +
1414
- '<div class="ss-dbg-job-stat"><span class="ss-dbg-job-stat-label">Completed:</span><span class="ss-dbg-job-stat-value">' +
1415
- (stats.completed || 0) +
1416
- '</span></div>' +
1417
- '<div class="ss-dbg-job-stat"><span class="ss-dbg-job-stat-label">Failed:</span><span class="ss-dbg-job-stat-value ss-dbg-c-red">' +
1418
- (stats.failed || 0) +
1419
- '</span></div>' +
1420
- '</div>'
1421
- }
1422
-
1423
- if (jobsSummaryEl) {
1424
- const total = (cachedJobsData.meta ? cachedJobsData.meta.total : null) || items.length
1425
- jobsSummaryEl.textContent = total + ' jobs'
1426
- }
1427
-
1428
- if (items.length === 0) {
1429
- jobsBodyEl.innerHTML = '<div class="ss-dbg-empty">No jobs found</div>'
1430
- return
1431
- }
1432
-
1433
- let html =
1434
- '<table class="ss-dbg-table"><thead><tr>' +
1435
- '<th style="width:50px">ID</th>' +
1436
- '<th>Name</th>' +
1437
- '<th style="width:80px">Status</th>' +
1438
- '<th style="width:60px">Attempts</th>' +
1439
- '<th style="width:80px">Duration</th>' +
1440
- '<th style="width:70px">Time</th>' +
1441
- '<th style="width:50px"></th>' +
1442
- '</tr></thead><tbody>'
1443
-
1444
- for (let i = 0; i < items.length; i++) {
1445
- const j = items[i]
1446
- const statusBadge =
1447
- j.status === 'failed'
1448
- ? 'red'
1449
- : j.status === 'completed'
1450
- ? 'green'
1451
- : j.status === 'active'
1452
- ? 'blue'
1453
- : 'amber'
1454
- html +=
1455
- '<tr>' +
1456
- '<td class="ss-dbg-c-dim">' +
1457
- j.id +
1458
- '</td>' +
1459
- '<td class="ss-dbg-c-sql">' +
1460
- esc(j.name || '') +
1461
- '</td>' +
1462
- '<td><span class="ss-dbg-badge ss-dbg-badge-' +
1463
- statusBadge +
1464
- '">' +
1465
- esc(j.status || '') +
1466
- '</span></td>' +
1467
- '<td class="ss-dbg-c-muted" style="text-align:center">' +
1468
- (j.attempts || j.attemptsMade || 0) +
1469
- '</td>' +
1470
- '<td class="ss-dbg-duration">' +
1471
- (j.duration != null ? j.duration.toFixed(0) + 'ms' : '-') +
1472
- '</td>' +
1473
- '<td class="ss-dbg-event-time">' +
1474
- timeAgo(j.timestamp || j.processedOn || j.created_at) +
1475
- '</td>' +
1476
- '<td>' +
1477
- (j.status === 'failed'
1478
- ? '<button class="ss-dbg-retry-btn" data-retry-id="' + j.id + '">Retry</button>'
1479
- : '') +
1480
- '</td>' +
1481
- '</tr>'
1482
- }
1483
-
1484
- html += '</tbody></table>'
1485
- jobsBodyEl.innerHTML = html
1486
-
1487
- // Retry buttons
1488
- jobsBodyEl.querySelectorAll('.ss-dbg-retry-btn').forEach((btn) => {
1489
- btn.addEventListener('click', (e) => {
1490
- e.stopPropagation()
1491
- const id = btn.getAttribute('data-retry-id')
1492
- btn.textContent = '...'
1493
- btn.disabled = true
1494
- fetch(DASH_API + '/jobs/' + id + '/retry', { method: 'POST', credentials: 'same-origin' })
1495
- .then(() => {
1496
- btn.textContent = 'OK'
1497
- setTimeout(fetchJobs, 1000)
1498
- })
1499
- .catch(() => {
1500
- btn.textContent = 'Retry'
1501
- btn.disabled = false
1502
- })
1503
- })
1504
- })
1505
- }
1506
-
1507
- jobFilters.forEach((btn) => {
1508
- btn.addEventListener('click', () => {
1509
- jobFilters.forEach((b) => b.classList.remove('ss-dbg-active'))
1510
- btn.classList.add('ss-dbg-active')
1511
- jobStatusFilter = btn.getAttribute('data-ss-dbg-job-status')
1512
- fetchJobs()
1513
- })
1514
- })
1515
-
1516
- // ── Config Tab ────────────────────────────────────────────────
1517
- const configBodyEl = document.getElementById('ss-dbg-config-body')
1518
- const configSummaryEl = document.getElementById('ss-dbg-config-summary')
1519
- const configSearchInput = document.getElementById('ss-dbg-search-config')
1520
- const configTabs = panel.querySelectorAll('[data-ss-dbg-config-tab]')
1521
- let configRawData = null
1522
- let configActiveTab = 'config'
1523
- let configSearchTerm = ''
1524
-
1525
- const flattenConfig = (obj, prefix) => {
1526
- const results = []
1527
- if (typeof obj !== 'object' || obj === null) {
1528
- results.push({ path: prefix, value: obj })
1529
- return results
1530
- }
1531
- const keys = Object.keys(obj)
1532
- for (let i = 0; i < keys.length; i++) {
1533
- const fullPath = prefix ? prefix + '.' + keys[i] : keys[i]
1534
- const val = obj[keys[i]]
1535
- if (typeof val === 'object' && val !== null && !Array.isArray(val) && !val.__redacted) {
1536
- const nested = flattenConfig(val, fullPath)
1537
- for (let n = 0; n < nested.length; n++) results.push(nested[n])
1538
- } else {
1539
- results.push({ path: fullPath, value: val })
1540
- }
1541
- }
1542
- return results
1543
- }
1544
-
1545
- const countLeaves = (obj) => {
1546
- if (typeof obj !== 'object' || obj === null || obj.__redacted) return 1
1547
- let count = 0
1548
- const keys = Object.keys(obj)
1549
- for (let i = 0; i < keys.length; i++) count += countLeaves(obj[keys[i]])
1550
- return count
1551
- }
1552
-
1553
- const formatConfigValue = (val) => {
1554
- if (val === null || val === undefined) return '<span class="ss-dbg-config-val-null">null</span>'
1555
- if (val === true) return '<span class="ss-dbg-config-val-true">true</span>'
1556
- if (val === false) return '<span class="ss-dbg-config-val-false">false</span>'
1557
- if (typeof val === 'number') return '<span class="ss-dbg-config-val-number">' + val + '</span>'
1558
- if (Array.isArray(val)) {
1559
- const items = val.map((item) => {
1560
- if (item === null || item === undefined) return 'null'
1561
- if (typeof item === 'object') {
1562
- try {
1563
- return JSON.stringify(item)
1564
- } catch {
1565
- return String(item)
1566
- }
1567
- }
1568
- return String(item)
1569
- })
1570
- return '<span class="ss-dbg-config-val-array">[' + esc(items.join(', ')) + ']</span>'
1571
- }
1572
- if (typeof val === 'object') {
1573
- try {
1574
- return (
1575
- '<span class="ss-dbg-config-val-null">' + esc(JSON.stringify(val, null, 2)) + '</span>'
1576
- )
1577
- } catch {
1578
- /* fall through */
1579
- }
1580
- }
1581
- return esc(String(val))
1582
- }
1583
-
1584
- const highlightMatch = (text, term) => {
1585
- if (!term) return text
1586
- const idx = text.toLowerCase().indexOf(term.toLowerCase())
1587
- if (idx === -1) return text
1588
- return (
1589
- text.slice(0, idx) +
1590
- '<mark class="ss-dbg-config-match">' +
1591
- text.slice(idx, idx + term.length) +
1592
- '</mark>' +
1593
- text.slice(idx + term.length)
1594
- )
1595
- }
1596
-
1597
- const isRedactedObj = (val) => val && typeof val === 'object' && val.__redacted === true
1598
-
1599
- const renderRedacted = (val, prefix) => {
1600
- const cls = prefix + '-config-redacted'
1601
- const realVal = esc(val.value || '')
1602
- return (
1603
- '<span class="' +
1604
- cls +
1605
- ' ' +
1606
- prefix +
1607
- '-redacted-wrap" data-redacted-value="' +
1608
- realVal +
1609
- '">' +
1610
- '<span class="' +
1611
- prefix +
1612
- '-redacted-display">' +
1613
- esc(val.display) +
1614
- '</span>' +
1615
- '<span class="' +
1616
- prefix +
1617
- '-redacted-real" style="display:none">' +
1618
- realVal +
1619
- '</span>' +
1620
- '<button type="button" class="' +
1621
- prefix +
1622
- '-redacted-reveal" title="Reveal value">' +
1623
- '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>' +
1624
- '</button>' +
1625
- '<button type="button" class="' +
1626
- prefix +
1627
- '-redacted-copy" title="Copy value">' +
1628
- '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>' +
1629
- '</button>' +
1630
- '</span>'
1631
- )
1632
- }
1633
-
1634
- const bindRedactedButtons = (container, prefix) => {
1635
- container.querySelectorAll('.' + prefix + '-redacted-reveal').forEach((btn) => {
1636
- btn.addEventListener('click', (e) => {
1637
- e.stopPropagation()
1638
- const wrap = btn.closest('.' + prefix + '-redacted-wrap')
1639
- if (!wrap) return
1640
- const display = wrap.querySelector('.' + prefix + '-redacted-display')
1641
- const real = wrap.querySelector('.' + prefix + '-redacted-real')
1642
- if (!display || !real) return
1643
- const isHidden = real.style.display === 'none'
1644
- display.style.display = isHidden ? 'none' : ''
1645
- real.style.display = isHidden ? '' : 'none'
1646
- btn.innerHTML = isHidden
1647
- ? '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>'
1648
- : '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>'
1649
- btn.title = isHidden ? 'Hide value' : 'Reveal value'
1650
- })
1651
- })
1652
-
1653
- container.querySelectorAll('.' + prefix + '-redacted-copy').forEach((btn) => {
1654
- btn.addEventListener('click', (e) => {
1655
- e.stopPropagation()
1656
- const wrap = btn.closest('.' + prefix + '-redacted-wrap')
1657
- if (!wrap) return
1658
- const val = wrap.getAttribute('data-redacted-value')
1659
- if (!val) return
1660
- navigator.clipboard.writeText(val).then(() => {
1661
- btn.innerHTML = '\u2713'
1662
- setTimeout(() => {
1663
- btn.innerHTML =
1664
- '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'
1665
- }, 1200)
1666
- })
1667
- })
1668
- })
1669
- }
1670
-
1671
- const fetchConfig = () => {
1672
- if (!DASH_API) return
1673
- fetchJSON(DASH_API + '/config')
1674
- .then((data) => {
1675
- configRawData = data
1676
- fetched.config = true
1677
- renderConfig()
1678
- })
1679
- .catch(() => {
1680
- if (configBodyEl)
1681
- configBodyEl.innerHTML = '<div class="ss-dbg-empty">Config not available</div>'
1682
- })
1683
- }
1684
-
1685
- const renderConfigTable = (obj, prefix) => {
1686
- const flat = flattenConfig(obj, prefix)
1687
- let html =
1688
- '<table class="ss-dbg-table"><thead><tr>' +
1689
- '<th style="width:320px">Key</th><th>Value</th>' +
1690
- '</tr></thead><tbody>'
1691
- for (let i = 0; i < flat.length; i++) {
1692
- const item = flat[i]
1693
- const relPath =
1694
- item.path.indexOf(prefix + '.') === 0 ? item.path.slice(prefix.length + 1) : item.path
1695
- const redacted = isRedactedObj(item.value)
1696
- html +=
1697
- '<tr>' +
1698
- '<td><span class="ss-dbg-config-key">' +
1699
- esc(relPath) +
1700
- '</span></td>' +
1701
- '<td>' +
1702
- (redacted
1703
- ? renderRedacted(item.value, 'ss-dbg')
1704
- : '<span class="ss-dbg-config-val">' + formatConfigValue(item.value) + '</span>') +
1705
- '</td>' +
1706
- '</tr>'
1707
- }
1708
- html += '</tbody></table>'
1709
- return html
1710
- }
1711
-
1712
- const renderConfig = () => {
1713
- if (!configBodyEl || !configRawData) return
1714
-
1715
- const source =
1716
- configActiveTab === 'env' ? configRawData.env || {} : configRawData.config || configRawData
1717
- const flat = flattenConfig(source, '')
1718
- const term = configSearchTerm.toLowerCase()
1719
- let filtered = flat
1720
- if (term) {
1721
- filtered = flat.filter((item) => {
1722
- var valStr = isRedactedObj(item.value) ? item.value.display : String(item.value)
1723
- return (
1724
- item.path.toLowerCase().indexOf(term) !== -1 || valStr.toLowerCase().indexOf(term) !== -1
1725
- )
1726
- })
1727
- }
1728
-
1729
- if (configSummaryEl) {
1730
- configSummaryEl.textContent =
1731
- filtered.length + (term ? ' of ' + flat.length : '') + ' entries'
1732
- }
1733
-
1734
- let html = ''
1735
-
1736
- if (configActiveTab === 'env') {
1737
- // Env vars: simple table
1738
- html +=
1739
- '<div class="ss-dbg-config-table-wrap"><table class="ss-dbg-table"><thead><tr>' +
1740
- '<th>Variable</th><th>Value</th>' +
1741
- '</tr></thead><tbody>'
1742
- for (let i = 0; i < filtered.length; i++) {
1743
- const item = filtered[i]
1744
- const redacted = isRedactedObj(item.value)
1745
- const displayVal = redacted ? item.value.display : String(item.value)
1746
- html +=
1747
- '<tr>' +
1748
- '<td><span class="ss-dbg-config-key">' +
1749
- highlightMatch(esc(item.path), term) +
1750
- '</span></td>' +
1751
- '<td>' +
1752
- (redacted
1753
- ? renderRedacted(item.value, 'ss-dbg')
1754
- : '<span class="ss-dbg-config-val">' +
1755
- highlightMatch(esc(displayVal), term) +
1756
- '</span>') +
1757
- '</td>' +
1758
- '</tr>'
1759
- }
1760
- html += '</tbody></table></div>'
1761
- } else {
1762
- if (term) {
1763
- // Search mode: flat list
1764
- html +=
1765
- '<div class="ss-dbg-config-table-wrap"><table class="ss-dbg-table"><thead><tr>' +
1766
- '<th>Path</th><th>Value</th>' +
1767
- '</tr></thead><tbody>'
1768
- for (let i = 0; i < filtered.length; i++) {
1769
- const item = filtered[i]
1770
- const redacted = isRedactedObj(item.value)
1771
- const displayVal = redacted ? item.value.display : String(item.value)
1772
- html +=
1773
- '<tr>' +
1774
- '<td><span class="ss-dbg-config-key" style="white-space:nowrap">' +
1775
- highlightMatch(esc(item.path), term) +
1776
- '</span></td>' +
1777
- '<td>' +
1778
- (redacted
1779
- ? renderRedacted(item.value, 'ss-dbg')
1780
- : '<span class="ss-dbg-config-val" style="word-break:break-all">' +
1781
- highlightMatch(esc(displayVal), term) +
1782
- '</span>') +
1783
- '</td>' +
1784
- '</tr>'
1785
- }
1786
- html += '</tbody></table></div>'
1787
- } else {
1788
- // Browse mode: collapsible sections
1789
- const topKeys = Object.keys(source)
1790
- html += '<div class="ss-dbg-config-sections">'
1791
- for (let t = 0; t < topKeys.length; t++) {
1792
- const sectionKey = topKeys[t]
1793
- const sectionVal = source[sectionKey]
1794
- const childCount = countLeaves(sectionVal)
1795
- const isObj =
1796
- typeof sectionVal === 'object' && sectionVal !== null && !sectionVal.__redacted
1797
-
1798
- html += '<div class="ss-dbg-config-section">'
1799
- if (isObj) {
1800
- html +=
1801
- '<div class="ss-dbg-config-section-header" data-config-section="' +
1802
- esc(sectionKey) +
1803
- '">' +
1804
- '<span class="ss-dbg-config-toggle">\u25B6</span>' +
1805
- '<span class="ss-dbg-config-key">' +
1806
- esc(sectionKey) +
1807
- '</span>' +
1808
- '<span class="ss-dbg-config-count">' +
1809
- childCount +
1810
- ' entries</span>' +
1811
- '</div>'
1812
- html += '<div class="ss-dbg-config-section-body" style="display:none">'
1813
- html += renderConfigTable(sectionVal, sectionKey)
1814
- html += '</div>'
1815
- } else {
1816
- html +=
1817
- '<div class="ss-dbg-config-section-header ss-dbg-config-leaf">' +
1818
- '<span class="ss-dbg-config-key">' +
1819
- esc(sectionKey) +
1820
- '</span>' +
1821
- '<span class="ss-dbg-config-val" style="margin-left:8px">' +
1822
- formatConfigValue(sectionVal) +
1823
- '</span>' +
1824
- '</div>'
1825
- }
1826
- html += '</div>'
1827
- }
1828
- html += '</div>'
1829
- }
1830
- }
1831
-
1832
- configBodyEl.innerHTML = html
1833
-
1834
- // Bind section toggles
1835
- configBodyEl.querySelectorAll('[data-config-section]').forEach((header) => {
1836
- header.addEventListener('click', () => {
1837
- const sectionBody = header.nextElementSibling
1838
- if (!sectionBody) return
1839
- const isHidden = sectionBody.style.display === 'none'
1840
- sectionBody.style.display = isHidden ? '' : 'none'
1841
- const toggle = header.querySelector('.ss-dbg-config-toggle')
1842
- if (toggle) toggle.textContent = isHidden ? '\u25BC' : '\u25B6'
1843
- })
1844
- })
1845
-
1846
- // Bind redacted reveal/copy buttons
1847
- bindRedactedButtons(configBodyEl, 'ss-dbg')
1848
- }
1849
-
1850
- configTabs.forEach((btn) => {
1851
- btn.addEventListener('click', () => {
1852
- configTabs.forEach((b) => b.classList.remove('ss-dbg-active'))
1853
- btn.classList.add('ss-dbg-active')
1854
- configActiveTab = btn.getAttribute('data-ss-dbg-config-tab')
1855
- renderConfig()
1856
- })
1857
- })
1858
-
1859
- if (configSearchInput) {
1860
- configSearchInput.addEventListener('input', () => {
1861
- configSearchTerm = configSearchInput.value.trim()
1862
- renderConfig()
1863
- })
1864
- }
1865
-
1866
- // ── Custom panes: fetch, render, bind ───────────────────────────
1867
- const getNestedValue = (obj, path) => {
1868
- const parts = path.split('.')
1869
- let cur = obj
1870
- for (let i = 0; i < parts.length; i++) {
1871
- if (cur == null) return undefined
1872
- cur = cur[parts[i]]
1873
- }
1874
- return cur
1875
- }
1876
-
1877
- const fetchCustomPane = (pane) => {
1878
- const bodyEl = document.getElementById('ss-dbg-' + pane.id + '-body')
1879
- fetchJSON(pane.endpoint)
1880
- .then((data) => {
1881
- const key = pane.dataKey || pane.id
1882
- const rows = getNestedValue(data, key) || (Array.isArray(data) ? data : [])
1883
- customPaneState[pane.id].data = rows
1884
- customPaneState[pane.id].fetched = true
1885
- renderCustomPane(pane)
1886
- })
1887
- .catch(() => {
1888
- if (bodyEl)
1889
- bodyEl.innerHTML =
1890
- '<div class="ss-dbg-empty">Failed to load ' + esc(pane.label) + '</div>'
1891
- })
1892
- }
1893
-
1894
- const renderCustomPane = (pane) => {
1895
- const state = customPaneState[pane.id]
1896
- if (!state) return
1897
- const bodyEl = document.getElementById('ss-dbg-' + pane.id + '-body')
1898
- const summaryEl = document.getElementById('ss-dbg-' + pane.id + '-summary')
1899
- if (!bodyEl) return
1900
-
1901
- const filter = state.filter.toLowerCase()
1902
- let rows = state.data
1903
-
1904
- if (summaryEl) {
1905
- summaryEl.textContent = rows.length + ' ' + pane.label.toLowerCase()
1906
- }
1907
-
1908
- if (filter) {
1909
- const searchCols = pane.columns.filter((c) => c.searchable)
1910
- if (searchCols.length > 0) {
1911
- rows = rows.filter((row) =>
1912
- searchCols.some((c) => {
1913
- const v = row[c.key]
1914
- return v != null && String(v).toLowerCase().indexOf(filter) !== -1
1915
- })
1916
- )
1917
- }
1918
- }
1919
-
1920
- if (rows.length === 0) {
1921
- bodyEl.innerHTML =
1922
- '<div class="ss-dbg-empty">' +
1923
- (filter
1924
- ? 'No matching ' + esc(pane.label.toLowerCase())
1925
- : 'No ' + esc(pane.label.toLowerCase()) + ' recorded yet') +
1926
- '</div>'
1927
- return
1928
- }
1929
-
1930
- let html = '<table class="ss-dbg-table"><thead><tr>'
1931
- for (let c = 0; c < pane.columns.length; c++) {
1932
- const col = pane.columns[c]
1933
- html +=
1934
- '<th' +
1935
- (col.width ? ' style="width:' + col.width + '"' : '') +
1936
- '>' +
1937
- esc(col.label) +
1938
- '</th>'
1939
- }
1940
- html += '</tr></thead><tbody>'
1941
-
1942
- for (let r = 0; r < rows.length; r++) {
1943
- html += '<tr>'
1944
- for (let c = 0; c < pane.columns.length; c++) {
1945
- const col = pane.columns[c]
1946
- const val = rows[r][col.key]
1947
- const cellHtml = formatCell(val, col)
1948
- if (col.filterable && val != null) {
1949
- html +=
1950
- '<td class="ss-dbg-filterable" data-ss-filter-key="' +
1951
- esc(col.key) +
1952
- '" data-ss-filter-val="' +
1953
- esc(String(val)) +
1954
- '">' +
1955
- cellHtml +
1956
- '</td>'
1957
- } else {
1958
- html += '<td>' + cellHtml + '</td>'
1959
- }
1960
- }
1961
- html += '</tr>'
1962
- }
1963
-
1964
- html += '</tbody></table>'
1965
- bodyEl.innerHTML = html
1966
-
1967
- // Bind click-to-filter on filterable cells
1968
- bodyEl.querySelectorAll('.ss-dbg-filterable').forEach((td) => {
1969
- td.style.cursor = 'pointer'
1970
- td.addEventListener('click', () => {
1971
- const val = td.getAttribute('data-ss-filter-val')
1972
- const searchInput = document.getElementById('ss-dbg-search-' + pane.id)
1973
- if (searchInput) {
1974
- searchInput.value = val
1975
- state.filter = val
1976
- renderCustomPane(pane)
1977
- }
1978
- })
1979
- })
1980
- }
1981
-
1982
- // Bind search + clear for each custom pane
1983
- for (let i = 0; i < customPanes.length; i++) {
1984
- const cp = customPanes[i]
1985
- const searchInput = document.getElementById('ss-dbg-search-' + cp.id)
1986
- const clearBtn = document.getElementById('ss-dbg-' + cp.id + '-clear')
1987
-
1988
- if (searchInput) {
1989
- searchInput.addEventListener('input', () => {
1990
- customPaneState[cp.id].filter = searchInput.value
1991
- renderCustomPane(cp)
1992
- })
1993
- }
1994
- if (clearBtn) {
1995
- clearBtn.addEventListener('click', () => {
1996
- customPaneState[cp.id].data = []
1997
- customPaneState[cp.id].fetched = false
1998
- if (searchInput) searchInput.value = ''
1999
- customPaneState[cp.id].filter = ''
2000
- renderCustomPane(cp)
2001
- })
2002
- }
2003
- }
2004
-
2005
- // ── Connection mode indicator ──────────────────────────────────
2006
- const POLL_INTERVAL_NORMAL = REFRESH_INTERVAL
2007
- const POLL_INTERVAL_LIVE = 15000 // slow polling as fallback when live
2008
-
2009
- const updateConnectionIndicator = () => {
2010
- const el = document.getElementById('ss-dbg-conn-mode')
2011
- if (!el) return
2012
- if (isLive) {
2013
- el.textContent = 'live'
2014
- el.className = 'ss-dbg-conn-mode ss-dbg-conn-live'
2015
- el.title = 'Connected via Transmit (SSE) — real-time updates'
2016
- } else {
2017
- el.textContent = 'polling'
2018
- el.className = 'ss-dbg-conn-mode ss-dbg-conn-polling'
2019
- el.title = 'Polling every ' + POLL_INTERVAL_NORMAL / 1000 + 's'
2020
- }
2021
- }
2022
-
2023
- // ── Auto-refresh ────────────────────────────────────────────────
2024
- const startRefresh = () => {
2025
- stopRefresh()
2026
- fetchMiniStats()
2027
- const interval = isLive ? POLL_INTERVAL_LIVE : POLL_INTERVAL_NORMAL
2028
- refreshTimer = setInterval(() => {
2029
- if (!isOpen) return
2030
- loadTab(activeTab)
2031
- fetchMiniStats()
2032
- }, interval)
2033
- }
2034
-
2035
- const stopRefresh = () => {
2036
- if (refreshTimer) {
2037
- clearInterval(refreshTimer)
2038
- refreshTimer = null
2039
- }
2040
- }
2041
-
2042
- // ── Transmit (SSE) support ─────────────────────────────────────
2043
- const initTransmit = () => {
2044
- // window.Transmit is set by the inline IIFE injected before this module
2045
- const TransmitClass = typeof window !== 'undefined' && window.Transmit ? window.Transmit : null
2046
-
2047
- if (!TransmitClass) return // Transmit client not available
2048
-
2049
- try {
2050
- const transmit = new TransmitClass({
2051
- baseUrl: window.location.origin,
2052
- onSubscription: () => {
2053
- isLive = true
2054
- updateConnectionIndicator()
2055
- // Restart refresh with slower interval now that we have live updates
2056
- if (isOpen) startRefresh()
2057
- },
2058
- onReconnectFailed: () => {
2059
- isLive = false
2060
- updateConnectionIndicator()
2061
- if (isOpen) startRefresh()
2062
- },
2063
- onSubscribeFailed: () => {
2064
- isLive = false
2065
- updateConnectionIndicator()
2066
- },
2067
- })
2068
-
2069
- transmitSub = transmit.subscription('server-stats/debug')
2070
-
2071
- transmitSub.onMessage((message) => {
2072
- try {
2073
- const event = typeof message === 'string' ? JSON.parse(message) : message
2074
- handleLiveEvent(event)
2075
- } catch {
2076
- /* ignore */
2077
- }
2078
- })
2079
-
2080
- transmitSub.create().catch(() => {
2081
- isLive = false
2082
- updateConnectionIndicator()
2083
- })
2084
- } catch {
2085
- // Transmit init failed — stay on polling
2086
- }
2087
- }
2088
-
2089
- const handleLiveEvent = (event) => {
2090
- if (!isOpen) return
2091
-
2092
- // Backend sends { types: ['query', 'event', ...] }
2093
- const types = event.types || (event.type ? [event.type] : [])
2094
- const tabMap = {
2095
- query: 'queries',
2096
- event: 'events',
2097
- email: 'emails',
2098
- trace: 'timeline',
2099
- }
2100
-
2101
- let shouldRefresh = false
2102
- for (let i = 0; i < types.length; i++) {
2103
- const targetTab = tabMap[types[i]]
2104
- if (targetTab && targetTab === activeTab) {
2105
- shouldRefresh = true
2106
- }
2107
- if (types[i] === 'query') {
2108
- updateBarQueryBadge()
2109
- }
2110
- }
2111
-
2112
- if (shouldRefresh) {
2113
- loadTab(activeTab)
2114
- }
2115
- }
2116
-
2117
- // Initialize Transmit after a short delay to let the page fully load
2118
- setTimeout(initTransmit, 500)
2119
- updateConnectionIndicator()
2120
-
2121
- // ── Stats bar query badge (always visible) ──────────────────────
2122
- const updateBarQueryBadge = () => {
2123
- const el = document.getElementById('ss-b-dbg-queries')
2124
- if (!el) return
2125
-
2126
- fetchJSON(BASE + '/queries')
2127
- .then((data) => {
2128
- const s = data.summary || {}
2129
- const valEl = el.querySelector('.ss-value')
2130
- if (valEl) {
2131
- valEl.textContent = (s.total || 0) + ' / ' + (s.avgDuration || 0).toFixed(1) + 'ms'
2132
- valEl.className = 'ss-value ' + (s.slow > 0 ? 'ss-amber' : 'ss-green')
2133
- }
2134
- })
2135
- .catch(() => {})
2136
- }
2137
-
2138
- updateBarQueryBadge()
2139
- setInterval(updateBarQueryBadge, 5000)
2140
- })()
1
+ (function(){"use strict";var ne,N,Ie,J,De,Be,je,Re,ge,be,ye,re={},se=[],Vt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,G=Array.isArray;function U(e,n){for(var r in n)e[r]=n[r];return e}function ve(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function le(e,n,r){var s,i,l,o={};for(l in n)l=="key"?s=n[l]:l=="ref"?i=n[l]:o[l]=n[l];if(arguments.length>2&&(o.children=arguments.length>3?ne.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(l in e.defaultProps)o[l]===void 0&&(o[l]=e.defaultProps[l]);return ie(e,o,s,i,null)}function ie(e,n,r,s,i){var l={type:e,props:n,key:r,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++Ie,__i:-1,__u:0};return i==null&&N.vnode!=null&&N.vnode(l),l}function I(e){return e.children}function H(e,n){this.props=e,this.context=n}function K(e,n){if(n==null)return e.__?K(e.__,e.__i+1):null;for(var r;n<e.__k.length;n++)if((r=e.__k[n])!=null&&r.__e!=null)return r.__e;return typeof e.type=="function"?K(e):null}function Wt(e){if(e.__P&&e.__d){var n=e.__v,r=n.__e,s=[],i=[],l=U({},n);l.__v=n.__v+1,N.vnode&&N.vnode(l),we(e.__P,l,n,e.__n,e.__P.namespaceURI,32&n.__u?[r]:null,s,r??K(n),!!(32&n.__u),i),l.__v=n.__v,l.__.__k[l.__i]=l,qe(s,l,i),n.__e=n.__=null,l.__e!=r&&Fe(l)}}function Fe(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(n){if(n!=null&&n.__e!=null)return e.__e=e.__c.base=n.__e}),Fe(e)}function Ue(e){(!e.__d&&(e.__d=!0)&&J.push(e)&&!ae.__r++||De!=N.debounceRendering)&&((De=N.debounceRendering)||Be)(ae)}function ae(){for(var e,n=1;J.length;)J.length>n&&J.sort(je),e=J.shift(),n=J.length,Wt(e);ae.__r=0}function He(e,n,r,s,i,l,o,h,c,a,p){var d,u,f,_,m,y,b,g=s&&s.__k||se,k=n.length;for(c=qt(r,n,g,c,k),d=0;d<k;d++)(f=r.__k[d])!=null&&(u=f.__i!=-1&&g[f.__i]||re,f.__i=d,y=we(e,f,u,i,l,o,h,c,a,p),_=f.__e,f.ref&&u.ref!=f.ref&&(u.ref&&xe(u.ref,null,f),p.push(f.ref,f.__c||_,f)),m==null&&_!=null&&(m=_),(b=!!(4&f.__u))||u.__k===f.__k?c=ze(f,c,e,b):typeof f.type=="function"&&y!==void 0?c=y:_&&(c=_.nextSibling),f.__u&=-7);return r.__e=m,c}function qt(e,n,r,s,i){var l,o,h,c,a,p=r.length,d=p,u=0;for(e.__k=new Array(i),l=0;l<i;l++)(o=n[l])!=null&&typeof o!="boolean"&&typeof o!="function"?(typeof o=="string"||typeof o=="number"||typeof o=="bigint"||o.constructor==String?o=e.__k[l]=ie(null,o,null,null,null):G(o)?o=e.__k[l]=ie(I,{children:o},null,null,null):o.constructor===void 0&&o.__b>0?o=e.__k[l]=ie(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):e.__k[l]=o,c=l+u,o.__=e,o.__b=e.__b+1,h=null,(a=o.__i=Jt(o,r,c,d))!=-1&&(d--,(h=r[a])&&(h.__u|=2)),h==null||h.__v==null?(a==-1&&(i>p?u--:i<p&&u++),typeof o.type!="function"&&(o.__u|=4)):a!=c&&(a==c-1?u--:a==c+1?u++:(a>c?u--:u++,o.__u|=4))):e.__k[l]=null;if(d)for(l=0;l<p;l++)(h=r[l])!=null&&(2&h.__u)==0&&(h.__e==s&&(s=K(h)),Ke(h,h));return s}function ze(e,n,r,s){var i,l;if(typeof e.type=="function"){for(i=e.__k,l=0;i&&l<i.length;l++)i[l]&&(i[l].__=e,n=ze(i[l],n,r,s));return n}e.__e!=n&&(s&&(n&&e.type&&!n.parentNode&&(n=K(e)),r.insertBefore(e.__e,n||null)),n=e.__e);do n=n&&n.nextSibling;while(n!=null&&n.nodeType==8);return n}function oe(e,n){return n=n||[],e==null||typeof e=="boolean"||(G(e)?e.some(function(r){oe(r,n)}):n.push(e)),n}function Jt(e,n,r,s){var i,l,o,h=e.key,c=e.type,a=n[r],p=a!=null&&(2&a.__u)==0;if(a===null&&h==null||p&&h==a.key&&c==a.type)return r;if(s>(p?1:0)){for(i=r-1,l=r+1;i>=0||l<n.length;)if((a=n[o=i>=0?i--:l++])!=null&&(2&a.__u)==0&&h==a.key&&c==a.type)return o}return-1}function Ve(e,n,r){n[0]=="-"?e.setProperty(n,r??""):e[n]=r==null?"":typeof r!="number"||Vt.test(n)?r:r+"px"}function ce(e,n,r,s,i){var l,o;e:if(n=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof s=="string"&&(e.style.cssText=s=""),s)for(n in s)r&&n in r||Ve(e.style,n,"");if(r)for(n in r)s&&r[n]==s[n]||Ve(e.style,n,r[n])}else if(n[0]=="o"&&n[1]=="n")l=n!=(n=n.replace(Re,"$1")),o=n.toLowerCase(),n=o in e||n=="onFocusOut"||n=="onFocusIn"?o.slice(2):n.slice(2),e.l||(e.l={}),e.l[n+l]=r,r?s?r.u=s.u:(r.u=ge,e.addEventListener(n,l?ye:be,l)):e.removeEventListener(n,l?ye:be,l);else{if(i=="http://www.w3.org/2000/svg")n=n.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(n!="width"&&n!="height"&&n!="href"&&n!="list"&&n!="form"&&n!="tabIndex"&&n!="download"&&n!="rowSpan"&&n!="colSpan"&&n!="role"&&n!="popover"&&n in e)try{e[n]=r??"";break e}catch{}typeof r=="function"||(r==null||r===!1&&n[4]!="-"?e.removeAttribute(n):e.setAttribute(n,n=="popover"&&r==1?"":r))}}function We(e){return function(n){if(this.l){var r=this.l[n.type+e];if(n.t==null)n.t=ge++;else if(n.t<r.u)return;return r(N.event?N.event(n):n)}}}function we(e,n,r,s,i,l,o,h,c,a){var p,d,u,f,_,m,y,b,g,k,C,v,w,P,$,M=n.type;if(n.constructor!==void 0)return null;128&r.__u&&(c=!!(32&r.__u),l=[h=n.__e=r.__e]),(p=N.__b)&&p(n);e:if(typeof M=="function")try{if(b=n.props,g="prototype"in M&&M.prototype.render,k=(p=M.contextType)&&s[p.__c],C=p?k?k.props.value:p.__:s,r.__c?y=(d=n.__c=r.__c).__=d.__E:(g?n.__c=d=new M(b,C):(n.__c=d=new H(b,C),d.constructor=M,d.render=Qt),k&&k.sub(d),d.state||(d.state={}),d.__n=s,u=d.__d=!0,d.__h=[],d._sb=[]),g&&d.__s==null&&(d.__s=d.state),g&&M.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=U({},d.__s)),U(d.__s,M.getDerivedStateFromProps(b,d.__s))),f=d.props,_=d.state,d.__v=n,u)g&&M.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),g&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(g&&M.getDerivedStateFromProps==null&&b!==f&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps(b,C),n.__v==r.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate(b,d.__s,C)===!1){n.__v!=r.__v&&(d.props=b,d.state=d.__s,d.__d=!1),n.__e=r.__e,n.__k=r.__k,n.__k.some(function(q){q&&(q.__=n)}),se.push.apply(d.__h,d._sb),d._sb=[],d.__h.length&&o.push(d);break e}d.componentWillUpdate!=null&&d.componentWillUpdate(b,d.__s,C),g&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(f,_,m)})}if(d.context=C,d.props=b,d.__P=e,d.__e=!1,v=N.__r,w=0,g)d.state=d.__s,d.__d=!1,v&&v(n),p=d.render(d.props,d.state,d.context),se.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,v&&v(n),p=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++w<25);d.state=d.__s,d.getChildContext!=null&&(s=U(U({},s),d.getChildContext())),g&&!u&&d.getSnapshotBeforeUpdate!=null&&(m=d.getSnapshotBeforeUpdate(f,_)),P=p!=null&&p.type===I&&p.key==null?Je(p.props.children):p,h=He(e,G(P)?P:[P],n,r,s,i,l,o,h,c,a),d.base=n.__e,n.__u&=-161,d.__h.length&&o.push(d),y&&(d.__E=d.__=null)}catch(q){if(n.__v=null,c||l!=null)if(q.then){for(n.__u|=c?160:128;h&&h.nodeType==8&&h.nextSibling;)h=h.nextSibling;l[l.indexOf(h)]=null,n.__e=h}else{for($=l.length;$--;)ve(l[$]);Ne(n)}else n.__e=r.__e,n.__k=r.__k,q.then||Ne(n);N.__e(q,n,r)}else l==null&&n.__v==r.__v?(n.__k=r.__k,n.__e=r.__e):h=n.__e=Kt(r.__e,n,r,s,i,l,o,c,a);return(p=N.diffed)&&p(n),128&n.__u?void 0:h}function Ne(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(Ne))}function qe(e,n,r){for(var s=0;s<r.length;s++)xe(r[s],r[++s],r[++s]);N.__c&&N.__c(n,e),e.some(function(i){try{e=i.__h,i.__h=[],e.some(function(l){l.call(i)})}catch(l){N.__e(l,i.__v)}})}function Je(e){return typeof e!="object"||e==null||e.__b>0?e:G(e)?e.map(Je):U({},e)}function Kt(e,n,r,s,i,l,o,h,c){var a,p,d,u,f,_,m,y=r.props||re,b=n.props,g=n.type;if(g=="svg"?i="http://www.w3.org/2000/svg":g=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),l!=null){for(a=0;a<l.length;a++)if((f=l[a])&&"setAttribute"in f==!!g&&(g?f.localName==g:f.nodeType==3)){e=f,l[a]=null;break}}if(e==null){if(g==null)return document.createTextNode(b);e=document.createElementNS(i,g,b.is&&b),h&&(N.__m&&N.__m(n,l),h=!1),l=null}if(g==null)y===b||h&&e.data==b||(e.data=b);else{if(l=l&&ne.call(e.childNodes),!h&&l!=null)for(y={},a=0;a<e.attributes.length;a++)y[(f=e.attributes[a]).name]=f.value;for(a in y)f=y[a],a=="dangerouslySetInnerHTML"?d=f:a=="children"||a in b||a=="value"&&"defaultValue"in b||a=="checked"&&"defaultChecked"in b||ce(e,a,null,f,i);for(a in b)f=b[a],a=="children"?u=f:a=="dangerouslySetInnerHTML"?p=f:a=="value"?_=f:a=="checked"?m=f:h&&typeof f!="function"||y[a]===f||ce(e,a,f,y[a],i);if(p)h||d&&(p.__html==d.__html||p.__html==e.innerHTML)||(e.innerHTML=p.__html),n.__k=[];else if(d&&(e.innerHTML=""),He(n.type=="template"?e.content:e,G(u)?u:[u],n,r,s,g=="foreignObject"?"http://www.w3.org/1999/xhtml":i,l,o,l?l[0]:r.__k&&K(r,0),h,c),l!=null)for(a=l.length;a--;)ve(l[a]);h||(a="value",g=="progress"&&_==null?e.removeAttribute("value"):_!=null&&(_!==e[a]||g=="progress"&&!_||g=="option"&&_!=y[a])&&ce(e,a,_,y[a],i),a="checked",m!=null&&m!=e[a]&&ce(e,a,m,y[a],i))}return e}function xe(e,n,r){try{if(typeof e=="function"){var s=typeof e.__u=="function";s&&e.__u(),s&&n==null||(e.__u=e(n))}else e.current=n}catch(i){N.__e(i,r)}}function Ke(e,n,r){var s,i;if(N.unmount&&N.unmount(e),(s=e.ref)&&(s.current&&s.current!=e.__e||xe(s,null,n)),(s=e.__c)!=null){if(s.componentWillUnmount)try{s.componentWillUnmount()}catch(l){N.__e(l,n)}s.base=s.__P=null}if(s=e.__k)for(i=0;i<s.length;i++)s[i]&&Ke(s[i],n,r||typeof e.type!="function");r||ve(e.__e),e.__c=e.__=e.__e=void 0}function Qt(e,n,r){return this.constructor(e,r)}function Gt(e,n,r){var s,i,l,o;n==document&&(n=document.documentElement),N.__&&N.__(e,n),i=(s=!1)?null:n.__k,l=[],o=[],we(n,e=n.__k=le(I,null,[e]),i||re,re,n.namespaceURI,i?null:n.firstChild?ne.call(n.childNodes):null,l,i?i.__e:n.firstChild,s,o),qe(l,e,o)}ne=se.slice,N={__e:function(e,n,r,s){for(var i,l,o;n=n.__;)if((i=n.__c)&&!i.__)try{if((l=i.constructor)&&l.getDerivedStateFromError!=null&&(i.setState(l.getDerivedStateFromError(e)),o=i.__d),i.componentDidCatch!=null&&(i.componentDidCatch(e,s||{}),o=i.__d),o)return i.__E=i}catch(h){e=h}throw e}},Ie=0,H.prototype.setState=function(e,n){var r;r=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=U({},this.state),typeof e=="function"&&(e=e(U({},r),this.props)),e&&U(r,e),e!=null&&this.__v&&(n&&this._sb.push(n),Ue(this))},H.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Ue(this))},H.prototype.render=I,J=[],Be=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,je=function(e,n){return e.__v.__b-n.__v.__b},ae.__r=0,Re=/(PointerCapture)$|Capture$/i,ge=0,be=We(!1),ye=We(!0);var Xt=0;function t(e,n,r,s,i,l){n||(n={});var o,h,c=n;if("ref"in c)for(h in c={},n)h=="ref"?o=n[h]:c[h]=n[h];var a={type:e,props:c,key:r,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--Xt,__i:-1,__u:0,__source:i,__self:l};if(typeof e=="function"&&(o=e.defaultProps))for(h in o)c[h]===void 0&&(c[h]=o[h]);return N.vnode&&N.vnode(a),a}var X,L,$e,Qe,Y=0,Ge=[],E=N,Xe=E.__b,Ye=E.__r,Ze=E.diffed,et=E.__c,tt=E.unmount,nt=E.__;function ke(e,n){E.__h&&E.__h(L,e,Y||n),Y=0;var r=L.__H||(L.__H={__:[],__h:[]});return e>=r.__.length&&r.__.push({}),r.__[e]}function x(e){return Y=1,Yt(lt,e)}function Yt(e,n,r){var s=ke(X++,2);if(s.t=e,!s.__c&&(s.__=[r?r(n):lt(void 0,n),function(h){var c=s.__N?s.__N[0]:s.__[0],a=s.t(c,h);c!==a&&(s.__N=[a,s.__[1]],s.__c.setState({}))}],s.__c=L,!L.__f)){var i=function(h,c,a){if(!s.__c.__H)return!0;var p=s.__c.__H.__.filter(function(u){return u.__c});if(p.every(function(u){return!u.__N}))return!l||l.call(this,h,c,a);var d=s.__c.props!==h;return p.some(function(u){if(u.__N){var f=u.__[0];u.__=u.__N,u.__N=void 0,f!==u.__[0]&&(d=!0)}}),l&&l.call(this,h,c,a)||d};L.__f=!0;var l=L.shouldComponentUpdate,o=L.componentWillUpdate;L.componentWillUpdate=function(h,c,a){if(this.__e){var p=l;l=void 0,i(h,c,a),l=p}o&&o.call(this,h,c,a)},L.shouldComponentUpdate=i}return s.__N||s.__}function z(e,n){var r=ke(X++,3);!E.__s&&st(r.__H,n)&&(r.__=e,r.u=n,L.__H.__h.push(r))}function B(e){return Y=5,T(function(){return{current:e}},[])}function T(e,n){var r=ke(X++,7);return st(r.__H,n)&&(r.__=e(),r.__H=n,r.__h=e),r.__}function S(e,n){return Y=8,T(function(){return e},n)}function Zt(){for(var e;e=Ge.shift();){var n=e.__H;if(e.__P&&n)try{n.__h.some(de),n.__h.some(Ce),n.__h=[]}catch(r){n.__h=[],E.__e(r,e.__v)}}}E.__b=function(e){L=null,Xe&&Xe(e)},E.__=function(e,n){e&&n.__k&&n.__k.__m&&(e.__m=n.__k.__m),nt&&nt(e,n)},E.__r=function(e){Ye&&Ye(e),X=0;var n=(L=e.__c).__H;n&&($e===L?(n.__h=[],L.__h=[],n.__.some(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(n.__h.some(de),n.__h.some(Ce),n.__h=[],X=0)),$e=L},E.diffed=function(e){Ze&&Ze(e);var n=e.__c;n&&n.__H&&(n.__H.__h.length&&(Ge.push(n)!==1&&Qe===E.requestAnimationFrame||((Qe=E.requestAnimationFrame)||en)(Zt)),n.__H.__.some(function(r){r.u&&(r.__H=r.u),r.u=void 0})),$e=L=null},E.__c=function(e,n){n.some(function(r){try{r.__h.some(de),r.__h=r.__h.filter(function(s){return!s.__||Ce(s)})}catch(s){n.some(function(i){i.__h&&(i.__h=[])}),n=[],E.__e(s,r.__v)}}),et&&et(e,n)},E.unmount=function(e){tt&&tt(e);var n,r=e.__c;r&&r.__H&&(r.__H.__.some(function(s){try{de(s)}catch(i){n=i}}),r.__H=void 0,n&&E.__e(n,r.__v))};var rt=typeof requestAnimationFrame=="function";function en(e){var n,r=function(){clearTimeout(s),rt&&cancelAnimationFrame(n),setTimeout(e)},s=setTimeout(r,35);rt&&(n=requestAnimationFrame(r))}function de(e){var n=L,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),L=n}function Ce(e){var n=L;e.__c=e.__(),L=n}function st(e,n){return!e||e.length!==n.length||n.some(function(r,s){return r!==e[s]})}function lt(e,n){return typeof n=="function"?n(e):n}function tn(e,n){for(var r in n)e[r]=n[r];return e}function it(e,n){for(var r in e)if(r!=="__source"&&!(r in n))return!0;for(var s in n)if(s!=="__source"&&e[s]!==n[s])return!0;return!1}function at(e,n){this.props=e,this.context=n}(at.prototype=new H).isPureReactComponent=!0,at.prototype.shouldComponentUpdate=function(e,n){return it(this.props,e)||it(this.state,n)};var ot=N.__b;N.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),ot&&ot(e)};var nn=N.__e;N.__e=function(e,n,r,s){if(e.then){for(var i,l=n;l=l.__;)if((i=l.__c)&&i.__c)return n.__e==null&&(n.__e=r.__e,n.__k=r.__k),i.__c(e,n)}nn(e,n,r,s)};var ct=N.unmount;function dt(e,n,r){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(s){typeof s.__c=="function"&&s.__c()}),e.__c.__H=null),(e=tn({},e)).__c!=null&&(e.__c.__P===r&&(e.__c.__P=n),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(s){return dt(s,n,r)})),e}function ht(e,n,r){return e&&r&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(s){return ht(s,n,r)}),e.__c&&e.__c.__P===n&&(e.__e&&r.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=r)),e}function Z(){this.__u=0,this.o=null,this.__b=null}function ut(e){if(!e.__)return null;var n=e.__.__c;return n&&n.__a&&n.__a(e)}function D(e){var n,r,s,i=null;function l(o){if(n||(n=e()).then(function(h){h&&(i=h.default||h),s=!0},function(h){r=h,s=!0}),r)throw r;if(!s)throw n;return i?le(i,o):null}return l.displayName="Lazy",l.__f=!0,l}function he(){this.i=null,this.l=null}N.unmount=function(e){var n=e.__c;n&&(n.__z=!0),n&&n.__R&&n.__R(),n&&32&e.__u&&(e.type=null),ct&&ct(e)},(Z.prototype=new H).__c=function(e,n){var r=n.__c,s=this;s.o==null&&(s.o=[]),s.o.push(r);var i=ut(s.__v),l=!1,o=function(){l||s.__z||(l=!0,r.__R=null,i?i(c):c())};r.__R=o;var h=r.__P;r.__P=null;var c=function(){if(!--s.__u){if(s.state.__a){var a=s.state.__a;s.__v.__k[0]=ht(a,a.__c.__P,a.__c.__O)}var p;for(s.setState({__a:s.__b=null});p=s.o.pop();)p.__P=h,p.forceUpdate()}};s.__u++||32&n.__u||s.setState({__a:s.__b=s.__v.__k[0]}),e.then(o,o)},Z.prototype.componentWillUnmount=function(){this.o=[]},Z.prototype.render=function(e,n){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),s=this.__v.__k[0].__c;this.__v.__k[0]=dt(this.__b,r,s.__O=s.__P)}this.__b=null}var i=n.__a&&le(I,null,e.fallback);return i&&(i.__u&=-33),[le(I,null,n.__a?null:e.children),i]};var ft=function(e,n,r){if(++r[1]===r[0]&&e.l.delete(n),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.l.size))for(r=e.i;r;){for(;r.length>3;)r.pop()();if(r[1]<r[0])break;e.i=r=r[2]}};(he.prototype=new H).__a=function(e){var n=this,r=ut(n.__v),s=n.l.get(e);return s[0]++,function(i){var l=function(){n.props.revealOrder?(s.push(i),ft(n,e,s)):i()};r?r(l):l()}},he.prototype.render=function(e){this.i=null,this.l=new Map;var n=oe(e.children);e.revealOrder&&e.revealOrder[0]==="b"&&n.reverse();for(var r=n.length;r--;)this.l.set(n[r],this.i=[1,0,this.i]);return e.children},he.prototype.componentDidUpdate=he.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(n,r){ft(e,r,n)})};var rn=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,sn=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,ln=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,an=/[A-Z0-9]/g,on=typeof document<"u",cn=function(e){return(typeof Symbol<"u"&&typeof Symbol()=="symbol"?/fil|che|rad/:/fil|che|ra/).test(e)};H.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(H.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(n){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:n})}})});var pt=N.event;function dn(){}function hn(){return this.cancelBubble}function un(){return this.defaultPrevented}N.event=function(e){return pt&&(e=pt(e)),e.persist=dn,e.isPropagationStopped=hn,e.isDefaultPrevented=un,e.nativeEvent=e};var fn={enumerable:!1,configurable:!0,get:function(){return this.class}},_t=N.vnode;N.vnode=function(e){typeof e.type=="string"&&(function(n){var r=n.props,s=n.type,i={},l=s.indexOf("-")===-1;for(var o in r){var h=r[o];if(!(o==="value"&&"defaultValue"in r&&h==null||on&&o==="children"&&s==="noscript"||o==="class"||o==="className")){var c=o.toLowerCase();o==="defaultValue"&&"value"in r&&r.value==null?o="value":o==="download"&&h===!0?h="":c==="translate"&&h==="no"?h=!1:c[0]==="o"&&c[1]==="n"?c==="ondoubleclick"?o="ondblclick":c!=="onchange"||s!=="input"&&s!=="textarea"||cn(r.type)?c==="onfocus"?o="onfocusin":c==="onblur"?o="onfocusout":ln.test(o)&&(o=c):c=o="oninput":l&&sn.test(o)?o=o.replace(an,"-$&").toLowerCase():h===null&&(h=void 0),c==="oninput"&&i[o=c]&&(o="oninputCapture"),i[o]=h}}s=="select"&&i.multiple&&Array.isArray(i.value)&&(i.value=oe(r.children).forEach(function(a){a.props.selected=i.value.indexOf(a.props.value)!=-1})),s=="select"&&i.defaultValue!=null&&(i.value=oe(r.children).forEach(function(a){a.props.selected=i.multiple?i.defaultValue.indexOf(a.props.value)!=-1:i.defaultValue==a.props.value})),r.class&&!r.className?(i.class=r.class,Object.defineProperty(i,"className",fn)):r.className&&(i.class=i.className=r.className),n.props=i})(e),e.$$typeof=rn,_t&&_t(e)};var mt=N.__r;N.__r=function(e){mt&&mt(e),e.__c};var gt=N.diffed;N.diffed=function(e){gt&&gt(e);var n=e.props,r=e.__e;r!=null&&e.type==="textarea"&&"value"in n&&n.value!==r.value&&(r.value=n.value==null?"":n.value)};const A={queries:{viewBox:"0 0 24 24",elements:['<ellipse cx="12" cy="5" rx="9" ry="3"/>','<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>','<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>']},events:{viewBox:"0 0 24 24",elements:['<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>']},emails:{viewBox:"0 0 24 24",elements:['<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>','<polyline points="22,6 12,13 2,6"/>']},routes:{viewBox:"0 0 24 24",elements:['<circle cx="12" cy="12" r="10"/>','<line x1="2" y1="12" x2="22" y2="12"/>','<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>']},logs:{viewBox:"0 0 24 24",elements:['<line x1="8" y1="6" x2="21" y2="6"/>','<line x1="8" y1="12" x2="21" y2="12"/>','<line x1="8" y1="18" x2="21" y2="18"/>','<line x1="3" y1="6" x2="3.01" y2="6"/>','<line x1="3" y1="12" x2="3.01" y2="12"/>','<line x1="3" y1="18" x2="3.01" y2="18"/>']},timeline:{viewBox:"0 0 24 24",elements:['<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>']},cache:{viewBox:"0 0 24 24",elements:['<rect x="2" y="2" width="20" height="8" rx="2" ry="2"/>','<rect x="2" y="14" width="20" height="8" rx="2" ry="2"/>','<line x1="6" y1="6" x2="6.01" y2="6"/>','<line x1="6" y1="18" x2="6.01" y2="18"/>']},jobs:{viewBox:"0 0 24 24",elements:['<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/>','<path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>']},config:{viewBox:"0 0 24 24",elements:['<circle cx="12" cy="12" r="3"/>','<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>']},internals:{viewBox:"0 0 24 24",elements:['<rect x="4" y="4" width="16" height="16" rx="2"/>','<rect x="9" y="9" width="6" height="6"/>','<line x1="9" y1="1" x2="9" y2="4"/>','<line x1="15" y1="1" x2="15" y2="4"/>','<line x1="9" y1="20" x2="9" y2="23"/>','<line x1="15" y1="20" x2="15" y2="23"/>','<line x1="20" y1="9" x2="23" y2="9"/>','<line x1="20" y1="14" x2="23" y2="14"/>','<line x1="1" y1="9" x2="4" y2="9"/>','<line x1="1" y1="14" x2="4" y2="14"/>']},overview:{viewBox:"0 0 24 24",elements:['<rect x="3" y="3" width="7" height="7"/>','<rect x="14" y="3" width="7" height="7"/>','<rect x="14" y="14" width="7" height="7"/>','<rect x="3" y="14" width="7" height="7"/>']},requests:{viewBox:"0 0 24 24",elements:['<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>']},"dashboard-timeline":{viewBox:"0 0 24 24",elements:['<circle cx="12" cy="12" r="10"/>','<polyline points="12 6 12 12 16 14"/>']},"custom-pane":{viewBox:"0 0 24 24",elements:['<rect x="3" y="3" width="18" height="18" rx="2"/>','<path d="M9 3v18"/>']},wrench:{viewBox:"0 0 24 24",elements:['<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>']},"external-link":{viewBox:"0 0 24 24",elements:['<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>','<polyline points="15 3 21 3 21 9"/>','<line x1="10" y1="14" x2="21" y2="3"/>']},sun:{viewBox:"0 0 24 24",elements:['<circle cx="12" cy="12" r="5"/>','<line x1="12" y1="1" x2="12" y2="3"/>','<line x1="12" y1="21" x2="12" y2="23"/>','<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>','<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>','<line x1="1" y1="12" x2="3" y2="12"/>','<line x1="21" y1="12" x2="23" y2="12"/>','<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>','<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>']},moon:{viewBox:"0 0 24 24",elements:['<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>']},search:{viewBox:"0 0 24 24",elements:['<circle cx="11" cy="11" r="8"/>','<line x1="21" y1="21" x2="16.65" y2="16.65"/>']},eye:{viewBox:"0 0 24 24",elements:['<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>','<circle cx="12" cy="12" r="3"/>']},"eye-off":{viewBox:"0 0 24 24",elements:['<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>','<path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>','<line x1="1" y1="1" x2="23" y2="23"/>','<path d="M14.12 14.12a3 3 0 1 1-4.24-4.24"/>']},"chevron-right":{viewBox:"0 0 24 24",elements:['<path d="M9 18l6-6-6-6"/>']},"chevron-left":{viewBox:"0 0 24 24",elements:['<path d="M15 18l-6-6 6-6"/>']},"open-external":{viewBox:"0 0 16 16",elements:['<path d="M6 3H3v10h10v-3M9 1h6v6M7 9L15 1"/>']}};class ue extends Error{status;constructor(n=403){super(`Unauthorized (HTTP ${n})`),this.name="UnauthorizedError",this.status=n}}class pn extends Error{status;body;constructor(n,r){super(`API error (HTTP ${n})`),this.name="ApiError",this.status=n,this.body=r}}class Se{baseUrl;authToken;constructor(n){this.baseUrl=n.baseUrl.replace(/\/+$/,""),this.authToken=n.authToken}async fetch(n,r){const i={...{Accept:"application/json",...this.authToken?{Authorization:`Bearer ${this.authToken}`}:{}},...r?.headers},l=await globalThis.fetch(`${this.baseUrl}${n}`,{...r,headers:i,credentials:this.authToken?"omit":"include"});if(l.status===401||l.status===403)throw new ue(l.status);if(!l.ok){const o=await l.text().catch(()=>"");throw new pn(l.status,o)}return l.json()}async get(n,r){const s=r?`${n}?${r}`:n;return this.fetch(s)}async post(n,r){const s={method:"POST",...r!==void 0?{body:JSON.stringify(r),headers:{"Content-Type":"application/json"}}:{}};return this.fetch(n,s)}async delete(n){return this.fetch(n,{method:"DELETE"})}}const bt="/admin/api/debug",yt={tracing:!1,process:!1,system:!1,http:!1,db:!1,redis:!1,queues:!1,cache:!1,app:!1,log:!1,emails:!1,dashboard:!1,customPanes:[]};function _n(e){return{tracing:e.features?.tracing??!1,process:e.features?.process??!1,system:e.features?.system??!1,http:e.features?.http??!1,db:e.features?.db??!1,redis:e.features?.redis??!1,queues:e.features?.queues??!1,cache:e.features?.cache??!1,app:e.features?.app??!1,log:e.features?.log??!1,emails:e.features?.emails??!1,dashboard:e.features?.dashboard??!1,customPanes:e.customPanes??[]}}async function mn(e,n=bt){const r=`${n.replace(/\/+$/,"")}/config`;return e.fetch(r)}async function gn(e){const{baseUrl:n="",debugEndpoint:r=bt,authToken:s}=e,i=new Se({baseUrl:n,authToken:s});try{const l=await mn(i,r);return _n(l)}catch{return yt}}function bn(e={}){const{baseUrl:n="",debugEndpoint:r="/admin/api/debug",authToken:s}=e,[i,l]=x(yt),[o,h]=x(!0),[c,a]=x(null),p=B(!1);return z(()=>{if(p.current)return;p.current=!0;let d=!1;return(async()=>{try{const f=await gn({baseUrl:n,debugEndpoint:r,authToken:s});d||(l(f),h(!1))}catch(f){d||(a(f instanceof Error?f:new Error(String(f))),h(!1))}})(),()=>{d=!0}},[n,r,s]),{features:i,isLoading:o,error:c}}const fe="ss-dash-theme",Te="ss-theme-change";function Le(){if(typeof window>"u")return"light";const e=localStorage.getItem(fe);return e==="dark"||e==="light"?e:window.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}function yn(e){typeof window>"u"||(localStorage.setItem(fe,e),window.dispatchEvent(new CustomEvent(Te,{detail:e})))}function vn(){const n=Le()==="dark"?"light":"dark";return yn(n),n}function wn(e){if(typeof window>"u")return()=>{};const n=l=>{const o=l.detail;(o==="dark"||o==="light")&&e(o)},r=l=>{if(l.key===fe){const o=l.newValue;e(o==="dark"||o==="light"?o:Le())}},s=window.matchMedia("(prefers-color-scheme: dark)"),i=l=>{localStorage.getItem(fe)||e(l.matches?"dark":"light")};return window.addEventListener(Te,n),window.addEventListener("storage",r),s.addEventListener("change",i),()=>{window.removeEventListener(Te,n),window.removeEventListener("storage",r),s.removeEventListener("change",i)}}function Nn(){const[e,n]=x(()=>Le());z(()=>wn(i=>{n(i)}),[]);const r=S(()=>{const s=vn();return n(s),s},[]);return{theme:e,toggleTheme:r}}function xn({theme:e,onToggle:n,className:r="",classPrefix:s="ss-dash"}){const i=e==="dark";return t("button",{type:"button",className:`${s==="ss-dbg"?"ss-dbg-theme-toggle":"ss-dash-theme-btn"} ${r}`,onClick:n,title:i?"Switch to light theme":"Switch to dark theme","aria-label":i?"Switch to light theme":"Switch to dark theme",children:i?t("svg",{width:"16",height:"16",viewBox:A.sun.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A.sun.elements.join("")}}):t("svg",{width:"16",height:"16",viewBox:A.moon.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A.moon.elements.join("")}})})}const $n=D(()=>Promise.resolve().then(()=>Gn)),kn=D(()=>Promise.resolve().then(()=>Xn)),Cn=D(()=>Promise.resolve().then(()=>Yn)),Sn=D(()=>Promise.resolve().then(()=>Zn)),Tn=D(()=>Promise.resolve().then(()=>sr)),Ln=D(()=>Promise.resolve().then(()=>ir)),En=D(()=>Promise.resolve().then(()=>ar)),An=D(()=>Promise.resolve().then(()=>ur)),Pn=D(()=>Promise.resolve().then(()=>vr)),Mn=D(()=>Promise.resolve().then(()=>Or)),On=D(()=>Promise.resolve().then(()=>Ir));function In(e){const{defaultOpen:n=!1,dashboardPath:r,isOpen:s,onOpenChange:i,isLive:l=!1,...o}=e,[h,c]=x(n),a=s!==void 0?s:h,p=v=>{i?i(v):c(v)},[d,u]=x("queries"),{features:f}=bn(o),{theme:_,toggleTheme:m}=Nn(),y=f.customPanes||[];z(()=>{const v=w=>{w.key==="Escape"&&a&&p(!1)};return document.addEventListener("keydown",v),()=>document.removeEventListener("keydown",v)},[a]);const b=T(()=>[{id:"queries",label:"Queries",visible:!0},{id:"events",label:"Events",visible:!0},{id:"emails",label:"Emails",visible:!0},{id:"routes",label:"Routes",visible:!0},{id:"logs",label:"Logs",visible:!0},{id:"timeline",label:"Timeline",visible:f.tracing},{id:"cache",label:"Cache",visible:f.cache},{id:"jobs",label:"Jobs",visible:f.queues},{id:"config",label:"Config",visible:!0},{id:"internals",label:"Internals",visible:!0}],[f]),g=T(()=>b.filter(v=>v.visible),[b]);z(()=>{const v=[...g.map(w=>w.id),...y.map(w=>w.id)];!v.includes(d)&&v.length>0&&u(v[0])},[g,y,d]);const k=S(()=>{p(!a)},[a]),C=S(()=>{const v={options:o},w=y.find($=>$.id===d);if(w)return t(Z,{fallback:t("div",{className:"ss-dbg-empty",children:"Loading..."}),children:t(On,{pane:w,options:o})});const P={queries:t($n,{...v}),events:t(kn,{...v}),emails:t(Cn,{...v}),routes:t(Sn,{...v,currentPath:typeof window<"u"?window.location.pathname:""}),logs:t(Tn,{...v}),timeline:t(Ln,{...v}),cache:t(En,{...v,dashboardPath:r}),jobs:t(An,{...v,dashboardPath:r}),config:t(Pn,{...v,dashboardPath:r}),internals:t(Mn,{...v})};return t(Z,{fallback:t("div",{className:"ss-dbg-empty",children:"Loading..."}),children:P[d]||t("div",{className:"ss-dbg-empty",children:"Unknown tab"})})},[d,o,y]);return t(I,{children:[s===void 0&&t("button",{type:"button",className:`ss-dbg-btn ${a?"ss-dbg-active":""}`,onClick:k,title:"Toggle debug panel",id:"ss-dbg-wrench",children:t("svg",{width:"14",height:"14",viewBox:A.wrench.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A.wrench.elements.join("")}})}),t("div",{className:`ss-dbg-panel ${a?"ss-dbg-open":""}`,"data-ss-theme":_,id:"ss-dbg-panel",children:[t("div",{className:"ss-dbg-tabs",children:[t("div",{className:"ss-dbg-tabs-scroll",children:[g.map(v=>t("button",{type:"button",className:`ss-dbg-tab ${d===v.id?"ss-dbg-active":""}`,onClick:()=>u(v.id),children:[A[v.id]?t("svg",{className:"ss-dbg-tab-icon",viewBox:A[v.id].viewBox,dangerouslySetInnerHTML:{__html:A[v.id].elements.join("")}}):null,v.label]},v.id)),y.map(v=>t("button",{type:"button",className:`ss-dbg-tab ${d===v.id?"ss-dbg-active":""}`,onClick:()=>u(v.id),children:v.label},v.id))]}),t("div",{className:"ss-dbg-tabs-right",children:[t("span",{className:`ss-dbg-conn-mode ${l?"ss-dbg-conn-live":"ss-dbg-conn-polling"}`,title:l?"Connected via Transmit (SSE) — real-time updates":"Polling every 3s",children:l?"live":"polling"}),t(xn,{theme:_,onToggle:m,classPrefix:"ss-dbg"}),r&&t("a",{href:r,target:"_blank",rel:"noopener noreferrer",className:"ss-dbg-dashboard-link",title:"Open dashboard",children:t("svg",{width:"14",height:"14",viewBox:A["external-link"].viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A["external-link"].elements.join("")}})}),t("button",{type:"button",className:"ss-dbg-close",onClick:()=>p(!1),title:"Close panel",children:"×"})]})]}),t("div",{className:"ss-dbg-content",children:a&&C()})]})]})}function Dn(e){const n=document.getElementById(e);return n?JSON.parse(n.textContent||"{}"):{}}const Ee=Dn("ss-dbg-config"),vt=document.getElementById("ss-dbg-panel");vt&&Gt(t(In,{debugEndpoint:Ee.debugEndpoint,authToken:Ee.authToken,dashboardPath:Ee.dashboardPath||void 0,defaultOpen:!1}),vt);const Bn=3e3,jn=100,Rn=500;function Fn(e){if(!e&&e!==0)return"-";const n=Math.floor(e),r=Math.floor(n/86400),s=Math.floor(n%86400/3600),i=Math.floor(n%3600/60);return r>0?`${r}d ${s}h`:s>0?`${s}h ${i}m`:i>0?`${i}m ${n%60}s`:`${n}s`}function j(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:e>=1?`${e.toFixed(0)}ms`:`${e.toFixed(2)}ms`}function V(e){if(!e)return"-";const n=typeof e=="string"?new Date(e):new Date(e);return Number.isNaN(n.getTime())?"-":n.toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})+"."+String(n.getMilliseconds()).padStart(3,"0")}function R(e){if(!e)return"-";const n=typeof e=="string"?new Date(e).getTime():e,r=Math.floor((Date.now()-n)/1e3);return r<0?"just now":r<60?`${r}s ago`:r<3600?`${Math.floor(r/60)}m ago`:r<86400?`${Math.floor(r/3600)}h ago`:`${Math.floor(r/86400)}d ago`}function Q(e){return e>Rn?"very-slow":e>jn?"slow":"normal"}function pe(e,n=100){if(e===null)return"null";if(e===void 0)return"-";if(typeof e=="string")return'"'+(e.length>40?e.slice(0,40)+"...":e)+'"';if(typeof e=="number"||typeof e=="boolean")return String(e);if(Array.isArray(e)){if(e.length===0)return"[]";const s="["+e.slice(0,3).map(i=>pe(i,30)).join(", ")+(e.length>3?", ..."+e.length+" items":"")+"]";return s.length>n?"["+e.length+" items]":s}if(typeof e=="object"){const r=Object.keys(e);if(r.length===0)return"{}";const s=[];for(let l=0;l<Math.min(r.length,4);l++)s.push(r[l]+": "+pe(e[r[l]],30));const i="{ "+s.join(", ")+(r.length>4?", ...+"+(r.length-4):"")+" }";return i.length>n?"{ "+r.slice(0,6).join(", ")+(r.length>6?", ...":"")+" }":i}return String(e)}function Un(e){return e<0?"no expiry":e<60?`${e}s`:e<3600?`${Math.floor(e/60)}m`:e<86400?`${Math.floor(e/3600)}h`:`${Math.floor(e/86400)}d`}function Hn(e){return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/(1024*1024)).toFixed(1)}MB`}function zn(e,n){if(!n)return e;const r=n.toLowerCase();return e.filter(s=>s.sql.toLowerCase().includes(r)||s.model&&s.model.toLowerCase().includes(r)||s.method.toLowerCase().includes(r))}function Vn(e){const n={};for(const r of e)n[r.sql]=(n[r.sql]||0)+1;return n}function Wn(e,n){const r=e.filter(l=>l.duration>100).length,s=Object.values(n).filter(l=>l>1).length,i=e.length>0?e.reduce((l,o)=>l+o.duration,0)/e.length:0;return{slowCount:r,dupCount:s,avgDuration:i,totalCount:e.length}}const qn={queries:"/queries",events:"/events",emails:"/emails",routes:"/routes",logs:"/logs",timeline:"/traces",cache:"/cache",jobs:"/jobs",config:"/config",internals:"/diagnostics"};function Jn(e){return qn[e]||`/${e}`}class Kn{client;endpoint;refreshInterval;callbacks;timer=null;currentTab=null;fetchOnceCache={};constructor(n){this.client=new Se({baseUrl:n.baseUrl,authToken:n.authToken}),this.endpoint=n.endpoint??"/admin/api/debug",this.refreshInterval=n.refreshInterval??Bn,this.callbacks={onData:n.onData,onLoading:n.onLoading,onError:n.onError,onUnauthorized:n.onUnauthorized}}start(n){this.stop(),this.currentTab=n,this.callbacks.onLoading(!0),this.callbacks.onError(null),this.fetchData(),this.timer=setInterval(()=>this.fetchData(),this.refreshInterval)}stop(){this.timer&&(clearInterval(this.timer),this.timer=null)}switchTab(n){this.start(n)}refresh(){this.currentTab&&this.fetchData()}async fetchCustomPane(n,r=!1){if(r&&this.fetchOnceCache[n]!==void 0){this.callbacks.onData(this.fetchOnceCache[n]),this.callbacks.onLoading(!1);return}this.callbacks.onLoading(!0);try{const s=await this.client.fetch(n);this.callbacks.onData(s),this.callbacks.onError(null),r&&(this.fetchOnceCache[n]=s)}catch(s){if(s instanceof ue){this.callbacks.onUnauthorized(s);return}this.callbacks.onError(s instanceof Error?s:new Error(String(s)))}finally{this.callbacks.onLoading(!1)}}cacheForTab(n,r){this.fetchOnceCache[n]=r}clearCache(){this.fetchOnceCache={}}async fetchData(){const n=this.currentTab;if(n){if(this.fetchOnceCache[n]!==void 0){this.callbacks.onData(this.fetchOnceCache[n]),this.callbacks.onLoading(!1);return}try{const r=`${this.endpoint}${Jn(n)}`,s=await this.client.fetch(r);this.callbacks.onData(s),this.callbacks.onError(null),this.callbacks.onLoading(!1)}catch(r){if(r instanceof ue){this.callbacks.onError(r),this.callbacks.onLoading(!1),this.stop(),this.callbacks.onUnauthorized(r);return}this.callbacks.onError(r instanceof Error?r:new Error(String(r))),this.callbacks.onLoading(!1)}}}}function F(e,n={}){const{baseUrl:r="",debugEndpoint:s="/admin/api/debug",authToken:i}=n,[l,o]=x(null),[h,c]=x(!0),[a,p]=x(null),d=B(null);d.current||(d.current=new Kn({baseUrl:r,endpoint:s,authToken:i,onData:m=>o(m),onLoading:m=>c(m),onError:m=>p(m),onUnauthorized:m=>p(m)})),z(()=>{const m=d.current;return m.start(e),()=>m.stop()},[e]);const u=S(()=>{d.current?.refresh()},[]),f=S(()=>{o(null)},[]),_=S((m,y)=>{d.current?.cacheForTab(m,y)},[]);return{data:l,isLoading:h,error:a,refresh:u,clearData:f,cacheForTab:_}}const Qn="ss-col-resize",wt="ss-resizing";function Nt(e){const n=Array.from(e.querySelectorAll("thead th"));if(n.length===0)return()=>{};const r=[];let s=!1;function i(){if(!s){s=!0;for(const l of n)l.style.width=l.offsetWidth+"px";e.style.tableLayout="fixed"}}for(const l of n){let o=function(c){c.preventDefault(),c.stopPropagation(),i();const a=c.clientX,p=l.offsetWidth;h.classList.add(wt),h.setPointerCapture(c.pointerId);function d(f){const _=f.clientX-a,m=Math.max(30,p+_);l.style.width=m+"px"}function u(){h.classList.remove(wt),h.removeEventListener("pointermove",d),h.removeEventListener("pointerup",u)}h.addEventListener("pointermove",d),h.addEventListener("pointerup",u)};if(!l.textContent?.trim())continue;const h=document.createElement("div");h.className=Qn,l.appendChild(h),h.addEventListener("pointerdown",o),r.push(()=>{h.removeEventListener("pointerdown",o),h.remove()})}return()=>{for(const l of r)l()}}function W(e=[]){const n=B(null),r=B(null);return z(()=>(n.current&&(r.current?.(),r.current=Nt(n.current)),()=>{r.current?.(),r.current=null}),e),S(i=>{r.current?.(),r.current=null,n.current=i,i&&(r.current=Nt(i))},[])}function xt({options:e}){const{data:n,isLoading:r,error:s}=F("queries",e),[i,l]=x(""),[o,h]=x(null),c=T(()=>n?.queries||[],[n]),a=T(()=>zn(c,i),[c,i]),p=T(()=>Vn(c),[c]),d=T(()=>Wn(c,p),[c,p]),u=S(_=>{h(m=>m===_?null:_)},[]),f=W([a]);return r&&!n?t("div",{className:"ss-dbg-empty",children:"Loading queries..."}):s?t("div",{className:"ss-dbg-empty",children:["Error: ",s.message]}):t("div",{children:[t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter queries...",value:i,onChange:_=>l(_.target.value)}),t("span",{className:"ss-dbg-summary",children:[a.length," queries",d.slowCount>0&&` | ${d.slowCount} slow`,d.dupCount>0&&` | ${d.dupCount} dup`,a.length>0&&` | avg ${j(d.avgDuration)}`]})]}),a.length===0?t("div",{className:"ss-dbg-empty",children:"No queries captured"}):t("table",{ref:f,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"50px"}}),t("col",{}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"70px"}}),t("col",{style:{width:"100px"}}),t("col",{style:{width:"80px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"#"}),t("th",{children:"SQL"}),t("th",{children:"Duration"}),t("th",{children:"Method"}),t("th",{children:"Model"}),t("th",{children:"Time"})]})}),t("tbody",{children:a.map(_=>t("tr",{children:[t("td",{className:"ss-dbg-c-dim",style:{whiteSpace:"nowrap"},children:_.id}),t("td",{children:[t("span",{className:`ss-dbg-sql ${o===_.id?"ss-dbg-expanded":""}`,onClick:()=>u(_.id),role:"button",tabIndex:0,onKeyDown:m=>m.key==="Enter"&&u(_.id),children:_.sql}),p[_.sql]>1&&t("span",{className:"ss-dbg-dup",children:[" x",p[_.sql]]}),_.inTransaction&&t("span",{className:"ss-dbg-dup",children:" TXN"})]}),t("td",{className:`ss-dbg-duration ${Q(_.duration)==="very-slow"?"ss-dbg-very-slow":Q(_.duration)==="slow"?"ss-dbg-slow":""}`,children:j(_.duration)}),t("td",{children:t("span",{className:`ss-dbg-method ss-dbg-method-${_.method.toLowerCase()}`,children:_.method})}),t("td",{className:"ss-dbg-c-muted",children:_.model||"-"}),t("td",{className:"ss-dbg-event-time",title:V(_.timestamp),children:R(_.timestamp)})]},_.id))})]})]})}const Gn=Object.freeze(Object.defineProperty({__proto__:null,QueriesTab:xt,default:xt},Symbol.toStringTag,{value:"Module"}));function Ae({data:e,maxPreviewLength:n=100,className:r="",classPrefix:s="ss-dash"}){const[i,l]=x(!1),o=T(()=>{if(typeof e=="string")try{return JSON.parse(e)}catch{return e}return e},[e]),h=T(()=>typeof o=="object"&&o!==null?pe(o,n):String(o??"-"),[o,n]),c=T(()=>typeof o=="object"&&o!==null?JSON.stringify(o,null,2):String(o),[o]),a=S(()=>{l(d=>!d)},[]),p=S(async()=>{try{await navigator.clipboard.writeText(c)}catch{}},[c]);return!e&&e!==0&&e!==!1?t("span",{className:`ss-dim ${s}-c-dim`,children:"-"}):t("div",{className:`${s}-data-cell ${r}`,children:[t("span",{className:`${s}-data-preview`,onClick:a,role:"button",tabIndex:0,onKeyDown:d=>d.key==="Enter"&&a(),children:h}),i&&t("div",{className:`${s}-data-full`,onClick:a,children:[t("button",{className:`${s}-copy-btn`,onClick:d=>{d.stopPropagation(),p()},title:"Copy to clipboard",type:"button",children:"Copy"}),t("pre",{children:c})]})]})}function $t({options:e}){const{data:n,isLoading:r,error:s}=F("events",e),[i,l]=x(""),o=T(()=>{const c=n?.events||[];if(!i)return c;const a=i.toLowerCase();return c.filter(p=>(p.event||"").toLowerCase().includes(a)||(p.data||"").toLowerCase().includes(a))},[n,i]),h=W([o]);return r&&!n?t("div",{className:"ss-dbg-empty",children:"Loading events..."}):s?t("div",{className:"ss-dbg-empty",children:["Error: ",s.message]}):t("div",{children:[t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter events...",value:i,onChange:c=>l(c.target.value)}),t("span",{className:"ss-dbg-summary",children:[o.length," events"]})]}),o.length===0?t("div",{className:"ss-dbg-empty",children:"No events captured"}):t("table",{ref:h,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"50px"}}),t("col",{style:{width:"20%"}}),t("col",{}),t("col",{style:{width:"80px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"#"}),t("th",{children:"Event"}),t("th",{children:"Data"}),t("th",{children:"Time"})]})}),t("tbody",{children:o.map(c=>{const a=c.timestamp||c.created_at||c.createdAt;return t("tr",{children:[t("td",{className:"ss-dbg-c-dim",style:{whiteSpace:"nowrap"},children:c.id}),t("td",{className:"ss-dbg-event-name",children:c.event}),t("td",{className:"ss-dbg-event-data",children:t(Ae,{data:c.data,maxPreviewLength:80,classPrefix:"ss-dbg"})}),t("td",{className:"ss-dbg-event-time",title:V(a),children:R(a)})]},c.id)})})]})]})}const Xn=Object.freeze(Object.defineProperty({__proto__:null,EventsTab:$t,default:$t},Symbol.toStringTag,{value:"Module"}));function kt({options:e}){const{data:n,isLoading:r,error:s}=F("emails",e),[i,l]=x(""),[o,h]=x(null),c=T(()=>{const f=n?.emails||[];if(!i)return f;const _=i.toLowerCase();return f.filter(m=>(m.subject||"").toLowerCase().includes(_)||(m.to||"").toLowerCase().includes(_)||(m.from||"").toLowerCase().includes(_)||(m.mailer||"").toLowerCase().includes(_))},[n,i]),a=T(()=>c.find(f=>f.id===o),[c,o]),p=S(()=>h(null),[]),d={sent:"ss-dbg-email-status-sent",sending:"ss-dbg-email-status-sending",queued:"ss-dbg-email-status-queued",failed:"ss-dbg-email-status-failed"},u=W([c]);return r&&!n?t("div",{className:"ss-dbg-empty",children:"Loading emails..."}):s?t("div",{className:"ss-dbg-empty",children:["Error: ",s.message]}):a?t("div",{className:"ss-dbg-email-preview",children:[t("div",{className:"ss-dbg-email-preview-header",children:[t("div",{className:"ss-dbg-email-preview-meta",children:[t("div",{children:[t("strong",{children:"Subject:"})," ",a.subject]}),t("div",{children:[t("strong",{children:"From:"})," ",a.from]}),t("div",{children:[t("strong",{children:"To:"})," ",a.to]}),a.cc&&t("div",{children:[t("strong",{children:"CC:"})," ",a.cc]})]}),t("button",{className:"ss-dbg-btn-clear",onClick:p,type:"button",children:"×"})]}),a.html?t("iframe",{className:"ss-dbg-email-iframe",srcDoc:a.html,title:"Email preview",sandbox:""}):t("div",{style:{padding:"12px",whiteSpace:"pre-wrap"},children:a.text||"No content"})]}):t("div",{children:[t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter emails...",value:i,onChange:f=>l(f.target.value)}),t("span",{className:"ss-dbg-summary",children:[c.length," emails"]})]}),c.length===0?t("div",{className:"ss-dbg-empty",children:"No emails captured"}):t("table",{ref:u,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"50px"}}),t("col",{style:{width:"140px"}}),t("col",{style:{width:"140px"}}),t("col",{}),t("col",{style:{width:"70px"}}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"40px"}}),t("col",{style:{width:"80px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"#"}),t("th",{children:"From"}),t("th",{children:"To"}),t("th",{children:"Subject"}),t("th",{children:"Status"}),t("th",{children:"Mailer"}),t("th",{title:"Attachments",children:"📎"}),t("th",{children:"Time"})]})}),t("tbody",{children:c.map(f=>t("tr",{className:"ss-dbg-email-row",onClick:()=>h(f.id),children:[t("td",{className:"ss-dbg-c-dim",style:{whiteSpace:"nowrap"},children:f.id}),t("td",{className:"ss-dbg-c-secondary",title:f.from,children:f.from}),t("td",{className:"ss-dbg-c-secondary",title:f.to,children:f.to}),t("td",{className:"ss-dbg-c-sql",children:f.subject}),t("td",{children:t("span",{className:`ss-dbg-email-status ${d[f.status]||""}`,children:f.status})}),t("td",{className:"ss-dbg-c-muted",children:f.mailer}),t("td",{className:"ss-dbg-c-dim",style:{textAlign:"center"},children:f.attachmentCount>0?f.attachmentCount:"-"}),t("td",{className:"ss-dbg-event-time",title:V(f.timestamp||f.created_at||f.createdAt),children:R(f.timestamp||f.created_at||f.createdAt)})]},f.id))})]})]})}const Yn=Object.freeze(Object.defineProperty({__proto__:null,EmailsTab:kt,default:kt},Symbol.toStringTag,{value:"Module"}));function Ct({options:e,currentPath:n}){const{data:r,isLoading:s,error:i}=F("routes",e),[l,o]=x(""),h=T(()=>{const a=r?.routes||[];if(!l)return a;const p=l.toLowerCase();return a.filter(d=>d.pattern.toLowerCase().includes(p)||d.handler.toLowerCase().includes(p)||d.method.toLowerCase().includes(p)||d.name&&d.name.toLowerCase().includes(p))},[r,l]),c=W([h]);return s&&!r?t("div",{className:"ss-dbg-empty",children:"Loading routes..."}):i?t("div",{className:"ss-dbg-empty",children:["Error: ",i.message]}):t("div",{children:[t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter routes...",value:l,onChange:a=>o(a.target.value)}),t("span",{className:"ss-dbg-summary",children:[h.length," routes"]})]}),h.length===0?t("div",{className:"ss-dbg-empty",children:"No routes found"}):t("table",{ref:c,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"70px"}}),t("col",{style:{width:"25%"}}),t("col",{style:{width:"15%"}}),t("col",{}),t("col",{style:{width:"20%"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"Method"}),t("th",{children:"Pattern"}),t("th",{children:"Name"}),t("th",{children:"Handler"}),t("th",{children:"Middleware"})]})}),t("tbody",{children:h.map((a,p)=>{const d=n&&(a.pattern===n||new RegExp("^"+a.pattern.replace(/:[^/]+/g,"[^/]+")+"$").test(n));return t("tr",{className:d?"ss-dbg-current-route":"",children:[t("td",{children:t("span",{className:`ss-dbg-method ss-dbg-method-${a.method.toLowerCase()}`,children:a.method})}),t("td",{className:"ss-dbg-c-text",children:a.pattern}),t("td",{className:"ss-dbg-c-muted",children:a.name||"-"}),t("td",{className:"ss-dbg-c-sql",children:a.handler}),t("td",{className:"ss-dbg-c-dim",style:{fontSize:"10px"},children:a.middleware.length>0?a.middleware.join(", "):"-"})]},`${a.method}-${a.pattern}-${p}`)})})]})]})}const Zn=Object.freeze(Object.defineProperty({__proto__:null,RoutesTab:Ct,default:Ct},Symbol.toStringTag,{value:"Module"})),er=["all","error","warn","info","debug"];function St(e){return(e.levelName||e.level_name||(typeof e.level=="string"?e.level:"")||"info").toLowerCase()}function Tt(e){return e.msg||e.message||JSON.stringify(e)}function tr(e){return e.createdAt||e.created_at||e.time||e.timestamp||0}function Lt(e){const n=e.data||{};return e.requestId||e.request_id||e["x-request-id"]||n.requestId||n.request_id||n["x-request-id"]||""}function nr(e,n="ss-dbg-log-level"){switch(e){case"error":case"fatal":return`${n}-error`;case"warn":return`${n}-warn`;case"info":return`${n}-info`;case"debug":return`${n}-debug`;case"trace":return`${n}-trace`;default:return`${n}-info`}}function rr(e,n){return n==="all"?e:e.filter(r=>{const s=St(r);return n==="error"?s==="error"||s==="fatal":s===n})}function Et({options:e}){const{data:n,isLoading:r,error:s}=F("logs",e),[i,l]=x("all"),[o,h]=x(""),[c,a]=x(""),p=T(()=>{let u=Array.isArray(n)?n:n?.logs||n?.entries||[];if(u=rr(u,i),c){const f=c.toLowerCase();u=u.filter(_=>Lt(_).toLowerCase().includes(f))}if(o){const f=o.toLowerCase();u=u.filter(_=>Tt(_).toLowerCase().includes(f))}return u},[n,i,o,c]),d=S(u=>{a(f=>f===u?"":u)},[]);return r&&!n?t("div",{className:"ss-dbg-empty",children:"Loading logs..."}):s?t("div",{className:"ss-dbg-empty",children:["Error: ",s.message]}):t("div",{children:[t("div",{className:"ss-dbg-log-filters",children:[er.map(u=>t("button",{type:"button",className:`ss-dbg-log-filter ${i===u?"ss-dbg-active":""}`,onClick:()=>l(u),children:u},u)),c&&t("button",{type:"button",className:"ss-dbg-log-filter ss-dbg-active",onClick:()=>a(""),children:["req: ",c.slice(0,8)," x"]}),t("span",{className:"ss-dbg-summary",style:{marginLeft:"auto"},children:[p.length," entries"]})]}),t("div",{className:"ss-dbg-search-bar",children:t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter log messages...",value:o,onChange:u=>h(u.target.value)})}),t("div",{style:{overflow:"auto",flex:1},children:p.length===0?t("div",{className:"ss-dbg-empty",children:"No log entries"}):p.slice(-200).reverse().map((u,f)=>{const _=St(u),m=Tt(u),y=tr(u),b=Lt(u);return t("div",{className:"ss-dbg-log-entry",children:[t("span",{className:`ss-dbg-log-level ${nr(_)}`,children:_.toUpperCase()}),t("span",{className:"ss-dbg-log-time",title:y?V(y):"",children:y?R(y):"-"}),b?t("span",{className:"ss-dbg-log-reqid",onClick:()=>d(b),role:"button",tabIndex:0,title:b,onKeyDown:g=>g.key==="Enter"&&d(b),children:b.slice(0,8)}):t("span",{className:"ss-dbg-log-reqid-empty",children:"-"}),t("span",{className:"ss-dbg-log-msg",children:m})]},f)})})]})}const sr=Object.freeze(Object.defineProperty({__proto__:null,LogsTab:Et,default:Et},Symbol.toStringTag,{value:"Module"}));function At(e="",n){const r=B(null);return S(()=>(r.current||(r.current=new Se({baseUrl:e,authToken:n})),r.current),[e,n])}const Pt={request:"#1e3a5f",middleware:"rgba(30, 58, 95, 0.7)",db:"#6d28d9",view:"#0e7490",mail:"#059669",event:"#b45309",custom:"#525252"},lr=[{label:"Request",color:"#1e3a5f"},{label:"Middleware",color:"rgba(30, 58, 95, 0.7)"},{label:"Database",color:"#6d28d9"},{label:"View",color:"#0e7490"},{label:"Mail",color:"#059669"},{label:"Event",color:"#b45309"}];function Mt({options:e}){const{baseUrl:n="",debugEndpoint:r="/admin/api/debug",authToken:s}=e||{},{data:i,isLoading:l,error:o}=F("timeline",e),[h,c]=x(""),[a,p]=x(null),[d,u]=x(null),[f,_]=x(!1),[m,y]=x(null),b=T(()=>{const w=i?.traces||[];if(!h)return w;const P=h.toLowerCase();return w.filter($=>$.url.toLowerCase().includes(P)||$.method.toLowerCase().includes(P)||String($.statusCode).includes(P))},[i,h]),g=At(n,s);z(()=>{if(a===null){u(null),y(null);return}let w=!1;return _(!0),y(null),g().get(`${r}/traces/${a}`).then($=>{w||(u($),_(!1))}).catch($=>{w||(y($ instanceof Error?$.message:"Failed to load trace"),_(!1))}),()=>{w=!0}},[a,r,g]);const k=S(w=>{p(P=>P===w?null:w)},[]),C=S(w=>w>=500?"ss-dbg-status-5xx":w>=400?"ss-dbg-status-4xx":w>=300?"ss-dbg-status-3xx":"ss-dbg-status-2xx",[]),v=W([b]);if(l&&!i)return t("div",{className:"ss-dbg-empty",children:"Loading traces..."});if(o)return t("div",{className:"ss-dbg-empty",children:["Error: ",o.message]});if(a!==null){if(f)return t("div",{className:"ss-dbg-empty",children:"Loading trace detail..."});if(m)return t("div",{children:[t("div",{className:"ss-dbg-tl-detail-header",children:t("button",{type:"button",className:"ss-dbg-btn-clear",onClick:()=>p(null),children:"← Back"})}),t("div",{className:"ss-dbg-empty",children:["Error: ",m]})]});if(!d)return t("div",{className:"ss-dbg-empty",children:"Loading trace detail..."});const w=d.spans||[],P=d.warnings||[];return t("div",{children:[t("div",{className:"ss-dbg-tl-detail-header",children:[t("button",{type:"button",className:"ss-dbg-btn-clear",onClick:()=>p(null),children:"← Back"}),t("span",{className:`ss-dbg-method ss-dbg-method-${d.method.toLowerCase()}`,children:d.method}),t("span",{className:"ss-dbg-tl-detail-url",children:d.url}),t("span",{className:`ss-dbg-status ${C(d.statusCode)}`,children:d.statusCode}),t("span",{className:"ss-dbg-tl-meta",children:[j(d.totalDuration)," · ",d.spanCount," spans"]})]}),t("div",{className:"ss-dbg-tl-legend",children:lr.map($=>t("div",{className:"ss-dbg-tl-legend-item",children:[t("div",{className:"ss-dbg-tl-legend-dot",style:{background:$.color}}),t("span",{children:$.label})]},$.label))}),t("div",{style:{padding:"8px 12px",overflow:"auto"},children:w.length===0?t("div",{className:"ss-dbg-empty",children:"No spans captured for this request"}):w.map($=>{const M=d.totalDuration||1,q=$.startOffset/M*100,Dr=Math.max($.duration/M*100,.5);return t("div",{className:"ss-dbg-tl-row",children:[t("div",{className:"ss-dbg-tl-label",title:$.label,children:$.label}),t("div",{className:"ss-dbg-tl-track",children:t("div",{className:`ss-dbg-tl-bar ss-dbg-tl-bar-${$.category}`,style:{left:`${q}%`,width:`${Dr}%`,background:Pt[$.category]||Pt.custom},title:`${$.label}: ${j($.duration)}`})}),t("span",{className:"ss-dbg-tl-dur",children:j($.duration)})]},$.id)})}),P.length>0&&t("div",{className:"ss-dbg-tl-warnings",children:[t("div",{className:"ss-dbg-tl-warnings-title",children:"Warnings"}),P.map(($,M)=>t("div",{className:"ss-dbg-tl-warning",children:$},M))]})]})}return t("div",{children:[t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter traces...",value:h,onChange:w=>c(w.target.value)}),t("span",{className:"ss-dbg-summary",children:[b.length," traces"]})]}),b.length===0?t("div",{className:"ss-dbg-empty",children:"No traces captured. Enable tracing in config."}):t("table",{ref:v,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"50px"}}),t("col",{style:{width:"70px"}}),t("col",{}),t("col",{style:{width:"60px"}}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"50px"}}),t("col",{style:{width:"80px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"#"}),t("th",{children:"Method"}),t("th",{children:"URL"}),t("th",{children:"Status"}),t("th",{children:"Duration"}),t("th",{children:"Spans"}),t("th",{children:"Time"})]})}),t("tbody",{children:b.map(w=>t("tr",{className:"ss-dbg-email-row",onClick:()=>k(w.id),children:[t("td",{className:"ss-dbg-c-dim",style:{whiteSpace:"nowrap"},children:w.id}),t("td",{children:t("span",{className:`ss-dbg-method ss-dbg-method-${w.method.toLowerCase()}`,children:w.method})}),t("td",{title:w.url,children:w.url}),t("td",{children:t("span",{className:`ss-dbg-status ${C(w.statusCode)}`,children:w.statusCode})}),t("td",{className:`ss-dbg-duration ${Q(w.totalDuration)==="very-slow"?"ss-dbg-very-slow":Q(w.totalDuration)==="slow"?"ss-dbg-slow":""}`,children:j(w.totalDuration)}),t("td",{className:"ss-dbg-c-muted",style:{textAlign:"center"},children:w.spanCount}),t("td",{className:"ss-dbg-event-time",title:V(w.timestamp),children:R(w.timestamp)})]},w.id))})]})]})}const ir=Object.freeze(Object.defineProperty({__proto__:null,TimelineTab:Mt,default:Mt},Symbol.toStringTag,{value:"Module"}));function Pe(e,n){const r=T(()=>e?e.replace(/\/+$/,"")+"/api":null,[e]),s=T(()=>r?{...n,debugEndpoint:r}:n,[r,n]);return{dashApiBase:r,resolvedOptions:s}}function Ot({options:e,dashboardPath:n}){const{dashApiBase:r,resolvedOptions:s}=Pe(n,e),{data:i,isLoading:l,error:o}=F("cache",s),[h,c]=x(""),[a,p]=x(null),[d,u]=x(null),f=T(()=>{const g=i?.keys||[];if(!h)return g;const k=h.toLowerCase();return g.filter(C=>C.key.toLowerCase().includes(k))},[i,h]),_=S(async g=>{if(a===g){p(null),u(null);return}p(g);try{const{baseUrl:k="",authToken:C}=e||{},v=r||e?.debugEndpoint||"/admin/api/debug",w=`${k}${v}/cache/${encodeURIComponent(g)}`,P={Accept:"application/json"};C&&(P.Authorization=`Bearer ${C}`);const M=await(await fetch(w,{headers:P,credentials:C?"omit":"same-origin"})).json();u(M)}catch{u({error:"Failed to fetch key value"})}},[a,e,r]),m=W([f]);if(l&&!i)return t("div",{className:"ss-dbg-empty",children:"Loading cache data..."});if(o)return t("div",{className:"ss-dbg-empty",children:["Error: ",o.message]});if(!i)return t("div",{className:"ss-dbg-empty",children:"Cache inspector not available"});const b=i.stats||i;return t("div",{children:[t("div",{className:"ss-dbg-cache-stats",children:[t("div",{className:"ss-dbg-cache-stat",children:[t("span",{className:"ss-dbg-cache-stat-label",children:"Hit Rate:"}),t("span",{className:"ss-dbg-cache-stat-value",children:[b.hitRate!==null&&b.hitRate!==void 0?b.hitRate.toFixed(1):"0","%"]})]}),t("div",{className:"ss-dbg-cache-stat",children:[t("span",{className:"ss-dbg-cache-stat-label",children:"Hits:"}),t("span",{className:"ss-dbg-cache-stat-value",children:b.totalHits??0})]}),t("div",{className:"ss-dbg-cache-stat",children:[t("span",{className:"ss-dbg-cache-stat-label",children:"Misses:"}),t("span",{className:"ss-dbg-cache-stat-value",children:b.totalMisses??0})]}),t("div",{className:"ss-dbg-cache-stat",children:[t("span",{className:"ss-dbg-cache-stat-label",children:"Keys:"}),t("span",{className:"ss-dbg-cache-stat-value",children:b.keyCount??"-"})]})]}),t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:"Filter keys...",value:h,onChange:g=>c(g.target.value)}),t("span",{className:"ss-dbg-summary",children:[f.length," keys"]})]}),a&&!!d&&t("div",{className:"ss-dbg-cache-detail",children:[t("strong",{children:a}),t("button",{type:"button",className:"ss-dbg-btn-clear",onClick:()=>p(null),children:["←"," Back"]}),t(Ae,{data:d,classPrefix:"ss-dbg"})]}),f.length===0?t("div",{className:"ss-dbg-empty",children:"No cache keys found"}):t("table",{ref:m,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"80px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"Key"}),t("th",{children:"Type"}),t("th",{children:"TTL"}),t("th",{children:"Size"})]})}),t("tbody",{children:f.map(g=>t("tr",{className:"ss-dbg-email-row",onClick:()=>_(g.key),children:[t("td",{className:"ss-dbg-c-sql",children:g.key}),t("td",{className:"ss-dbg-c-muted",children:g.type}),t("td",{className:"ss-dbg-c-muted",children:g.ttl>0?Un(g.ttl):"-"}),t("td",{className:"ss-dbg-c-dim",children:g.size>0?Hn(g.size):"-"})]},g.key))})]})]})}const ar=Object.freeze(Object.defineProperty({__proto__:null,CacheTab:Ot,default:Ot},Symbol.toStringTag,{value:"Module"})),or=["all","active","waiting","delayed","completed","failed"];function cr(e,n="ss-dbg-job-status"){switch(e){case"completed":case"failed":case"active":case"waiting":case"delayed":return`${n}-${e}`;default:return"ss-dbg-badge-muted"}}function dr(e){if(!e)return[];if(Array.isArray(e))return e;const n=e;return n.jobs||n.data||[]}function hr(e){if(!e||Array.isArray(e))return null;const n=e;return n.stats||n.overview||null}function It({options:e,dashboardPath:n}){const{dashApiBase:r,resolvedOptions:s}=Pe(n,e),{data:i,isLoading:l,error:o}=F("jobs",s),[h,c]=x("all"),[a,p]=x(null),d=T(()=>{const m=dr(i);return h==="all"?m:m.filter(y=>y.status===h)},[i,h]),u=S(async m=>{p(m);try{const{baseUrl:y="",authToken:b}=e||{},g=r||e?.debugEndpoint||"/admin/api/debug",k=`${y}${g}/jobs/${m}/retry`,C={Accept:"application/json"};b&&(C.Authorization=`Bearer ${b}`),await fetch(k,{method:"POST",headers:C,credentials:b?"omit":"same-origin"})}catch{}p(null)},[e,r]),f=W([d]);if(!r)return t("div",{className:"ss-dbg-empty",children:"Queue inspector not available (no dashboard configured)"});if(l&&!i)return t("div",{className:"ss-dbg-empty",children:"Loading jobs..."});if(o)return t("div",{className:"ss-dbg-empty",children:["Error: ",o.message]});if(!i)return t("div",{className:"ss-dbg-empty",children:"Queue inspector not available"});const _=hr(i);return t("div",{children:[t("div",{className:"ss-dbg-job-stats-area",children:[t("div",{className:"ss-dbg-job-stats",children:[t("div",{className:"ss-dbg-job-stat",children:[t("span",{className:"ss-dbg-job-stat-label",children:"Active:"}),t("span",{className:"ss-dbg-job-stat-value",children:_?.active??0})]}),t("div",{className:"ss-dbg-job-stat",children:[t("span",{className:"ss-dbg-job-stat-label",children:"Waiting:"}),t("span",{className:"ss-dbg-job-stat-value",children:_?.waiting??0})]}),t("div",{className:"ss-dbg-job-stat",children:[t("span",{className:"ss-dbg-job-stat-label",children:"Delayed:"}),t("span",{className:"ss-dbg-job-stat-value",children:_?.delayed??0})]}),t("div",{className:"ss-dbg-job-stat",children:[t("span",{className:"ss-dbg-job-stat-label",children:"Completed:"}),t("span",{className:"ss-dbg-job-stat-value",children:_?.completed??0})]}),t("div",{className:"ss-dbg-job-stat",children:[t("span",{className:"ss-dbg-job-stat-label",children:"Failed:"}),t("span",{className:"ss-dbg-job-stat-value ss-dbg-c-red",children:_?.failed??0})]})]}),t("div",{className:"ss-dbg-log-filters",children:or.map(m=>t("button",{type:"button",className:`ss-dbg-job-filter ${h===m?"ss-dbg-active":""}`,onClick:()=>c(m),children:m},m))})]}),d.length===0?t("div",{className:"ss-dbg-empty",children:"No jobs found"}):t("table",{ref:f,className:"ss-dbg-table",children:[t("colgroup",{children:[t("col",{style:{width:"50px"}}),t("col",{style:{width:"15%"}}),t("col",{style:{width:"80px"}}),t("col",{}),t("col",{style:{width:"50px"}}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"80px"}}),t("col",{style:{width:"60px"}})]}),t("thead",{children:t("tr",{children:[t("th",{children:"ID"}),t("th",{children:"Name"}),t("th",{children:"Status"}),t("th",{children:"Payload"}),t("th",{children:"Tries"}),t("th",{children:"Duration"}),t("th",{children:"Time"}),t("th",{})]})}),t("tbody",{children:d.map(m=>{const y=m;return t("tr",{children:[t("td",{className:"ss-dbg-c-dim",children:m.id}),t("td",{className:"ss-dbg-c-sql",title:m.name,children:m.name}),t("td",{children:t("span",{className:`ss-dbg-badge ${cr(m.status)}`,children:m.status})}),t("td",{children:t(Ae,{data:m.payload||m.data,maxPreviewLength:60,classPrefix:"ss-dbg"})}),t("td",{className:"ss-dbg-c-muted",style:{textAlign:"center"},children:m.attempts||y.attemptsMade||0}),t("td",{className:"ss-dbg-duration",children:m.duration!==null?j(m.duration):"-"}),t("td",{className:"ss-dbg-event-time",title:V(m.timestamp||m.createdAt||y.processedAt||y.created_at),children:R(m.timestamp||m.createdAt||y.processedAt||y.created_at)}),t("td",{children:m.status==="failed"&&t("button",{type:"button",className:"ss-dbg-retry-btn",onClick:()=>u(m.id),disabled:a===m.id,children:a===m.id?"...":"Retry"})})]},m.id)})})]})]})}const ur=Object.freeze(Object.defineProperty({__proto__:null,JobsTab:It,default:It},Symbol.toStringTag,{value:"Module"}));function O(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)&&e.__redacted===!0}function Me(e,n=""){if(typeof e!="object"||e===null||e===void 0)return[{path:n,value:e}];if(Array.isArray(e)||O(e))return[{path:n,value:e}];const r=[];for(const s of Object.keys(e)){const i=n?`${n}.${s}`:s,l=e[s];typeof l=="object"&&l!==null&&!Array.isArray(l)&&!O(l)?r.push(...Me(l,i)):r.push({path:i,value:l})}return r}function Oe(e){return e==null?{text:"null",color:"var(--ss-dim)"}:typeof e=="boolean"?{text:String(e),color:e?"var(--ss-green-fg)":"var(--ss-red-fg)"}:typeof e=="number"?{text:String(e),color:"var(--ss-amber-fg)"}:Array.isArray(e)?{text:`[${e.map(r=>r==null?"null":typeof r=="object"?JSON.stringify(r):String(r)).join(", ")}]`,color:"var(--ss-purple-fg)"}:typeof e=="object"?{text:JSON.stringify(e),color:"var(--ss-dim)"}:{text:String(e)}}function Dt(e){if(e==null||typeof e!="object"||Array.isArray(e)||O(e))return 1;let n=0;for(const r of Object.keys(e))n+=Dt(e[r]);return n}function fr(e){if(e==null||typeof e!="object"||Array.isArray(e)||O(e))return[];const n=[];for(const r of Object.keys(e)){const s=e[r];s!==null&&typeof s=="object"&&!Array.isArray(s)&&!O(s)&&n.push(r)}return n}function _e(e,n,r){n&&navigator.clipboard.writeText(e).then(()=>{const s=n.textContent;n.textContent="✓",n.classList.add(`${r}-copy-row-ok`),setTimeout(()=>{n.textContent=s,n.classList.remove(`${r}-copy-row-ok`)},1200)}).catch(()=>{})}function me({redacted:e,p:n}){const[r,s]=x(!1);return t("span",{className:`${n}-config-redacted`,style:{display:"inline-flex",alignItems:"center",gap:"4px"},children:[t("span",{children:r?e.value:e.display}),t("button",{type:"button",className:`${n}-btn`,title:r?"Hide":"Reveal",style:{padding:"0 4px",fontSize:"0.85em",lineHeight:1,minWidth:"auto"},onClick:i=>{i.stopPropagation(),s(l=>!l)},children:r?t("svg",{width:"14",height:"14",viewBox:A["eye-off"].viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A["eye-off"].elements.join("")}}):t("svg",{width:"14",height:"14",viewBox:A.eye.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A.eye.elements.join("")}})})]})}function pr({env:e,search:n,p:r}){const s=B(new Map),i=n.toLowerCase(),l=Object.entries(e).filter(([o,h])=>{if(!i)return!0;const c=O(h)?h.display:h==null?"":String(h);return o.toLowerCase().includes(i)||c.toLowerCase().includes(i)});return t("div",{className:`${r}-config-table-wrap`,children:t("table",{className:`${r}-table ${r}-config-env-table`,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Variable"}),t("th",{children:"Value"}),t("th",{style:{width:36}})]})}),t("tbody",{children:[l.map(([o,h])=>{const c=O(h),a=c?h.display:h==null?"null":String(h),p=`${o}=${a}`;return t("tr",{children:[t("td",{className:`${r}-env-key`,children:t("span",{className:`${r}-config-key`,children:o})}),t("td",{className:`${r}-env-val`,children:c?t(me,{redacted:h,p:r}):t("span",{className:`${r}-config-val`,children:a})}),t("td",{children:!c&&t("button",{type:"button",className:`${r}-copy-row-btn`,title:"Copy",ref:d=>{s.current.set(o,d)},onClick:d=>{d.stopPropagation(),_e(p,s.current.get(o)??null,r)},children:"⎘"})})]},o)}),l.length===0&&t("tr",{children:t("td",{colSpan:3,style:{textAlign:"center",color:"var(--ss-dim)"},children:"No matching variables"})})]})]})})}function _r({source:e,search:n,p:r}){const s=B(new Map),i=n.toLowerCase(),l=Me(e,""),o=l.filter(h=>{const c=O(h.value)?h.value.display:h.value===null||h.value===void 0?"":String(h.value);return h.path.toLowerCase().includes(i)||c.toLowerCase().includes(i)});return t("div",{className:`${r}-config-table-wrap`,children:[t("table",{className:`${r}-table`,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Path"}),t("th",{children:"Value"}),t("th",{style:{width:36}})]})}),t("tbody",{children:[o.map(h=>{const c=O(h.value),a=c?null:Oe(h.value),p=c?h.value.display:a.text,d=`${h.path}: ${p}`;return t("tr",{children:[t("td",{children:t("span",{className:`${r}-config-key`,style:{whiteSpace:"nowrap"},children:h.path})}),t("td",{children:c?t(me,{redacted:h.value,p:r}):t("span",{className:`${r}-config-val`,style:{wordBreak:"break-all",color:a.color},children:a.text})}),t("td",{children:!c&&t("button",{type:"button",className:`${r}-copy-row-btn`,title:"Copy",ref:u=>{s.current.set(h.path,u)},onClick:u=>{u.stopPropagation(),_e(d,s.current.get(h.path)??null,r)},children:"⎘"})})]},h.path)}),o.length===0&&t("tr",{children:t("td",{colSpan:3,style:{textAlign:"center",color:"var(--ss-dim)"},children:"No matching entries"})})]})]}),t("div",{style:{padding:"4px 16px",fontSize:"10px",color:"var(--ss-muted)"},children:[o.length," of ",l.length," entries"]})]})}function mr({obj:e,prefix:n,p:r}){const s=B(new Map),i=Me(e,n);return t("table",{className:`${r}-table ${r}-config-inner-table`,children:[t("thead",{children:t("tr",{children:[t("th",{style:{width:"35%"},children:"Key"}),t("th",{children:"Value"}),t("th",{style:{width:36}})]})}),t("tbody",{children:i.map(l=>{const o=l.path.indexOf(n+".")===0?l.path.slice(n.length+1):l.path,h=O(l.value),c=h?null:Oe(l.value),a=h?l.value.display:c.text,p=`${l.path}: ${a}`;return t("tr",{children:[t("td",{title:o,children:t("span",{className:`${r}-config-key`,children:o})}),t("td",{title:a,children:h?t(me,{redacted:l.value,p:r}):t("span",{className:`${r}-config-val`,style:{color:c.color},children:c.text})}),t("td",{children:!h&&t("button",{type:"button",className:`${r}-copy-row-btn`,title:"Copy",ref:d=>{s.current.set(l.path,d)},onClick:d=>{d.stopPropagation(),_e(p,s.current.get(l.path)??null,r)},children:"⎘"})})]},l.path)})})]})}function gr({value:e,p:n}){if(e==null)return t("span",{className:`${n}-config-val`,style:{color:"var(--ss-dim)"},children:"null"});if(O(e))return t(me,{redacted:e,p:n});if(typeof e=="boolean")return t("span",{className:`${n}-config-val`,style:{color:e?"var(--ss-green-fg)":"var(--ss-red-fg)"},children:String(e)});if(typeof e=="number")return t("span",{className:`${n}-config-val`,style:{color:"var(--ss-amber-fg)"},children:String(e)});if(Array.isArray(e)){const r=e.map(s=>s==null?"null":typeof s=="object"?JSON.stringify(s):String(s));return t("span",{className:`${n}-config-val`,style:{color:"var(--ss-purple-fg)"},children:["[",r.join(", "),"]"]})}return typeof e=="object"?t("span",{className:`${n}-config-val`,style:{color:"var(--ss-dim)"},children:JSON.stringify(e)}):t("span",{className:`${n}-config-val`,children:String(e)})}function br({obj:e,expandedPaths:n,onToggle:r,p:s}){if(e==null||typeof e!="object"||Array.isArray(e)||O(e))return null;const i=Object.keys(e),l=B(new Map);return t("div",{className:`${s}-config-sections`,children:i.map(o=>{const h=e[o],c=h!==null&&typeof h=="object"&&!Array.isArray(h)&&!O(h),a=n.has(o),p=O(h);return t("div",{className:`${s}-config-section`,children:[t("div",{className:`${s}-config-section-header${c?"":` ${s}-config-leaf`}`,onClick:c?()=>r(o):void 0,style:{cursor:c?"pointer":"default"},children:[c?t("span",{className:`${s}-config-toggle`,children:a?"▼":"▶"}):t("span",{className:`${s}-config-toggle`,style:{visibility:"hidden"},children:"•"}),t("span",{className:`${s}-config-key`,children:o}),c?t("span",{className:`${s}-config-count`,children:[Dt(h)," entries"]}):t(I,{children:[t("span",{className:`${s}-config-val`,style:{marginLeft:"8px"},children:t(gr,{value:h,p:s})}),!p&&t("button",{type:"button",className:`${s}-copy-row-btn`,style:{marginLeft:"4px"},title:"Copy",ref:d=>{l.current.set(o,d)},onClick:d=>{d.stopPropagation();const u=Oe(h);_e(`${o}: ${u.text}`,l.current.get(o)??null,s)},children:"⎘"})]})]}),c&&a&&t("div",{className:`${s}-config-section-body`,children:t(mr,{obj:h,prefix:o,p:s})})]},o)})})}function yr({data:e,isLoading:n,classPrefix:r}){const s=r,[i,l]=x(""),[o,h]=x(""),[c,a]=x("app"),[p,d]=x(new Set),[u,f]=x("Copy JSON");z(()=>{const k=setTimeout(()=>h(i),200);return()=>clearTimeout(k)},[i]);const _=e,m=S(k=>{d(C=>{const v=new Set(C);return v.has(k)?v.delete(k):v.add(k),v})},[]),y=S(()=>{if(!_)return;const k=c==="app"?_.app:_.env;if(!k)return;const C=fr(k);d(new Set(C))},[_,c]),b=S(()=>{d(new Set)},[]),g=S(async()=>{if(_)try{const k=c==="app"?_.app:_.env;await navigator.clipboard.writeText(JSON.stringify(k,null,2)),f("Copied!"),setTimeout(()=>f("Copy JSON"),1500)}catch{}},[_,c]);return t("div",{children:[t("div",{className:`${s}-config-toolbar`,style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px"},children:[t("button",{type:"button",className:`${s}-config-tab${c==="app"?` ${s}-active`:""}`,onClick:()=>a("app"),children:"App Config"}),t("button",{type:"button",className:`${s}-config-tab${c==="env"?` ${s}-active`:""}`,onClick:()=>a("env"),children:"Env"}),t("div",{style:{position:"relative",flex:1},children:[t("input",{type:"text",className:`${s}-search`,placeholder:"Search keys and values...",value:i,onChange:k=>l(k.target.value),style:{width:"100%"}}),i&&t("button",{type:"button",onClick:()=>l(""),style:{position:"absolute",right:"6px",top:"50%",transform:"translateY(-50%)",background:"none",border:"none",cursor:"pointer",fontSize:"14px",color:"var(--ss-dim)",padding:"0 2px",lineHeight:1},children:"×"})]}),c==="app"&&!o&&t(I,{children:[t("button",{type:"button",className:`${s}-btn`,onClick:y,children:"Expand All"}),t("button",{type:"button",className:`${s}-btn`,onClick:b,children:"Collapse All"})]}),t("button",{type:"button",className:`${s}-btn`,onClick:g,children:u})]}),n&&!e?t("div",{className:`${s}-empty`,children:"Loading config..."}):_?c==="env"?t(pr,{env:_.env??{},search:o,p:s}):o?t(_r,{source:_.app??{},search:o,p:s}):t("div",{className:`${s}-config-table-wrap`,children:t(br,{obj:_.app,expandedPaths:p,onToggle:m,p:s})}):t("div",{className:`${s}-empty`,children:"Config not available"})]})}function Bt({options:e,dashboardPath:n}){const{resolvedOptions:r}=Pe(n,e),{data:s,isLoading:i,error:l}=F("config",r);return l?t("div",{className:"ss-dbg-empty",children:["Error: ",l.message]}):t(yr,{data:s,isLoading:i,classPrefix:"ss-dbg"})}const vr=Object.freeze(Object.defineProperty({__proto__:null,ConfigTab:Bt,default:Bt},Symbol.toStringTag,{value:"Module"})),wr=["password","secret","token","key","credential","auth"];function jt(e){const n=e.toLowerCase();return wr.some(r=>n.includes(r))}function Rt(e){if(e==null)return"-";if(typeof e=="string"||typeof e=="number"||typeof e=="boolean")return String(e);if(Array.isArray(e))return e.join(", ")||"-";try{return JSON.stringify(e)}catch{return String(e)}}const Nr={collectionInterval:"Stats Collection",dashboardBroadcast:"Dashboard Broadcast",debugBroadcast:"Debug Broadcast",persistFlush:"Persist Flush",retentionCleanup:"Retention Cleanup"};function xr(e){return Nr[e]||e}const $r={prometheus:"Prometheus",pinoHook:"Pino Log Hook",edgePlugin:"Edge Plugin",cacheInspector:"Cache Inspector",queueInspector:"Queue Inspector"};function kr(e){return $r[e]||e}const Cr=["healthy","active","connected","available","ready"],Sr=["errored","unavailable"];function Tr(e){return Cr.includes(e)?"ok":Sr.includes(e)?"err":""}function ee({status:e,prefix:n}){const r=Tr(e);let s=`${n}-dot`;return r==="ok"?s+=` ${n}-dot-ok`:r==="err"&&(s+=` ${n}-dot-err`),t("span",{className:s})}const Ft=()=>t("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:A.eye.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A.eye.elements.join("")}}),Ut=()=>t("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:A["eye-off"].viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:A["eye-off"].elements.join("")}});function Lr({value:e}){const[n,r]=x(!1);return t("span",{children:[n?e:"••••••••"," ",t("button",{type:"button",onClick:()=>r(s=>!s),style:{background:"none",border:"1px solid var(--ss-border)",borderRadius:3,padding:"0 4px",fontSize:"10px",color:"var(--ss-dim)",cursor:"pointer",verticalAlign:"middle"},children:n?t(Ut,{}):t(Ft,{})})]})}function Er({current:e,max:n,prefix:r}){const s=n>0?Math.min(100,Math.round(e/n*100)):0,i=s>=100;return t("div",{className:`${r}-bar`,children:[t("div",{className:`${r}-bar-track`,children:t("div",{className:`${r}-bar-fill${i?` ${r}-bar-fill-warn`:""}`,style:{width:`${s}%`}})}),t("span",{className:`${r}-bar-pct${i?` ${r}-bar-pct-warn`:""}`,children:[s,"%"]})]})}function Ar({config:e,prefix:n}){const r=Object.entries(e);return r.length===0?t("span",{className:`${n}-c-dim`,children:"-"}):t("span",{className:`${n}-c-muted`,children:r.map(([s,i],l)=>t("span",{children:[l>0&&", ",t("span",{className:`${n}-c-dim`,children:s}),"=",jt(s)&&typeof i=="string"?t(Lr,{value:i}):t("span",{children:Rt(i)})]},s))})}function te({label:e,value:n,prefix:r}){return t("div",{className:`${r}-info-card`,children:[t("span",{className:`${r}-info-card-label`,children:e}),t("span",{className:`${r}-info-card-value`,children:n})]})}function Pr({data:e,tableClassName:n,classPrefix:r}){const s=r||"ss-dash",[i,l]=x(new Set),o=S(c=>{l(a=>{const p=new Set(a);return p.has(c)?p.delete(c):p.add(c),p})},[]),h=S((c,a)=>{if(a==null)return t("span",{className:`${s}-c-dim`,children:"null"});if(typeof a=="boolean")return t("span",{className:a?`${s}-c-green`:`${s}-c-red`,children:String(a)});if(Array.isArray(a))return t("span",{children:a.join(", ")||"-"});const p=Rt(a);if(jt(c)){const d=i.has(c);return t("span",{children:[d?p:"••••••••"," ",t("button",{type:"button",onClick:()=>o(c),style:{background:"none",border:"1px solid var(--ss-border)",borderRadius:3,padding:"0 4px",fontSize:"10px",color:"var(--ss-dim)",cursor:"pointer",verticalAlign:"middle"},children:d?t(Ut,{}):t(Ft,{})})]})}return t("span",{children:p})},[i,o,s]);return t("div",{children:[t("h3",{className:`${s}-internals-title`,children:"Package Info"}),t("div",{className:`${s}-info-cards`,children:[t(te,{label:"Version",value:e.package.version||"-",prefix:s}),t(te,{label:"Node.js",value:e.package.nodeVersion||"-",prefix:s}),t(te,{label:"AdonisJS",value:e.package.adonisVersion||"-",prefix:s}),t(te,{label:"Uptime",value:Fn(e.package.uptime),prefix:s}),t(te,{label:"Renderer",value:e.devToolbar?.renderer||"preact",prefix:s})]}),e.collectors.length>0&&t(I,{children:[t("h3",{className:`${s}-internals-title`,children:"Collectors"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Collector"}),t("th",{children:"Status"}),t("th",{children:"Last Error"}),t("th",{children:"Config"})]})}),t("tbody",{children:e.collectors.map(c=>t("tr",{children:[t("td",{children:[t("code",{children:c.name}),c.label&&c.label!==c.name&&t("span",{className:`${s}-c-dim`,children:[" ",c.label]})]}),t("td",{children:[t(ee,{status:c.status,prefix:s}),c.status]}),t("td",{className:c.lastError?`${s}-c-red`:`${s}-c-dim`,children:c.lastError?t(I,{children:[c.lastError,c.lastErrorAt&&t("span",{className:`${s}-c-dim`,style:{fontSize:"10px"},children:R(c.lastErrorAt)})]}):"-"}),t("td",{children:t(Ar,{config:c.config,prefix:s})})]},c.name))})]})]}),t("h3",{className:`${s}-internals-title`,children:"Buffers"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Buffer"}),t("th",{children:"Usage"}),t("th",{children:"Fill %"})]})}),t("tbody",{children:Object.entries(e.buffers).map(([c,a])=>t("tr",{children:[t("td",{style:{textTransform:"capitalize"},children:c}),t("td",{children:[a.current.toLocaleString()," / ",a.max.toLocaleString()]}),t("td",{children:t(Er,{current:a.current,max:a.max,prefix:s})})]},c))})]}),t("h3",{className:`${s}-internals-title`,children:"Timers"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Timer"}),t("th",{children:"Status"}),t("th",{children:"Interval"})]})}),t("tbody",{children:Object.entries(e.timers).map(([c,a])=>t("tr",{children:[t("td",{children:xr(c)}),t("td",{children:[t(ee,{status:a.active?"active":"inactive",prefix:s}),t("span",{className:a.active?`${s}-c-green`:`${s}-c-dim`,children:a.active?"active":"inactive"})]}),t("td",{children:a.active?a.intervalMs?j(a.intervalMs):a.debounceMs?`${j(a.debounceMs)} (debounce)`:"-":t("span",{className:`${s}-c-dim`,children:"—"})})]},c))})]}),t("h3",{className:`${s}-internals-title`,children:"Integrations"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{children:"Integration"}),t("th",{children:"Status"}),t("th",{children:"Details"})]})}),t("tbody",{children:[t("tr",{children:[t("td",{children:"Transmit (SSE)"}),t("td",{children:[t(ee,{status:e.transmit.available?"connected":"inactive",prefix:s}),e.transmit.available?"connected":"unavailable"]}),t("td",{style:{fontSize:"11px"},children:e.transmit.channels.length>0?`Channels: ${e.transmit.channels.join(", ")}`:"-"})]}),Object.entries(e.integrations).map(([c,a])=>{const p=a.active??a.available??!1,d=a.active?"active":a.available?"available":"unavailable";let u=a.mode?`Mode: ${a.mode}`:"-";return c==="edgePlugin"&&a.active?u="@serverStats() tag registered":c==="cacheInspector"&&a.available?u="Redis dependency detected":c==="queueInspector"&&a.available&&(u="Queue dependency detected"),t("tr",{children:[t("td",{children:kr(c)}),t("td",{children:[t(ee,{status:p?"active":"inactive",prefix:s}),d]}),t("td",{className:`${s}-c-dim`,style:{fontSize:"11px"},children:u})]},c)})]})]}),e.storage&&t(I,{children:[t("h3",{className:`${s}-internals-title`,children:"Storage (SQLite)"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{style:{width:"200px"},children:"Metric"}),t("th",{children:"Value"})]})}),t("tbody",{children:[t("tr",{children:[t("td",{children:"Status"}),t("td",{children:[t(ee,{status:e.storage.ready?"ready":"inactive",prefix:s}),e.storage.ready?"ready":"not ready"]})]}),t("tr",{children:[t("td",{children:"DB Path"}),t("td",{children:t("code",{children:e.storage.dbPath})})]}),t("tr",{children:[t("td",{children:"File Size"}),t("td",{children:[e.storage.fileSizeMb.toFixed(1)," MB"]})]}),t("tr",{children:[t("td",{children:"WAL Size"}),t("td",{children:[e.storage.walSizeMb.toFixed(1)," MB"]})]}),t("tr",{children:[t("td",{children:"Retention"}),t("td",{children:[e.storage.retentionDays," days"]})]}),t("tr",{children:[t("td",{children:"Last Cleanup"}),t("td",{children:e.storage.lastCleanupAt?R(e.storage.lastCleanupAt):"-"})]})]})]}),e.storage.tables.length>0&&t("table",{className:n,style:{marginTop:8},children:[t("thead",{children:t("tr",{children:[t("th",{children:"Table"}),t("th",{children:"Rows"})]})}),t("tbody",{children:e.storage.tables.map(c=>t("tr",{children:[t("td",{children:t("code",{children:c.name})}),t("td",{children:c.rowCount.toLocaleString()})]},c.name))})]})]}),t("h3",{className:`${s}-internals-title`,children:"Resolved Config"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{style:{width:"200px"},children:"Setting"}),t("th",{children:"Value"})]})}),t("tbody",{children:[t("tr",{children:[t("td",{children:"intervalMs"}),t("td",{children:e.config.intervalMs})]}),t("tr",{children:[t("td",{children:"transport"}),t("td",{children:e.config.transport})]}),t("tr",{children:[t("td",{children:"channelName"}),t("td",{children:e.config.channelName})]}),t("tr",{children:[t("td",{children:"endpoint"}),t("td",{children:e.config.endpoint===!1?"false":e.config.endpoint})]}),t("tr",{children:[t("td",{children:"skipInTest"}),t("td",{children:h("skipInTest",e.config.skipInTest)})]}),t("tr",{children:[t("td",{children:"onStats callback"}),t("td",{children:e.config.hasOnStatsCallback?"defined":"not defined"})]}),t("tr",{children:[t("td",{children:"shouldShow callback"}),t("td",{children:e.config.hasShouldShowCallback?"defined":"not defined"})]})]})]}),t("h4",{className:`${s}-internals-title`,children:"DevToolbar"}),t("table",{className:n,children:[t("thead",{children:t("tr",{children:[t("th",{style:{width:"200px"},children:"Setting"}),t("th",{children:"Value"})]})}),t("tbody",{children:Object.entries(e.devToolbar).map(([c,a])=>t("tr",{children:[t("td",{children:c==="customPaneCount"?"customPanes":c}),t("td",{children:c==="customPaneCount"?`${a} registered`:h(c,a)})]},c))})]})]})}const Mr=3e3;function Ht({options:e}){const{baseUrl:n="",debugEndpoint:r="/admin/api/debug",authToken:s}=e||{},[i,l]=x(null),[o,h]=x(!0),[c,a]=x(null),p=B(null),d=At(n,s),u=S(async()=>{try{const _=await d().get(`${r}/diagnostics`);l(_),a(null),h(!1)}catch(f){if(f instanceof ue){a(f),h(!1),p.current&&(clearInterval(p.current),p.current=null);return}a(f instanceof Error?f:new Error(String(f))),h(!1)}},[r,d]);return z(()=>(h(!0),a(null),u(),p.current=setInterval(u,Mr),()=>{p.current&&(clearInterval(p.current),p.current=null)}),[u]),o&&!i?t("div",{className:"ss-dbg-empty",children:"Loading diagnostics..."}):c?t("div",{className:"ss-dbg-empty",children:["Error: ",c.message]}):i?t(Pr,{data:i,tableClassName:"ss-dbg-table",classPrefix:"ss-dbg"}):t("div",{className:"ss-dbg-empty",children:"Diagnostics not available"})}const Or=Object.freeze(Object.defineProperty({__proto__:null,InternalsTab:Ht,default:Ht},Symbol.toStringTag,{value:"Module"}));function zt({pane:e,options:n}){({...n});const{data:r,isLoading:s,error:i,clearData:l}=F(e.endpoint.replace(/^\//,""),{...n,debugEndpoint:""}),[o,h]=x(""),c=T(()=>{if(!r)return[];const u=e.dataKey||e.id;let f=r;for(const _ of u.split("."))f=f?.[_];return Array.isArray(f)?f:[]},[r,e.dataKey,e.id]),a=T(()=>{if(!o)return c;const u=o.toLowerCase(),f=e.columns.filter(_=>_.searchable).map(_=>_.key);return f.length===0?c:c.filter(_=>f.some(m=>{const y=_[m];return y!==null&&String(y).toLowerCase().includes(u)}))},[c,o,e.columns]),p=(u,f)=>{if(u==null)return t("span",{className:"ss-dbg-c-dim",children:"-"});switch(f.format||"text"){case"time":return t("span",{className:"ss-dbg-event-time",title:V(u),children:typeof u=="number"?R(u):String(u)});case"timeAgo":return t("span",{className:"ss-dbg-event-time",title:V(u),children:R(u)});case"duration":{const m=typeof u=="number"?u:parseFloat(String(u));return isNaN(m)?String(u):t("span",{className:`ss-dbg-duration ${Q(m)==="very-slow"?"ss-dbg-very-slow":Q(m)==="slow"?"ss-dbg-slow":""}`,children:j(m)})}case"method":return t("span",{className:`ss-dbg-method ss-dbg-method-${String(u).toLowerCase()}`,children:String(u)});case"json":{let m=u;if(typeof u=="string")try{m=JSON.parse(u)}catch{}return pe(m,80)}case"badge":{const m=String(u).toLowerCase(),b=(f.badgeColorMap||{})[m]||"muted";return t("span",{className:`ss-dbg-badge ss-dbg-badge-${b}`,children:String(u)})}default:return String(u)}},d=W([a]);return s&&!r?t("div",{className:"ss-dbg-empty",children:["Loading ",e.label,"..."]}):i?t("div",{className:"ss-dbg-empty",children:["Error: ",i.message]}):t("div",{children:[e.search&&t("div",{className:"ss-dbg-search-bar",children:[t("input",{type:"text",className:"ss-dbg-search",placeholder:e.search.placeholder,value:o,onChange:u=>h(u.target.value)}),t("span",{className:"ss-dbg-summary",children:[a.length," items"]}),e.clearable&&t("button",{type:"button",className:"ss-dbg-btn-clear",onClick:l,children:"Clear"})]}),a.length===0?t("div",{className:"ss-dbg-empty",children:"No data"}):t("table",{ref:d,className:"ss-dbg-table",children:[t("thead",{children:t("tr",{children:e.columns.map(u=>t("th",{children:u.label},u.key))})}),t("tbody",{children:a.map((u,f)=>t("tr",{children:e.columns.map(_=>t("td",{children:p(u[_.key],_)},_.key))},u.id??f))})]})]})}const Ir=Object.freeze(Object.defineProperty({__proto__:null,CustomPaneTab:zt,default:zt},Symbol.toStringTag,{value:"Module"}))})();