@zintrust/core 0.1.42 → 0.1.43

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 (365) hide show
  1. package/app/Controllers/AuthController.d.ts +10 -0
  2. package/app/Controllers/AuthController.d.ts.map +1 -0
  3. package/app/Controllers/AuthController.js +201 -0
  4. package/app/Controllers/UserController.d.ts +9 -0
  5. package/app/Controllers/UserController.d.ts.map +1 -0
  6. package/app/Controllers/UserController.js +8 -0
  7. package/app/Controllers/UserQueryBuilderController.d.ts +16 -0
  8. package/app/Controllers/UserQueryBuilderController.d.ts.map +1 -0
  9. package/app/Controllers/UserQueryBuilderController.js +404 -0
  10. package/app/Middleware/ProfilerMiddleware.d.ts +12 -0
  11. package/app/Middleware/ProfilerMiddleware.d.ts.map +1 -0
  12. package/app/Middleware/ProfilerMiddleware.js +47 -0
  13. package/app/Middleware/index.d.ts +59 -0
  14. package/app/Middleware/index.d.ts.map +1 -0
  15. package/app/Middleware/index.js +215 -0
  16. package/app/Models/Post.d.ts +14 -0
  17. package/app/Models/Post.d.ts.map +1 -0
  18. package/app/Models/Post.js +27 -0
  19. package/app/Models/User.d.ts +14 -0
  20. package/app/Models/User.d.ts.map +1 -0
  21. package/app/Models/User.js +44 -0
  22. package/app/Schedules/JobTracking.d.ts +3 -0
  23. package/app/Schedules/JobTracking.d.ts.map +1 -0
  24. package/app/Schedules/JobTracking.js +13 -0
  25. package/app/Schedules/index.d.ts +2 -0
  26. package/app/Schedules/index.d.ts.map +1 -0
  27. package/app/Schedules/index.js +1 -0
  28. package/app/Toolkit/Broadcast/sendBroadcast.d.ts +6 -0
  29. package/app/Toolkit/Broadcast/sendBroadcast.d.ts.map +1 -0
  30. package/app/Toolkit/Broadcast/sendBroadcast.js +5 -0
  31. package/app/Toolkit/Mail/sendWelcomeEmail.d.ts +6 -0
  32. package/app/Toolkit/Mail/sendWelcomeEmail.d.ts.map +1 -0
  33. package/app/Toolkit/Mail/sendWelcomeEmail.js +20 -0
  34. package/app/Toolkit/Notification/sendSlackNotification.d.ts +8 -0
  35. package/app/Toolkit/Notification/sendSlackNotification.d.ts.map +1 -0
  36. package/app/Toolkit/Notification/sendSlackNotification.js +5 -0
  37. package/app/Toolkit/Notification/sendSms.d.ts +6 -0
  38. package/app/Toolkit/Notification/sendSms.d.ts.map +1 -0
  39. package/app/Toolkit/Notification/sendSms.js +5 -0
  40. package/app/Types/controller.d.ts +42 -0
  41. package/app/Types/controller.d.ts.map +1 -0
  42. package/app/Types/controller.js +1 -0
  43. package/config/broadcast.d.ts +38 -0
  44. package/config/broadcast.d.ts.map +1 -0
  45. package/config/broadcast.js +37 -0
  46. package/config/cache.d.ts +40 -0
  47. package/config/cache.d.ts.map +1 -0
  48. package/config/cache.js +39 -0
  49. package/config/database.d.ts +58 -0
  50. package/config/database.d.ts.map +1 -0
  51. package/config/database.js +65 -0
  52. package/config/mail.d.ts +51 -0
  53. package/config/mail.d.ts.map +1 -0
  54. package/config/mail.js +69 -0
  55. package/config/middleware.d.ts +11 -0
  56. package/config/middleware.d.ts.map +1 -0
  57. package/config/middleware.js +30 -0
  58. package/config/notification.d.ts +33 -0
  59. package/config/notification.d.ts.map +1 -0
  60. package/config/notification.js +33 -0
  61. package/config/queue.d.ts +55 -0
  62. package/config/queue.d.ts.map +1 -0
  63. package/config/queue.js +87 -0
  64. package/config/storage.d.ts +59 -0
  65. package/config/storage.d.ts.map +1 -0
  66. package/config/storage.js +59 -0
  67. package/config/workers.d.ts +54 -0
  68. package/config/workers.d.ts.map +1 -0
  69. package/config/workers.js +83 -0
  70. package/package.json +11 -5
  71. package/packages/cloudflare-d1-proxy/src/index.d.ts +48 -0
  72. package/packages/cloudflare-d1-proxy/src/index.d.ts.map +1 -0
  73. package/packages/cloudflare-d1-proxy/src/index.js +387 -0
  74. package/packages/cloudflare-kv-proxy/src/index.d.ts +44 -0
  75. package/packages/cloudflare-kv-proxy/src/index.d.ts.map +1 -0
  76. package/packages/cloudflare-kv-proxy/src/index.js +325 -0
  77. package/packages/queue-monitor/src/QueueMonitoringService.d.ts +35 -0
  78. package/packages/queue-monitor/src/QueueMonitoringService.d.ts.map +1 -0
  79. package/packages/queue-monitor/src/QueueMonitoringService.js +194 -0
  80. package/packages/queue-monitor/src/connection.d.ts +3 -0
  81. package/packages/queue-monitor/src/connection.d.ts.map +1 -0
  82. package/packages/queue-monitor/src/connection.js +1 -0
  83. package/packages/queue-monitor/src/dashboard-ui.d.ts +7 -0
  84. package/packages/queue-monitor/src/dashboard-ui.d.ts.map +1 -0
  85. package/packages/queue-monitor/src/dashboard-ui.js +997 -0
  86. package/packages/queue-monitor/src/driver.d.ts +15 -0
  87. package/packages/queue-monitor/src/driver.d.ts.map +1 -0
  88. package/packages/queue-monitor/src/driver.js +115 -0
  89. package/packages/queue-monitor/src/index.d.ts +71 -0
  90. package/packages/queue-monitor/src/index.d.ts.map +1 -0
  91. package/packages/queue-monitor/src/index.js +296 -0
  92. package/packages/queue-monitor/src/metrics.d.ts +27 -0
  93. package/packages/queue-monitor/src/metrics.d.ts.map +1 -0
  94. package/packages/queue-monitor/src/metrics.js +92 -0
  95. package/packages/queue-monitor/src/worker.d.ts +8 -0
  96. package/packages/queue-monitor/src/worker.d.ts.map +1 -0
  97. package/packages/queue-monitor/src/worker.js +35 -0
  98. package/packages/queue-redis/src/BullMQRedisQueue.d.ts +26 -0
  99. package/packages/queue-redis/src/BullMQRedisQueue.d.ts.map +1 -0
  100. package/packages/queue-redis/src/BullMQRedisQueue.js +463 -0
  101. package/packages/queue-redis/src/HttpQueueDriver.d.ts +18 -0
  102. package/packages/queue-redis/src/HttpQueueDriver.d.ts.map +1 -0
  103. package/packages/queue-redis/src/HttpQueueDriver.js +249 -0
  104. package/packages/queue-redis/src/QueueHttpGateway.d.ts +16 -0
  105. package/packages/queue-redis/src/QueueHttpGateway.d.ts.map +1 -0
  106. package/packages/queue-redis/src/QueueHttpGateway.js +217 -0
  107. package/packages/queue-redis/src/RedisPublishClient.d.ts +14 -0
  108. package/packages/queue-redis/src/RedisPublishClient.d.ts.map +1 -0
  109. package/packages/queue-redis/src/RedisPublishClient.js +251 -0
  110. package/packages/queue-redis/src/index.d.ts +12 -0
  111. package/packages/queue-redis/src/index.d.ts.map +1 -0
  112. package/packages/queue-redis/src/index.js +10 -0
  113. package/packages/queue-redis/src/register.d.ts +6 -0
  114. package/packages/queue-redis/src/register.d.ts.map +1 -0
  115. package/packages/queue-redis/src/register.js +21 -0
  116. package/packages/workers/migrations/20260119100000_create_zintrust_workers_table.d.ts +11 -0
  117. package/packages/workers/migrations/20260119100000_create_zintrust_workers_table.d.ts.map +1 -0
  118. package/packages/workers/migrations/20260119100000_create_zintrust_workers_table.js +32 -0
  119. package/packages/workers/migrations/20260123180000_create_queue_jobs_table.d.ts +11 -0
  120. package/packages/workers/migrations/20260123180000_create_queue_jobs_table.d.ts.map +1 -0
  121. package/packages/workers/migrations/20260123180000_create_queue_jobs_table.js +46 -0
  122. package/packages/workers/migrations/20260213142000_create_zintrust_job_tracking_tables.d.ts +7 -0
  123. package/packages/workers/migrations/20260213142000_create_zintrust_job_tracking_tables.d.ts.map +1 -0
  124. package/packages/workers/migrations/20260213142000_create_zintrust_job_tracking_tables.js +44 -0
  125. package/packages/workers/migrations/20260213183000_expand_zintrust_job_tracking_reliability_tables.d.ts +7 -0
  126. package/packages/workers/migrations/20260213183000_expand_zintrust_job_tracking_reliability_tables.d.ts.map +1 -0
  127. package/packages/workers/migrations/20260213183000_expand_zintrust_job_tracking_reliability_tables.js +104 -0
  128. package/packages/workers/src/AnomalyDetection.d.ts +107 -0
  129. package/packages/workers/src/AnomalyDetection.d.ts.map +1 -0
  130. package/packages/workers/src/AnomalyDetection.js +329 -0
  131. package/packages/workers/src/AutoScaler.d.ts +128 -0
  132. package/packages/workers/src/AutoScaler.d.ts.map +1 -0
  133. package/packages/workers/src/AutoScaler.js +425 -0
  134. package/packages/workers/src/BroadcastWorker.d.ts +24 -0
  135. package/packages/workers/src/BroadcastWorker.d.ts.map +1 -0
  136. package/packages/workers/src/BroadcastWorker.js +24 -0
  137. package/packages/workers/src/CanaryController.d.ts +104 -0
  138. package/packages/workers/src/CanaryController.d.ts.map +1 -0
  139. package/packages/workers/src/CanaryController.js +424 -0
  140. package/packages/workers/src/ChaosEngineering.d.ts +80 -0
  141. package/packages/workers/src/ChaosEngineering.d.ts.map +1 -0
  142. package/packages/workers/src/ChaosEngineering.js +229 -0
  143. package/packages/workers/src/CircuitBreaker.d.ts +107 -0
  144. package/packages/workers/src/CircuitBreaker.d.ts.map +1 -0
  145. package/packages/workers/src/CircuitBreaker.js +374 -0
  146. package/packages/workers/src/ClusterLock.d.ts +91 -0
  147. package/packages/workers/src/ClusterLock.d.ts.map +1 -0
  148. package/packages/workers/src/ClusterLock.js +397 -0
  149. package/packages/workers/src/ComplianceManager.d.ts +178 -0
  150. package/packages/workers/src/ComplianceManager.d.ts.map +1 -0
  151. package/packages/workers/src/ComplianceManager.js +556 -0
  152. package/packages/workers/src/DatacenterOrchestrator.d.ts +134 -0
  153. package/packages/workers/src/DatacenterOrchestrator.d.ts.map +1 -0
  154. package/packages/workers/src/DatacenterOrchestrator.js +404 -0
  155. package/packages/workers/src/DeadLetterQueue.d.ts +123 -0
  156. package/packages/workers/src/DeadLetterQueue.d.ts.map +1 -0
  157. package/packages/workers/src/DeadLetterQueue.js +544 -0
  158. package/packages/workers/src/HealthMonitor.d.ts +43 -0
  159. package/packages/workers/src/HealthMonitor.d.ts.map +1 -0
  160. package/packages/workers/src/HealthMonitor.js +312 -0
  161. package/packages/workers/src/MultiQueueWorker.d.ts +90 -0
  162. package/packages/workers/src/MultiQueueWorker.d.ts.map +1 -0
  163. package/packages/workers/src/MultiQueueWorker.js +282 -0
  164. package/packages/workers/src/NotificationWorker.d.ts +24 -0
  165. package/packages/workers/src/NotificationWorker.d.ts.map +1 -0
  166. package/packages/workers/src/NotificationWorker.js +23 -0
  167. package/packages/workers/src/Observability.d.ts +154 -0
  168. package/packages/workers/src/Observability.d.ts.map +1 -0
  169. package/packages/workers/src/Observability.js +538 -0
  170. package/packages/workers/src/PluginManager.d.ts +124 -0
  171. package/packages/workers/src/PluginManager.d.ts.map +1 -0
  172. package/packages/workers/src/PluginManager.js +392 -0
  173. package/packages/workers/src/PriorityQueue.d.ts +118 -0
  174. package/packages/workers/src/PriorityQueue.d.ts.map +1 -0
  175. package/packages/workers/src/PriorityQueue.js +276 -0
  176. package/packages/workers/src/ResourceMonitor.d.ts +165 -0
  177. package/packages/workers/src/ResourceMonitor.d.ts.map +1 -0
  178. package/packages/workers/src/ResourceMonitor.js +632 -0
  179. package/packages/workers/src/SLAMonitor.d.ts +111 -0
  180. package/packages/workers/src/SLAMonitor.d.ts.map +1 -0
  181. package/packages/workers/src/SLAMonitor.js +274 -0
  182. package/packages/workers/src/WorkerFactory.d.ts +218 -0
  183. package/packages/workers/src/WorkerFactory.d.ts.map +1 -0
  184. package/packages/workers/src/WorkerFactory.js +2253 -0
  185. package/packages/workers/src/WorkerInit.d.ts +86 -0
  186. package/packages/workers/src/WorkerInit.d.ts.map +1 -0
  187. package/packages/workers/src/WorkerInit.js +307 -0
  188. package/packages/workers/src/WorkerMetrics.d.ts +116 -0
  189. package/packages/workers/src/WorkerMetrics.d.ts.map +1 -0
  190. package/packages/workers/src/WorkerMetrics.js +570 -0
  191. package/packages/workers/src/WorkerRegistry.d.ts +152 -0
  192. package/packages/workers/src/WorkerRegistry.d.ts.map +1 -0
  193. package/packages/workers/src/WorkerRegistry.js +396 -0
  194. package/packages/workers/src/WorkerShutdown.d.ts +70 -0
  195. package/packages/workers/src/WorkerShutdown.d.ts.map +1 -0
  196. package/packages/workers/src/WorkerShutdown.js +185 -0
  197. package/packages/workers/src/WorkerVersioning.d.ts +108 -0
  198. package/packages/workers/src/WorkerVersioning.d.ts.map +1 -0
  199. package/packages/workers/src/WorkerVersioning.js +300 -0
  200. package/packages/workers/src/config/workerConfig.d.ts +5 -0
  201. package/packages/workers/src/config/workerConfig.d.ts.map +1 -0
  202. package/packages/workers/src/config/workerConfig.js +25 -0
  203. package/packages/workers/src/createQueueWorker.d.ts +26 -0
  204. package/packages/workers/src/createQueueWorker.d.ts.map +1 -0
  205. package/packages/workers/src/createQueueWorker.js +367 -0
  206. package/packages/workers/src/dashboard/index.d.ts +2 -0
  207. package/packages/workers/src/dashboard/index.d.ts.map +1 -0
  208. package/packages/workers/src/dashboard/index.js +1 -0
  209. package/packages/workers/src/dashboard/types.d.ts +123 -0
  210. package/packages/workers/src/dashboard/types.d.ts.map +1 -0
  211. package/packages/workers/src/dashboard/types.js +1 -0
  212. package/packages/workers/src/dashboard/workers-api.d.ts +5 -0
  213. package/packages/workers/src/dashboard/workers-api.d.ts.map +1 -0
  214. package/packages/workers/src/dashboard/workers-api.js +738 -0
  215. package/packages/workers/src/helper/index.d.ts +6 -0
  216. package/packages/workers/src/helper/index.d.ts.map +1 -0
  217. package/packages/workers/src/helper/index.js +10 -0
  218. package/packages/workers/src/http/WorkerApiController.d.ts +39 -0
  219. package/packages/workers/src/http/WorkerApiController.d.ts.map +1 -0
  220. package/packages/workers/src/http/WorkerApiController.js +313 -0
  221. package/packages/workers/src/http/WorkerController.d.ts +375 -0
  222. package/packages/workers/src/http/WorkerController.d.ts.map +1 -0
  223. package/packages/workers/src/http/WorkerController.js +1454 -0
  224. package/packages/workers/src/http/WorkerMonitoringService.d.ts +12 -0
  225. package/packages/workers/src/http/WorkerMonitoringService.d.ts.map +1 -0
  226. package/packages/workers/src/http/WorkerMonitoringService.js +89 -0
  227. package/packages/workers/src/http/middleware/CustomValidation.d.ts +93 -0
  228. package/packages/workers/src/http/middleware/CustomValidation.d.ts.map +1 -0
  229. package/packages/workers/src/http/middleware/CustomValidation.js +270 -0
  230. package/packages/workers/src/http/middleware/DatacenterValidator.d.ts +4 -0
  231. package/packages/workers/src/http/middleware/DatacenterValidator.d.ts.map +1 -0
  232. package/packages/workers/src/http/middleware/DatacenterValidator.js +94 -0
  233. package/packages/workers/src/http/middleware/EditWorkerValidation.d.ts +8 -0
  234. package/packages/workers/src/http/middleware/EditWorkerValidation.d.ts.map +1 -0
  235. package/packages/workers/src/http/middleware/EditWorkerValidation.js +56 -0
  236. package/packages/workers/src/http/middleware/FeaturesValidator.d.ts +4 -0
  237. package/packages/workers/src/http/middleware/FeaturesValidator.d.ts.map +1 -0
  238. package/packages/workers/src/http/middleware/FeaturesValidator.js +60 -0
  239. package/packages/workers/src/http/middleware/InfrastructureValidator.d.ts +32 -0
  240. package/packages/workers/src/http/middleware/InfrastructureValidator.d.ts.map +1 -0
  241. package/packages/workers/src/http/middleware/InfrastructureValidator.js +226 -0
  242. package/packages/workers/src/http/middleware/OptionsValidator.d.ts +4 -0
  243. package/packages/workers/src/http/middleware/OptionsValidator.d.ts.map +1 -0
  244. package/packages/workers/src/http/middleware/OptionsValidator.js +112 -0
  245. package/packages/workers/src/http/middleware/PayloadSanitizer.d.ts +8 -0
  246. package/packages/workers/src/http/middleware/PayloadSanitizer.d.ts.map +1 -0
  247. package/packages/workers/src/http/middleware/PayloadSanitizer.js +42 -0
  248. package/packages/workers/src/http/middleware/ProcessorPathSanitizer.d.ts +4 -0
  249. package/packages/workers/src/http/middleware/ProcessorPathSanitizer.d.ts.map +1 -0
  250. package/packages/workers/src/http/middleware/ProcessorPathSanitizer.js +140 -0
  251. package/packages/workers/src/http/middleware/QueueNameSanitizer.d.ts +4 -0
  252. package/packages/workers/src/http/middleware/QueueNameSanitizer.d.ts.map +1 -0
  253. package/packages/workers/src/http/middleware/QueueNameSanitizer.js +45 -0
  254. package/packages/workers/src/http/middleware/ValidateDriver.d.ts +8 -0
  255. package/packages/workers/src/http/middleware/ValidateDriver.d.ts.map +1 -0
  256. package/packages/workers/src/http/middleware/ValidateDriver.js +20 -0
  257. package/packages/workers/src/http/middleware/VersionSanitizer.d.ts +4 -0
  258. package/packages/workers/src/http/middleware/VersionSanitizer.d.ts.map +1 -0
  259. package/packages/workers/src/http/middleware/VersionSanitizer.js +25 -0
  260. package/packages/workers/src/http/middleware/WorkerNameSanitizer.d.ts +4 -0
  261. package/packages/workers/src/http/middleware/WorkerNameSanitizer.d.ts.map +1 -0
  262. package/packages/workers/src/http/middleware/WorkerNameSanitizer.js +46 -0
  263. package/packages/workers/src/http/middleware/WorkerValidationChain.d.ts +28 -0
  264. package/packages/workers/src/http/middleware/WorkerValidationChain.d.ts.map +1 -0
  265. package/packages/workers/src/http/middleware/WorkerValidationChain.js +186 -0
  266. package/packages/workers/src/index.d.ts +47 -0
  267. package/packages/workers/src/index.d.ts.map +1 -0
  268. package/packages/workers/src/index.js +48 -0
  269. package/packages/workers/src/routes/workers.d.ts +13 -0
  270. package/packages/workers/src/routes/workers.d.ts.map +1 -0
  271. package/packages/workers/src/routes/workers.js +126 -0
  272. package/packages/workers/src/storage/WorkerStore.d.ts +52 -0
  273. package/packages/workers/src/storage/WorkerStore.d.ts.map +1 -0
  274. package/packages/workers/src/storage/WorkerStore.js +259 -0
  275. package/packages/workers/src/telemetry/api/TelemetryAPI.d.ts +47 -0
  276. package/packages/workers/src/telemetry/api/TelemetryAPI.d.ts.map +1 -0
  277. package/packages/workers/src/telemetry/api/TelemetryAPI.js +219 -0
  278. package/packages/workers/src/telemetry/api/TelemetryMonitoringService.d.ts +18 -0
  279. package/packages/workers/src/telemetry/api/TelemetryMonitoringService.d.ts.map +1 -0
  280. package/packages/workers/src/telemetry/api/TelemetryMonitoringService.js +140 -0
  281. package/packages/workers/src/telemetry/components/AlertPanel.d.ts +2 -0
  282. package/packages/workers/src/telemetry/components/AlertPanel.d.ts.map +1 -0
  283. package/packages/workers/src/telemetry/components/AlertPanel.js +13 -0
  284. package/packages/workers/src/telemetry/components/CostTracking.d.ts +2 -0
  285. package/packages/workers/src/telemetry/components/CostTracking.d.ts.map +1 -0
  286. package/packages/workers/src/telemetry/components/CostTracking.js +14 -0
  287. package/packages/workers/src/telemetry/components/ResourceUsageChart.d.ts +2 -0
  288. package/packages/workers/src/telemetry/components/ResourceUsageChart.d.ts.map +1 -0
  289. package/packages/workers/src/telemetry/components/ResourceUsageChart.js +11 -0
  290. package/packages/workers/src/telemetry/components/WorkerHealthChart.d.ts +2 -0
  291. package/packages/workers/src/telemetry/components/WorkerHealthChart.d.ts.map +1 -0
  292. package/packages/workers/src/telemetry/components/WorkerHealthChart.js +11 -0
  293. package/packages/workers/src/telemetry/index.d.ts +16 -0
  294. package/packages/workers/src/telemetry/index.d.ts.map +1 -0
  295. package/packages/workers/src/telemetry/index.js +60 -0
  296. package/packages/workers/src/telemetry/routes/dashboard.d.ts +7 -0
  297. package/packages/workers/src/telemetry/routes/dashboard.d.ts.map +1 -0
  298. package/packages/workers/src/telemetry/routes/dashboard.js +608 -0
  299. package/packages/workers/src/type.d.ts +77 -0
  300. package/packages/workers/src/type.d.ts.map +1 -0
  301. package/packages/workers/src/type.js +1 -0
  302. package/packages/workers/src/ui/router/EmbeddedAssets.d.ts +5 -0
  303. package/packages/workers/src/ui/router/EmbeddedAssets.d.ts.map +1 -0
  304. package/packages/workers/src/ui/router/EmbeddedAssets.js +13 -0
  305. package/packages/workers/src/ui/router/ui.d.ts +4 -0
  306. package/packages/workers/src/ui/router/ui.d.ts.map +1 -0
  307. package/packages/workers/src/ui/router/ui.js +208 -0
  308. package/packages/workers/src/ui/types/worker-ui.d.ts +230 -0
  309. package/packages/workers/src/ui/types/worker-ui.d.ts.map +1 -0
  310. package/packages/workers/src/ui/types/worker-ui.js +5 -0
  311. package/routes/api.d.ts +7 -0
  312. package/routes/api.d.ts.map +1 -0
  313. package/routes/api.js +129 -0
  314. package/routes/broadcast.d.ts +9 -0
  315. package/routes/broadcast.d.ts.map +1 -0
  316. package/routes/broadcast.js +27 -0
  317. package/routes/storage.d.ts +4 -0
  318. package/routes/storage.d.ts.map +1 -0
  319. package/routes/storage.js +35 -0
  320. package/src/cache/Cache.d.ts.map +1 -1
  321. package/src/cache/Cache.js +40 -8
  322. package/src/cache/drivers/KVRemoteDriver.d.ts +1 -1
  323. package/src/cache/drivers/KVRemoteDriver.d.ts.map +1 -1
  324. package/src/cache/drivers/KVRemoteDriver.js +259 -44
  325. package/src/cache/drivers/MemoryDriver.d.ts.map +1 -1
  326. package/src/cache/drivers/MemoryDriver.js +10 -2
  327. package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
  328. package/src/cache/drivers/RedisDriver.js +256 -33
  329. package/src/cli/commands/InitContainerCommand.js +10 -10
  330. package/src/cli/commands/NewCommand.d.ts.map +1 -1
  331. package/src/cli/commands/NewCommand.js +33 -0
  332. package/src/cli/commands/StartCommand.d.ts.map +1 -1
  333. package/src/cli/commands/StartCommand.js +23 -1
  334. package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
  335. package/src/cli/scaffolding/ProjectScaffolder.js +65 -73
  336. package/src/cli/utils/DistPackager.d.ts.map +1 -1
  337. package/src/cli/utils/DistPackager.js +25 -0
  338. package/src/cli/utils/EnvFileLoader.d.ts +1 -0
  339. package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
  340. package/src/cli/utils/EnvFileLoader.js +14 -0
  341. package/src/common/RemoteSignedJson.d.ts.map +1 -1
  342. package/src/common/RemoteSignedJson.js +9 -2
  343. package/src/config/cache.js +1 -1
  344. package/src/config/env.d.ts +7 -0
  345. package/src/config/env.d.ts.map +1 -1
  346. package/src/config/env.js +8 -0
  347. package/src/config/queue.js +1 -1
  348. package/src/functions/cloudflare.d.ts.map +1 -1
  349. package/src/functions/cloudflare.js +4 -2
  350. package/src/index.js +3 -3
  351. package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -1
  352. package/src/middleware/JwtAuthMiddleware.js +11 -5
  353. package/src/runtime/RuntimeAdapter.d.ts.map +1 -1
  354. package/src/runtime/RuntimeAdapter.js +30 -12
  355. package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
  356. package/src/runtime/adapters/CloudflareAdapter.js +15 -4
  357. package/src/scheduler/Schedule.js +1 -1
  358. package/src/scheduler/leader/SchedulerLeader.js +1 -1
  359. package/src/schedules/job-tracking-cleanup.js +1 -1
  360. package/src/security/TokenRevocation.d.ts +19 -2
  361. package/src/security/TokenRevocation.d.ts.map +1 -1
  362. package/src/security/TokenRevocation.js +558 -30
  363. package/src/templates/project/basic/app/Controllers/AuthController.ts.tpl +11 -3
  364. package/src/templates/project/basic/config/middleware.ts.tpl +23 -22
  365. package/src/templates/project/basic/wrangler.jsonc.tpl +28 -0
@@ -0,0 +1,997 @@
1
+ const getRootAndThemeVariables = () => `
2
+ :root {
3
+ --bg: #0b1220;
4
+ --card: rgba(15, 23, 42, 0.65);
5
+ --border: #334155;
6
+ --text: #e2e8f0;
7
+ --muted: #94a3b8;
8
+ --accent: #bae6fd;
9
+ --accent2: #e2e8f0;
10
+ --danger: #ef4444;
11
+ --success: #10b981;
12
+ }
13
+
14
+ html[data-theme="light"] {
15
+ --bg: #f8fafc;
16
+ --card: #ffffff;
17
+ --border: #e2e8f0;
18
+ --text: #0f172a;
19
+ --muted: #475569;
20
+ --accent: #0284c7;
21
+ --accent2: #0f172a;
22
+ --danger: #dc2626;
23
+ --success: #16a34a;
24
+ }`;
25
+ const getLogoAndLayoutStyles = () => `
26
+ .logo-frame {
27
+ width: 34px;
28
+ height: 34px;
29
+ border-radius: 9px;
30
+ border: 1px solid rgba(14, 165, 233, 0.35);
31
+ background: linear-gradient(180deg, rgba(14, 165, 233, 0.18), rgba(2, 132, 199, 0.1));
32
+ display: grid;
33
+ place-items: center;
34
+ overflow: hidden;
35
+ }
36
+
37
+ .logo-img {
38
+ width: 26px;
39
+ height: 26px;
40
+ display: block;
41
+ }
42
+
43
+ html,
44
+ body {
45
+ height: 100%;
46
+ margin: 0;
47
+ padding: 0;
48
+ background: var(--bg);
49
+ color: var(--text);
50
+ font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
51
+ }
52
+
53
+ .page { min-height: 100%; padding: 24px; }
54
+ .shell { max-width: 1080px; margin: 0 auto; }
55
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
56
+
57
+ .tile {
58
+ border: 1px solid var(--border);
59
+ background: var(--card);
60
+ border-radius: 12px;
61
+ padding: 20px;
62
+ }`;
63
+ const getDashboardComponentStyles = () => `
64
+ header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; }
65
+ .brand { display: flex; gap: 12px; align-items: center; }
66
+ .brand b { font-size: 16px; color: var(--text); display: block; }
67
+ .brand span { font-size: 13px; color: var(--muted); }
68
+
69
+ select { background: var(--bg); color: var(--text); border: 1px solid var(--border); padding: 6px 10px; border-radius: 6px; font-size: 13px; outline: none; }
70
+ select:focus { border-color: var(--accent); }
71
+
72
+ table { width: 100%; border-collapse: collapse; margin-top: 4px; }
73
+ th, td { text-align: left; padding: 12px; border-bottom: 1px solid var(--border); font-size: 14px; }
74
+ th { color: var(--muted); font-size: 11px; text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em; }
75
+ tr:last-child td { border-bottom: none; }
76
+ .expandable-row { cursor: pointer; transition: background 0.2s; }
77
+ .expandable-row:hover { background: rgba(255,255,255,0.03); }
78
+ .expandable-row code { cursor: pointer; color: var(--accent); }
79
+ .expandable-row code:hover { text-decoration: underline; }
80
+ .detail-row { background: rgba(0,0,0,0.2); border-bottom: 1px solid var(--border); }
81
+ .detail-cell { padding: 16px 20px !important; }
82
+ .detail-content { font-family: monospace; font-size: 12px; line-height: 1.6; }
83
+ .detail-content pre { margin: 0; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; }
84
+ .expand-icon { display: inline-block; margin-right: 6px; transition: transform 0.2s; user-select: none; }
85
+ .expand-icon.expanded { transform: rotate(90deg); }
86
+
87
+ .stat-value { font-size: 28px; font-weight: 800; color: var(--text); margin-top: 8px; line-height: 1; }
88
+ .stat-label { font-size: 12px; color: var(--muted); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; }`;
89
+ const getStatusBadgeStyles = () => `
90
+ .status-badge { padding: 4px 10px; border-radius: 999px; font-size: 11px; font-weight: 800; display: inline-flex; align-items: center; letter-spacing: 0.02em; }
91
+ .status-completed { background: rgba(16, 185, 129, 0.1); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.2); }
92
+ .status-failed { background: rgba(239, 68, 68, 0.1); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.2); }
93
+ .status-active { background: rgba(59, 130, 246, 0.1); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.2); }
94
+ .status-waiting { background: rgba(250, 204, 21, 0.1); color: #facc15; border: 1px solid rgba(250, 204, 21, 0.2); }
95
+ .status-delayed { background: rgba(168, 85, 247, 0.1); color: #c084fc; border: 1px solid rgba(168, 85, 247, 0.2); }
96
+ .status-paused { background: rgba(148, 163, 184, 0.1); color: #94a3b8; border: 1px solid rgba(148, 163, 184, 0.2); }`;
97
+ const getInteractiveStyles = () => `
98
+ .refresh-btn { background: rgba(255,255,255,0.03); color: var(--text); border: 1px solid var(--border); padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; transition: all 0.2s; }
99
+ .refresh-btn:hover { background: rgba(255,255,255,0.08); border-color: var(--muted); }
100
+
101
+ .nav-links { display: flex; gap: 8px; flex-wrap: wrap; }
102
+ .nav-link { text-decoration: none; color: var(--text); border: 1px solid var(--border); padding: 6px 10px; border-radius: 6px; font-size: 12px; font-weight: 600; transition: all 0.2s; }
103
+ .nav-link:hover { border-color: var(--accent); color: var(--accent); }
104
+
105
+ html[data-theme="light"] .refresh-btn { background: rgba(2, 132, 199, 0.08); }
106
+ html[data-theme="light"] .refresh-btn:hover { background: rgba(2, 132, 199, 0.16); }
107
+
108
+ .retry-btn { background: rgba(59, 130, 246, 0.1); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 11px; font-weight: 600; transition: all 0.2s; }
109
+ .retry-btn:hover { background: rgba(59, 130, 246, 0.2); transform: scale(1.05); }
110
+ .retry-btn:disabled { opacity: 0.5; cursor: not-allowed; }
111
+
112
+ #error-container { display: none; margin-bottom: 2rem; padding: 1rem; background: rgba(239, 68, 68, 0.1); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.2); border-radius: 0.5rem; font-size: 13px; font-weight: 600; }
113
+ code { background: rgba(0,0,0,0.3); padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 12px; color: var(--accent); border: 1px solid var(--border); }
114
+
115
+ .stat-header { display: flex; align-items: center; gap: 6px; }
116
+ .info-icon { width: 16px; height: 16px; border-radius: 50%; background: rgba(59, 130, 246, 0.2); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; cursor: help; transition: all 0.2s; }
117
+ .info-icon:hover { background: rgba(59, 130, 246, 0.3); transform: scale(1.1); }
118
+ .tooltip { position: fixed; background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 12px 16px; font-size: 13px; line-height: 1.6; color: var(--text); box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 1000; max-width: 320px; display: none; }
119
+ .tooltip.show { display: block; }
120
+ .tooltip-title { font-weight: 700; color: var(--accent); margin-bottom: 6px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; }`;
121
+ const getDashboardStyles = () => [
122
+ getRootAndThemeVariables(),
123
+ getLogoAndLayoutStyles(),
124
+ getDashboardComponentStyles(),
125
+ getStatusBadgeStyles(),
126
+ getInteractiveStyles(),
127
+ ].join('\n');
128
+ const getHeaderSection = () => `
129
+ <header>
130
+ <div class="brand">
131
+ <div class="logo-frame">
132
+ ${getLogoSvg()}
133
+ </div>
134
+ <div>
135
+ <b>ZinTrust</b>
136
+ <span>Queue Monitor</span>
137
+ </div>
138
+ </div>
139
+ <div style="display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; justify-content: flex-end;">
140
+ <span id="last-updated" style="color: var(--muted); font-size: 12px;"></span>
141
+ <div class="nav-links">
142
+ <a class="nav-link" href="/workers">Workers</a>
143
+ <a class="nav-link" href="/telemetry">Telemetry</a>
144
+ <a class="nav-link" href="/metrics">Metrics</a>
145
+ </div>
146
+ <button id="theme-toggle" class="refresh-btn" type="button">Light mode</button>
147
+ <button id="auto-refresh-toggle" class="refresh-btn" type="button">Pause auto refresh</button>
148
+ </div>
149
+ </header>
150
+ `;
151
+ const getLogoSvg = () => `
152
+ <svg width="26" height="26" viewBox="0 0 100 100" fill="none" class="logo-img" xmlns="http://www.w3.org/2000/svg">
153
+ <defs>
154
+ <linearGradient id="zt-g2d" x1="10" y1="50" x2="90" y2="50" gradientUnits="userSpaceOnUse">
155
+ <stop stop-color="#22c55e" />
156
+ <stop offset="1" stop-color="#38bdf8" />
157
+ </linearGradient>
158
+ </defs>
159
+ <circle cx="50" cy="50" r="34" stroke="rgba(255,255,255,0.16)" stroke-width="4" />
160
+ <ellipse cx="50" cy="50" rx="40" ry="18" stroke="url(#zt-g2d)" stroke-width="4" />
161
+ <ellipse cx="50" cy="50" rx="18" ry="40" stroke="url(#zt-g2d)" stroke-width="4" opacity="0.75" />
162
+ <circle cx="50" cy="50" r="6" fill="url(#zt-g2d)" />
163
+ <path d="M40 52C35 52 32 49 32 44C32 39 35 36 40 36H48" stroke="white" stroke-width="6" stroke-linecap="round" />
164
+ <path d="M60 48C65 48 68 51 68 56C68 61 65 64 60 64H52" stroke="white" stroke-width="6" stroke-linecap="round" />
165
+ <path d="M44 50H56" stroke="rgba(255,255,255,0.22)" stroke-width="6" stroke-linecap="round" />
166
+ </svg>
167
+ `;
168
+ const getStatsSection = () => `
169
+ <div class="grid" id="stats-grid">
170
+ <!-- Stats inserted here -->
171
+ </div>
172
+ `;
173
+ const getLocksSection = () => `
174
+ <div class="tile" style="margin-top: 24px; padding: 0;">
175
+ <div style="padding: 16px 20px; display: flex; flex-direction: column; gap: 12px; border-bottom: 1px solid var(--border);">
176
+ <div style="display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;">
177
+ <h3 style="margin: 0; font-size: 14px; font-weight: 800; color: var(--text);">Active Locks</h3>
178
+ <div style="display: flex; gap: 8px; align-items: center;">
179
+ <input id="lock-pattern" placeholder="Pattern (e.g. email-*)" style="background: var(--bg); color: var(--text); border: 1px solid var(--border); padding: 6px 10px; border-radius: 6px; font-size: 12px; min-width: 220px;" />
180
+ <button id="lock-refresh" class="refresh-btn" type="button">Refresh locks</button>
181
+ </div>
182
+ </div>
183
+ <div id="locks-summary" style="display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--muted);"></div>
184
+ <div id="locks-histogram" style="font-size: 12px;"></div>
185
+ </div>
186
+ <div style="overflow-x: auto;">
187
+ <table id="locks-table">
188
+ <thead>
189
+ <tr>
190
+ <th>Lock Key</th>
191
+ <th>TTL</th>
192
+ <th>Expires</th>
193
+ </tr>
194
+ </thead>
195
+ <tbody></tbody>
196
+ </table>
197
+ </div>
198
+ </div>
199
+ `;
200
+ const getJobsSection = () => `
201
+ <div class="tile" style="margin-top: 24px; padding: 0;">
202
+ <div style="padding: 16px 20px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border);">
203
+ <h3 style="margin: 0; font-size: 14px; font-weight: 800; color: var(--text);">Recent Jobs</h3>
204
+ <select id="queue-select">
205
+ <!-- Queues inserted here -->
206
+ </select>
207
+ </div>
208
+ <div style="overflow-x: auto;">
209
+ <table id="jobs-table">
210
+ <thead>
211
+ <tr>
212
+ <th>ID</th>
213
+ <th>Worker Name</th>
214
+ <th>Queue</th>
215
+ <th>Status</th>
216
+ <th>Attempts</th>
217
+ <th>Time</th>
218
+ <th>Action</th>
219
+ </tr>
220
+ </thead>
221
+ <tbody></tbody>
222
+ </table>
223
+ </div>
224
+ </div>
225
+ `;
226
+ const getDashboardBody = () => `
227
+ <div class="page">
228
+ <div class="shell">
229
+ ${getHeaderSection()}
230
+
231
+ <section id="error-container"></section>
232
+
233
+ ${getStatsSection()}
234
+ ${getLocksSection()}
235
+ ${getJobsSection()}
236
+ </div>
237
+ </div>
238
+ `;
239
+ const getDashboardScriptState = (options) => String.raw `
240
+ const AUTO_REFRESH = ${options.autoRefresh ? 'true' : 'false'};
241
+ const REFRESH_INTERVAL = ${Math.max(1000, Math.floor(options.refreshIntervalMs || 0))};
242
+ const API_BASE = ${JSON.stringify(options.basePath)};
243
+ const THEME_KEY = 'zintrust-queue-monitor-theme';
244
+ const AUTO_REFRESH_KEY = 'zintrust-queue-monitor-auto-refresh';
245
+ const QUEUE_KEY = 'zintrust-queue-monitor-selected-queue';
246
+ let currentQueue = localStorage.getItem(QUEUE_KEY);
247
+ let autoRefreshEnabled = AUTO_REFRESH;
248
+ let refreshTimer = null;
249
+ let eventSource = null;
250
+ let sseActive = false;
251
+ let lastSseQueue = null;
252
+ let lastSsePattern = null;
253
+ let currentTheme = null;
254
+ `;
255
+ const getDashboardScriptTheme = () => `
256
+ function getPreferredTheme() {
257
+ const stored = localStorage.getItem(THEME_KEY);
258
+ if (stored === 'light' || stored === 'dark') {
259
+ return stored;
260
+ }
261
+ const prefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;
262
+ return prefersLight ? 'light' : 'dark';
263
+ }
264
+
265
+ function updateThemeButton() {
266
+ const btn = document.getElementById('theme-toggle');
267
+ if (!btn) return;
268
+ btn.textContent = currentTheme === 'dark' ? 'Light mode' : 'Dark mode';
269
+ }
270
+
271
+ function applyTheme(nextTheme) {
272
+ currentTheme = nextTheme;
273
+ document.documentElement.setAttribute('data-theme', nextTheme);
274
+ localStorage.setItem(THEME_KEY, nextTheme);
275
+ updateThemeButton();
276
+ }
277
+
278
+ function toggleTheme() {
279
+ applyTheme(currentTheme === 'dark' ? 'light' : 'dark');
280
+ }
281
+ `;
282
+ const getDashboardScriptAutoRefresh = () => `
283
+ function updateAutoRefreshButton() {
284
+ const btn = document.getElementById('auto-refresh-toggle');
285
+ if (!btn) return;
286
+ btn.textContent = autoRefreshEnabled ? 'Pause auto refresh' : 'Resume auto refresh';
287
+ }
288
+
289
+ function startAutoRefresh() {
290
+ if (!autoRefreshEnabled || refreshTimer !== null || sseActive) return;
291
+ // Disabled HTTP polling - SSE handles all updates
292
+ // refreshTimer = setInterval(fetchData, REFRESH_INTERVAL);
293
+ console.log('HTTP auto-refresh disabled - using SSE only');
294
+ }
295
+
296
+ function stopAutoRefresh() {
297
+ if (refreshTimer === null) return;
298
+ clearInterval(refreshTimer);
299
+ refreshTimer = null;
300
+ }
301
+
302
+ function setAutoRefresh(enabled) {
303
+ autoRefreshEnabled = enabled;
304
+ localStorage.setItem(AUTO_REFRESH_KEY, String(enabled));
305
+ if (!enabled) {
306
+ if (eventSource) {
307
+ eventSource.close();
308
+ eventSource = null;
309
+ }
310
+ sseActive = false;
311
+ }
312
+
313
+ if (autoRefreshEnabled && !sseActive) {
314
+ if (window.EventSource) {
315
+ setupEventStream(currentQueue);
316
+ } else {
317
+ startAutoRefresh();
318
+ }
319
+ } else {
320
+ stopAutoRefresh();
321
+ }
322
+ updateAutoRefreshButton();
323
+ }
324
+
325
+ function toggleAutoRefresh() {
326
+ setAutoRefresh(!autoRefreshEnabled);
327
+ }
328
+ `;
329
+ const getRenderStatsFunction = () => `
330
+ function renderStats(data) {
331
+ const grid = document.getElementById('stats-grid');
332
+ grid.innerHTML = '';
333
+
334
+ const totalActive = data.queues.reduce((acc, q) => acc + q.counts.active, 0);
335
+ const totalFailed = data.queues.reduce((acc, q) => acc + q.counts.failed, 0);
336
+ const totalDelayed = data.queues.reduce((acc, q) => acc + q.counts.delayed, 0);
337
+ const totalWaiting = data.queues.reduce((acc, q) => acc + q.counts.waiting, 0);
338
+
339
+ const cards = [
340
+ {
341
+ label: 'Active Jobs',
342
+ value: totalActive,
343
+ info: 'Jobs currently being processed by workers. These are picked up from the waiting queue and are actively running.'
344
+ },
345
+ {
346
+ label: 'Failed Jobs',
347
+ value: totalFailed,
348
+ color: totalFailed > 0 ? '#f87171' : null,
349
+ info: 'Jobs that threw an error during processing and exceeded retry attempts. Check error logs for details.'
350
+ },
351
+ {
352
+ label: 'Delayed',
353
+ value: totalDelayed,
354
+ info: 'Jobs scheduled to run at a future time. They will move to waiting queue when their delay time expires.'
355
+ },
356
+ {
357
+ label: 'Waiting',
358
+ value: totalWaiting,
359
+ color: totalWaiting > 0 ? '#facc15' : null,
360
+ info: 'Jobs ready to be processed, waiting for available workers to pick them up from the queue.'
361
+ },
362
+ {
363
+ label: 'Queues',
364
+ value: data.queues.length,
365
+ info: 'Total number of active job queues in Redis. Each queue can process different types of jobs independently.'
366
+ }
367
+ ];
368
+
369
+ cards.forEach(card => {
370
+ const div = document.createElement('div');
371
+ div.className = 'tile';
372
+ const infoIcon = '<span class="info-icon" data-info="' + card.info + '">i</span>';
373
+ div.innerHTML =
374
+ '<div class="stat-header">' +
375
+ '<div class="stat-label">' + card.label + '</div>' +
376
+ infoIcon +
377
+ '</div>' +
378
+ '<div class="stat-value" style="' + (card.color ? 'color:' + card.color : '') + '">' +
379
+ card.value +
380
+ '</div>';
381
+ grid.appendChild(div);
382
+ });
383
+
384
+ document.querySelectorAll('.info-icon').forEach(icon => {
385
+ icon.addEventListener('mouseenter', showTooltip);
386
+ icon.addEventListener('mouseleave', hideTooltip);
387
+ });
388
+ }`;
389
+ const getUpdateQueueSelectFunction = () => `
390
+ function updateQueueSelect(queues) {
391
+ const select = document.getElementById('queue-select');
392
+ const currentSelection = select.value || currentQueue;
393
+ select.innerHTML = '';
394
+
395
+ if (queues.length === 0) return
396
+
397
+ queues.forEach(q => {
398
+ const opt = document.createElement('option');
399
+ opt.value = q.name;
400
+ opt.textContent = q.name + ' (' + q.counts.waiting + ' waiting, ' + q.counts.failed + ' failed)';
401
+ opt.selected = q.name === currentSelection;
402
+ select.appendChild(opt);
403
+ });
404
+ }`;
405
+ const getRenderJobsFunction = () => `
406
+ // Track expanded job IDs to preserve state during SSE updates
407
+ let expandedJobIds = new Set();
408
+
409
+ function renderJobs(jobs) {
410
+ const tbody = document.querySelector('#jobs-table tbody');
411
+
412
+ // Store currently expanded job IDs before clearing
413
+ const currentExpanded = document.querySelectorAll('.expand-icon.expanded');
414
+ currentExpanded.forEach(icon => {
415
+ const row = icon.closest('tr');
416
+ if (row) {
417
+ const jobId = row.querySelector('code')?.textContent;
418
+ if (jobId) expandedJobIds.add(jobId);
419
+ }
420
+ });
421
+
422
+ tbody.innerHTML = '';
423
+
424
+ if (!jobs || jobs.length === 0) {
425
+ tbody.innerHTML = '<tr><td colspan="7" style="text-align:center; color: var(--muted)">No recent jobs found</td></tr>';
426
+ return;
427
+ }
428
+
429
+ jobs.forEach((job, idx) => {
430
+ const tr = document.createElement('tr');
431
+ tr.className = 'expandable-row';
432
+ tr.dataset.jobIndex = idx;
433
+ const status = (job.status || (job.failedReason ? 'failed' : 'completed')).toLowerCase();
434
+ const statusMap = {
435
+ failed: { label: 'Failed', cls: 'status-failed' },
436
+ completed: { label: 'Completed', cls: 'status-completed' },
437
+ active: { label: 'Active', cls: 'status-active' },
438
+ waiting: { label: 'Waiting', cls: 'status-waiting' },
439
+ delayed: { label: 'Delayed', cls: 'status-delayed' },
440
+ paused: { label: 'Paused', cls: 'status-paused' }
441
+ };
442
+ const statusInfo = statusMap[status] || statusMap.completed;
443
+
444
+ const retryBtn = status === 'failed'
445
+ ? '<button class="retry-btn" onclick="retryJob(' + "'" + job.id + "'" + ', ' + "'" + (job.queue || currentQueue) + "'" + ')" title="Retry this job">↻ Retry</button>'
446
+ : '<span style="color: var(--muted); font-size: 11px;">—</span>';
447
+
448
+ // Check if this job was previously expanded
449
+ const isExpanded = expandedJobIds.has(job.id);
450
+
451
+ tr.innerHTML =
452
+ '<td><span class="expand-icon' + (isExpanded ? ' expanded' : '') + '">▶</span><code>' + job.id + '</code></td>' +
453
+ '<td>' + job.name + '</td>' +
454
+ '<td>' + (job.queue || currentQueue) + '</td>' +
455
+ '<td><span class="status-badge ' +
456
+ statusInfo.cls +
457
+ '">' +
458
+ statusInfo.label +
459
+ '</span></td>' +
460
+ '<td>' + job.attempts + '</td>' +
461
+ '<td>' + new Date(job.timestamp).toLocaleTimeString() + '</td>' +
462
+ '<td>' + retryBtn + '</td>';
463
+ if (job.failedReason) {
464
+ tr.title = 'Click to see error details';
465
+ }
466
+
467
+ tr.addEventListener('click', (e) => {
468
+ if (e.target.classList.contains('retry-btn')) return;
469
+ toggleJobDetails(tr, job);
470
+ });
471
+
472
+ tbody.appendChild(tr);
473
+
474
+ // Auto-expand if this job was previously expanded
475
+ if (isExpanded) {
476
+ setTimeout(() => {
477
+ toggleJobDetails(tr, job);
478
+ }, 10); // Small delay to ensure DOM is ready
479
+ }
480
+ });
481
+
482
+ // Clean up expanded job IDs that are no longer in the current jobs list
483
+ const currentJobIds = new Set(jobs.map(job => job.id));
484
+ expandedJobIds = new Set([...expandedJobIds].filter(id => currentJobIds.has(id)));
485
+ }`;
486
+ const getRenderLocksFunction = () => `
487
+ // Track expanded lock keys to preserve state during SSE updates
488
+ let expandedLockKeys = new Set();
489
+
490
+ function renderLocks(payload) {
491
+ const tbody = document.querySelector('#locks-table tbody');
492
+ const locks = payload && payload.locks ? payload.locks : [];
493
+ const metrics = payload && payload.metrics ? payload.metrics : null;
494
+ const histogram = payload && payload.histogram ? payload.histogram : [];
495
+
496
+ // Update summary and histogram (these don't cause layout shifts)
497
+ updateLocksSummary(document.getElementById('locks-summary'), metrics);
498
+ updateLocksHistogram(document.getElementById('locks-histogram'), histogram);
499
+
500
+ if (!locks || locks.length === 0) {
501
+ // Only clear if we have content to replace
502
+ if (tbody.children.length > 0) {
503
+ tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; color: var(--muted)">No active locks found</td></tr>';
504
+ }
505
+ expandedLockKeys.clear();
506
+ return;
507
+ }
508
+
509
+ // Create a map of current lock keys for efficient lookup
510
+ const currentLockKeys = new Set(locks.map(lock => lock.key));
511
+
512
+ // Remove rows for locks that no longer exist
513
+ removeObsoleteLockRows(tbody, currentLockKeys);
514
+
515
+ // Get map of existing rows
516
+ const existingRows = getExistingLockRows(tbody);
517
+
518
+ // Update existing rows and add new ones
519
+ locks.forEach((lock, idx) => {
520
+ const existingRow = existingRows.get(lock.key);
521
+ if (existingRow) {
522
+ updateExistingLockRow(existingRow, lock, idx);
523
+ } else {
524
+ const tr = createNewLockRow(lock, idx);
525
+ tbody.appendChild(tr);
526
+
527
+ // Auto-expand if this lock was previously expanded
528
+ if (expandedLockKeys.has(lock.key)) {
529
+ setTimeout(() => {
530
+ toggleLockDetails(tr, lock);
531
+ }, 10);
532
+ }
533
+ }
534
+ });
535
+
536
+ // Clean up expanded lock keys that are no longer in the current locks list
537
+ expandedLockKeys = new Set([...expandedLockKeys].filter(key => currentLockKeys.has(key)));
538
+ }
539
+ `;
540
+ const getLockHelperFunctions = () => `
541
+ function updateLocksSummary(summary, metrics) {
542
+ if (!summary) return;
543
+ if (metrics) {
544
+ const rate = metrics.attempts > 0
545
+ ? (metrics.collisionRate * 100).toFixed(1) + '%'
546
+ : '0%';
547
+ summary.innerHTML =
548
+ '<span><strong>Active</strong> ' + metrics.active + '</span>' +
549
+ '<span><strong>Attempts</strong> ' + metrics.attempts + '</span>' +
550
+ '<span><strong>Collisions</strong> ' + metrics.collisions + '</span>' +
551
+ '<span><strong>Collision rate</strong> ' + rate + '</span>';
552
+ } else {
553
+ summary.textContent = 'No metrics available.';
554
+ }
555
+ }
556
+
557
+ function updateLocksHistogram(histogramEl, histogram) {
558
+ if (!histogramEl) return;
559
+ if (histogram.length === 0) {
560
+ histogramEl.textContent = 'No TTL data available.';
561
+ } else {
562
+ histogramEl.innerHTML = histogram.map(bucket => {
563
+ return '<div style="display:flex; justify-content: space-between; gap: 12px; margin: 4px 0;">' +
564
+ '<span style="color: var(--muted);">' + bucket.label + '</span>' +
565
+ '<span>' + bucket.count + '</span>' +
566
+ '</div>';
567
+ }).join('');
568
+ }
569
+ }
570
+
571
+ function removeObsoleteLockRows(tbody, currentLockKeys) {
572
+ const rowsToRemove = [];
573
+ for (let i = 0; i < tbody.children.length; i++) {
574
+ const row = tbody.children[i];
575
+ const lockKey = row.querySelector('code')?.textContent;
576
+ if (lockKey && !currentLockKeys.has(lockKey)) {
577
+ rowsToRemove.push(row);
578
+ expandedLockKeys.delete(lockKey);
579
+ }
580
+ }
581
+ rowsToRemove.forEach(row => row.remove());
582
+ }
583
+
584
+ function getExistingLockRows(tbody) {
585
+ const existingRows = new Map();
586
+ for (let i = 0; i < tbody.children.length; i++) {
587
+ const row = tbody.children[i];
588
+ const lockKey = row.querySelector('code')?.textContent;
589
+ if (lockKey) {
590
+ existingRows.set(lockKey, row);
591
+ }
592
+ }
593
+ return existingRows;
594
+ }
595
+
596
+ function updateExistingLockRow(row, lock, idx) {
597
+ const ttl = typeof lock.ttl === 'number' ? Math.round(lock.ttl / 1000) + 's' : '—';
598
+ const expires = lock.expires ? new Date(lock.expires).toLocaleTimeString() : '—';
599
+
600
+ const ttlCell = row.children[1];
601
+ const expiresCell = row.children[2];
602
+ if (ttlCell) ttlCell.textContent = ttl;
603
+ if (expiresCell) expiresCell.textContent = expires;
604
+
605
+ row.dataset.lockIndex = idx;
606
+ }
607
+
608
+ function createNewLockRow(lock, idx) {
609
+ const tr = document.createElement('tr');
610
+ tr.className = 'expandable-row';
611
+ tr.dataset.lockIndex = idx;
612
+
613
+ const ttl = typeof lock.ttl === 'number' ? Math.round(lock.ttl / 1000) + 's' : '—';
614
+ const expires = lock.expires ? new Date(lock.expires).toLocaleTimeString() : '—';
615
+ const isExpanded = expandedLockKeys.has(lock.key);
616
+
617
+ tr.innerHTML =
618
+ '<td><span class="expand-icon' + (isExpanded ? ' expanded' : '') + '">▶</span><code>' + lock.key + '</code></td>' +
619
+ '<td>' + ttl + '</td>' +
620
+ '<td>' + expires + '</td>';
621
+ tr.title = 'Click to see lock details';
622
+
623
+ tr.addEventListener('click', () => {
624
+ toggleLockDetails(tr, lock);
625
+ });
626
+
627
+ return tr;
628
+ }
629
+ `;
630
+ const getErrorAndTooltipFunctions = () => `
631
+ function showError(msg) {
632
+ const el = document.getElementById('error-container');
633
+ el.textContent = msg;
634
+ el.style.display = 'block';
635
+ }
636
+
637
+ let tooltipEl = null;
638
+ function showTooltip(e) {
639
+ const info = e.target.getAttribute('data-info');
640
+ if (!info) return;
641
+
642
+ if (!tooltipEl) {
643
+ tooltipEl = document.createElement('div');
644
+ tooltipEl.className = 'tooltip';
645
+ document.body.appendChild(tooltipEl);
646
+ }
647
+
648
+ tooltipEl.textContent = info;
649
+ tooltipEl.classList.add('show');
650
+
651
+ const rect = e.target.getBoundingClientRect();
652
+ tooltipEl.style.left = Math.min(rect.left, window.innerWidth - tooltipEl.offsetWidth - 10) + 'px';
653
+ tooltipEl.style.top = (rect.bottom + 8) + 'px';
654
+ }
655
+
656
+ function hideTooltip() {
657
+ if (tooltipEl) {
658
+ tooltipEl.classList.remove('show');
659
+ }
660
+ }`;
661
+ const getToggleDetailsFunctions = () => `
662
+ function toggleJobDetails(row, job) {
663
+ const expandIcon = row.querySelector('.expand-icon');
664
+ const existingDetail = row.nextElementSibling;
665
+
666
+ if (existingDetail && existingDetail.classList.contains('detail-row')) {
667
+ expandIcon.classList.remove('expanded');
668
+ existingDetail.remove();
669
+ // Remove from expanded set
670
+ expandedJobIds.delete(job.id);
671
+ return;
672
+ }
673
+
674
+ expandIcon.classList.add('expanded');
675
+ // Add to expanded set
676
+ expandedJobIds.add(job.id);
677
+
678
+ const detailRow = document.createElement('tr');
679
+ detailRow.className = 'detail-row';
680
+
681
+ const jobData = {
682
+ id: job.id,
683
+ name: job.name,
684
+ queue: currentQueue,
685
+ status: job.status || (job.failedReason ? 'failed' : 'completed'),
686
+ attempts: job.attempts,
687
+ timestamp: new Date(job.timestamp).toISOString(),
688
+ data: job.data || {},
689
+ failedReason: job.failedReason || null,
690
+ processedOn: job.processedOn ? new Date(job.processedOn).toISOString() : null,
691
+ finishedOn: job.finishedOn ? new Date(job.finishedOn).toISOString() : null,
692
+ returnvalue: job.returnvalue
693
+ };
694
+
695
+ detailRow.innerHTML =
696
+ '<td colspan="7" class="detail-cell">' +
697
+ '<div class="detail-content">' +
698
+ '<strong style="color: var(--accent); display: block; margin-bottom: 8px;">Job Details:</strong>' +
699
+ '<pre>' + JSON.stringify(jobData, null, 2) + '</pre>' +
700
+ '</div>' +
701
+ '</td>';
702
+
703
+ row.parentNode.insertBefore(detailRow, row.nextSibling);
704
+ }
705
+
706
+ function toggleLockDetails(row, lock) {
707
+ const expandIcon = row.querySelector('.expand-icon');
708
+ const existingDetail = row.nextElementSibling;
709
+
710
+ if (existingDetail && existingDetail.classList.contains('detail-row')) {
711
+ expandIcon.classList.remove('expanded');
712
+ existingDetail.remove();
713
+ // Remove from expanded set
714
+ expandedLockKeys.delete(lock.key);
715
+ return;
716
+ }
717
+
718
+ expandIcon.classList.add('expanded');
719
+ // Add to expanded set
720
+ expandedLockKeys.add(lock.key);
721
+
722
+ const detailRow = document.createElement('tr');
723
+ detailRow.className = 'detail-row';
724
+
725
+ const lockData = {
726
+ key: lock.key,
727
+ ttl: lock.ttl,
728
+ ttlSeconds: typeof lock.ttl === 'number' ? Math.round(lock.ttl / 1000) : null,
729
+ expires: lock.expires ? new Date(lock.expires).toISOString() : null,
730
+ expiresLocal: lock.expires ? new Date(lock.expires).toLocaleString() : null,
731
+ value: lock.value || null,
732
+ metadata: lock.metadata || {}
733
+ };
734
+
735
+ detailRow.innerHTML =
736
+ '<td colspan="3" class="detail-cell">' +
737
+ '<div class="detail-content">' +
738
+ '<strong style="color: var(--accent); display: block; margin-bottom: 8px;">Lock Details:</strong>' +
739
+ '<pre>' + JSON.stringify(lockData, null, 2) + '</pre>' +
740
+ '</div>' +
741
+ '</td>';
742
+
743
+ row.parentNode.insertBefore(detailRow, row.nextSibling);
744
+ }`;
745
+ const getRetryJobFunction = () => `
746
+ async function retryJob(jobId, queueName) {
747
+ try {
748
+ const btn = event.target;
749
+ btn.disabled = true;
750
+ btn.textContent = '⏳ Retrying...';
751
+
752
+ const res = await fetch(API_BASE + '/api/retry/' + queueName + '/' + jobId, {
753
+ method: 'POST'
754
+ });
755
+
756
+ if (res.ok) {
757
+ btn.textContent = '✓ Retried';
758
+ setTimeout(() => {
759
+ console.log('HTTP jobs polling disabled - using SSE only');
760
+ // fetchJobs(currentQueue);
761
+ }, 1000);
762
+ } else {
763
+ btn.textContent = '✗ Failed';
764
+ btn.disabled = false;
765
+ }
766
+ } catch (e) {
767
+ console.error('Failed to retry job', e);
768
+ const btn = event.target;
769
+ btn.textContent = '✗ Failed';
770
+ btn.disabled = false;
771
+ }
772
+ }`;
773
+ const getDashboardScriptHelpers = () => `
774
+ function getLockPattern() {
775
+ const patternInput = document.getElementById('lock-pattern');
776
+ return patternInput && patternInput.value ? patternInput.value : '*';
777
+ }
778
+
779
+ function buildEventsUrl(queue, pattern) {
780
+ const q = queue || '';
781
+ const p = pattern || '*';
782
+ return API_BASE + '/api/events?queue=' + encodeURIComponent(q) + '&pattern=' + encodeURIComponent(p);
783
+ }
784
+ `;
785
+ const getDashboardScriptEventStream = () => `
786
+ function setupEventStream(queueOverride) {
787
+ if (!window.EventSource) return;
788
+
789
+ const queue = queueOverride || currentQueue;
790
+ const pattern = getLockPattern();
791
+
792
+ if (eventSource && queue === lastSseQueue && pattern === lastSsePattern) return;
793
+
794
+ if (eventSource) {
795
+ eventSource.close();
796
+ eventSource = null;
797
+ }
798
+
799
+ lastSseQueue = queue;
800
+ lastSsePattern = pattern;
801
+ eventSource = new EventSource(buildEventsUrl(queue, pattern));
802
+
803
+ eventSource.onopen = () => {
804
+ sseActive = true;
805
+ stopAutoRefresh();
806
+ };
807
+
808
+ eventSource.onmessage = (evt) => {
809
+ try {
810
+ const payload = JSON.parse(evt.data);
811
+ if (!payload || !payload.type) return;
812
+
813
+ if (payload.type === 'snapshot') {
814
+ if (payload.snapshot) {
815
+ renderStats(payload.snapshot);
816
+ updateQueueSelect(payload.snapshot.queues || []);
817
+ }
818
+
819
+ if (payload.queue && payload.queue !== currentQueue) {
820
+ currentQueue = payload.queue;
821
+ localStorage.setItem(QUEUE_KEY, currentQueue);
822
+ const select = document.getElementById('queue-select');
823
+ if (select) select.value = currentQueue;
824
+ }
825
+
826
+ if (payload.jobs) renderJobs(payload.jobs);
827
+ if (payload.locks) renderLocks(payload.locks);
828
+
829
+ document.getElementById('last-updated').textContent = new Date().toLocaleTimeString();
830
+ }
831
+ } catch (err) {
832
+ console.error('Failed to parse SSE payload', err);
833
+ }
834
+ };
835
+
836
+ eventSource.onerror = () => {
837
+ if (eventSource) {
838
+ eventSource.close();
839
+ eventSource = null;
840
+ }
841
+ sseActive = false;
842
+ if (autoRefreshEnabled) startAutoRefresh();
843
+ };
844
+ }
845
+ `;
846
+ const getFetchDataFunction = () => `
847
+ // HTTP polling disabled - 100% SSE reliance
848
+ async function fetchData() {
849
+ console.log('HTTP polling disabled - using SSE only');
850
+ // Disabled to ensure 100% SSE streaming
851
+ /*
852
+ try {
853
+ document.getElementById('error-container').style.display = 'none';
854
+ const res = await fetch(API_BASE + '/api/snapshot');
855
+ if (!res.ok) throw new Error('Failed to fetch stats');
856
+ const data = await res.json();
857
+
858
+ renderStats(data);
859
+ updateQueueSelect(data.queues);
860
+ handleQueueSelection(data);
861
+ await fetchLocks();
862
+ document.getElementById('last-updated').textContent = new Date().toLocaleTimeString();
863
+ } catch (e) {
864
+ showError(e.message);
865
+ }
866
+ */
867
+ }
868
+
869
+ function handleQueueSelection(data) {
870
+ if (data.queues.length > 0) {
871
+ document.getElementById('queue-select').value = currentQueue;
872
+ } else {
873
+ document.getElementById('queue-select').innerHTML = '<option>No Queues</option>';
874
+ renderJobs([]);
875
+ }
876
+ }
877
+ `;
878
+ const getDashboardScriptFetch = () => `
879
+ // HTTP polling disabled - 100% SSE reliance
880
+ async function fetchJobs(queue) {
881
+ console.log('HTTP jobs polling disabled - using SSE only');
882
+ // Disabled to ensure 100% SSE streaming
883
+ /*
884
+ try {
885
+ const res = await fetch(API_BASE + '/api/jobs/' + queue);
886
+ const jobs = await res.json();
887
+ renderJobs(jobs);
888
+ } catch (e) {
889
+ console.error('Failed to fetch jobs', e);
890
+ }
891
+ */
892
+ }
893
+
894
+ // HTTP polling disabled - 100% SSE reliance
895
+ async function fetchLocks() {
896
+ console.log('HTTP locks polling disabled - using SSE only');
897
+ // Disabled to ensure 100% SSE streaming
898
+ /*
899
+ try {
900
+ const pattern = getLockPattern();
901
+ const res = await fetch(API_BASE + '/api/locks?pattern=' + encodeURIComponent(pattern));
902
+ const data = await res.json();
903
+ renderLocks(data);
904
+ } catch (e) {
905
+ console.error('Failed to fetch locks', e);
906
+ }
907
+ */
908
+ }
909
+ `;
910
+ const getDashboardScriptRender = () => [
911
+ getRenderStatsFunction(),
912
+ getUpdateQueueSelectFunction(),
913
+ getRenderJobsFunction(),
914
+ getRenderLocksFunction(),
915
+ getLockHelperFunctions(),
916
+ getErrorAndTooltipFunctions(),
917
+ getToggleDetailsFunctions(),
918
+ getRetryJobFunction(),
919
+ ].join('\n');
920
+ const getDashboardScriptBootstrap = () => `
921
+ const themeButton = document.getElementById('theme-toggle');
922
+ if (themeButton) {
923
+ themeButton.addEventListener('click', toggleTheme);
924
+ }
925
+
926
+ const autoRefreshButton = document.getElementById('auto-refresh-toggle');
927
+ if (autoRefreshButton) {
928
+ autoRefreshButton.addEventListener('click', toggleAutoRefresh);
929
+ }
930
+
931
+ const queueSelect = document.getElementById('queue-select');
932
+ if (queueSelect) {
933
+ queueSelect.addEventListener('change', (e) => {
934
+ currentQueue = e.target.value;
935
+ localStorage.setItem(QUEUE_KEY, currentQueue);
936
+ console.log('Queue changed - SSE will update automatically');
937
+
938
+ setupEventStream(currentQueue);
939
+ });
940
+ }
941
+
942
+ const lockRefresh = document.getElementById('lock-refresh');
943
+ if (lockRefresh) {
944
+ lockRefresh.addEventListener('click', () => {
945
+ console.log('Lock refresh disabled - SSE handles updates');
946
+ // fetchLocks(); // Disabled - SSE handles updates
947
+ setupEventStream(currentQueue);
948
+ });
949
+ }
950
+
951
+ const storedAutoRefresh = localStorage.getItem(AUTO_REFRESH_KEY);
952
+ const initialAutoRefresh = storedAutoRefresh === null
953
+ ? AUTO_REFRESH
954
+ : storedAutoRefresh === 'true';
955
+
956
+ applyTheme(getPreferredTheme());
957
+ console.log('HTTP polling disabled - 100% SSE streaming active');
958
+ // fetchData(); // Disabled - SSE handles initial data
959
+ setAutoRefresh(initialAutoRefresh);
960
+
961
+ setupEventStream(currentQueue);
962
+
963
+ window.addEventListener('beforeunload', () => {
964
+ if (eventSource) {
965
+ eventSource.close();
966
+ }
967
+ });
968
+ `;
969
+ const getDashboardScript = (options) => [
970
+ getDashboardScriptState(options),
971
+ getDashboardScriptTheme(),
972
+ getDashboardScriptAutoRefresh(),
973
+ getDashboardScriptHelpers(),
974
+ getDashboardScriptEventStream(),
975
+ getFetchDataFunction(),
976
+ getDashboardScriptFetch(),
977
+ getDashboardScriptRender(),
978
+ getDashboardScriptBootstrap(),
979
+ ].join('\n');
980
+ export const getDashboardHtml = (options) => `<!DOCTYPE html>
981
+ <html lang="en">
982
+ <head>
983
+ <meta charset="UTF-8">
984
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
985
+ <title>ZinTrust Queue Monitor</title>
986
+ <style>
987
+ ${getDashboardStyles()}
988
+ </style>
989
+ </head>
990
+ <body>
991
+ ${getDashboardBody()}
992
+
993
+ <script>
994
+ ${getDashboardScript(options)}
995
+ </script>
996
+ </body>
997
+ </html>`;