@stacksjs/actions 0.70.88 → 0.70.90

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 (261) hide show
  1. package/dist/action.d.ts +149 -0
  2. package/dist/action.js +78 -0
  3. package/dist/actions.d.ts +2 -0
  4. package/dist/actions.js +2 -0
  5. package/dist/add.d.ts +6 -0
  6. package/dist/add.js +20 -0
  7. package/dist/ai/request-model-access.d.ts +1 -0
  8. package/dist/ai/request-model-access.js +10 -0
  9. package/dist/auth/client.d.ts +1 -0
  10. package/dist/auth/client.js +44 -0
  11. package/dist/auth/prune.d.ts +1 -0
  12. package/dist/auth/prune.js +35 -0
  13. package/dist/auth/setup.d.ts +1 -0
  14. package/dist/auth/setup.js +322 -0
  15. package/dist/auth/token.d.ts +1 -0
  16. package/dist/auth/token.js +10 -0
  17. package/dist/blog-admin.d.ts +55 -0
  18. package/dist/blog-admin.js +156 -0
  19. package/dist/blog.d.ts +30 -0
  20. package/dist/blog.js +398 -0
  21. package/dist/build/cli.d.ts +1 -0
  22. package/dist/build/cli.js +6 -0
  23. package/dist/build/component-libs.d.ts +1 -0
  24. package/dist/build/component-libs.js +7 -0
  25. package/dist/build/core.d.ts +1 -0
  26. package/dist/build/core.js +55 -0
  27. package/dist/build/desktop.d.ts +1 -0
  28. package/dist/build/desktop.js +5 -0
  29. package/dist/build/docs.d.ts +1 -0
  30. package/dist/build/docs.js +5 -0
  31. package/dist/build/frontend-static.d.ts +16 -0
  32. package/dist/build/frontend-static.js +124 -0
  33. package/dist/build/server.d.ts +1 -0
  34. package/dist/build/server.js +6 -0
  35. package/dist/build/stacks.d.ts +1 -0
  36. package/dist/build/stacks.js +8 -0
  37. package/dist/build/views.d.ts +1 -0
  38. package/dist/build/views.js +11 -0
  39. package/dist/build.d.ts +9 -0
  40. package/dist/build.js +64 -0
  41. package/dist/bump.d.ts +1 -0
  42. package/dist/bump.js +163 -0
  43. package/dist/cdn/invalidate-cache.d.ts +1 -0
  44. package/dist/cdn/invalidate-cache.js +0 -0
  45. package/dist/changelog.d.ts +9 -0
  46. package/dist/changelog.js +27 -0
  47. package/dist/check/ports.d.ts +1 -0
  48. package/dist/check/ports.js +16 -0
  49. package/dist/clean.d.ts +1 -0
  50. package/dist/clean.js +4 -0
  51. package/dist/commit.d.ts +3 -0
  52. package/dist/commit.js +12 -0
  53. package/dist/copy-types.d.ts +1 -0
  54. package/dist/copy-types.js +10 -0
  55. package/dist/database/seed.d.ts +1 -0
  56. package/dist/database/seed.js +26 -0
  57. package/dist/deploy/create-receipt-rule.d.ts +1 -0
  58. package/dist/deploy/create-receipt-rule.js +36 -0
  59. package/dist/deploy/index.d.ts +1 -0
  60. package/dist/deploy/index.js +1574 -0
  61. package/dist/dev/api.d.ts +1 -0
  62. package/dist/dev/api.js +94 -0
  63. package/dist/dev/components.d.ts +1 -0
  64. package/dist/dev/components.js +7 -0
  65. package/dist/dev/dashboard-globals.d.ts +4 -0
  66. package/dist/dev/dashboard-globals.js +89 -0
  67. package/dist/dev/dashboard-utils.d.ts +150 -0
  68. package/dist/dev/dashboard-utils.js +380 -0
  69. package/dist/dev/dashboard.d.ts +22 -0
  70. package/dist/dev/dashboard.js +435 -0
  71. package/dist/dev/desktop.d.ts +1 -0
  72. package/dist/dev/desktop.js +5 -0
  73. package/dist/dev/docs.d.ts +1 -0
  74. package/dist/dev/docs.js +24 -0
  75. package/dist/dev/index.d.ts +10 -0
  76. package/dist/dev/index.js +29 -0
  77. package/dist/dev/migrate-watcher.d.ts +1 -0
  78. package/dist/dev/migrate-watcher.js +74 -0
  79. package/dist/dev/system-tray.d.ts +1 -0
  80. package/dist/dev/system-tray.js +5 -0
  81. package/dist/dev/views.d.ts +1 -0
  82. package/dist/dev/views.js +147 -0
  83. package/dist/discover-packages.d.ts +18 -0
  84. package/dist/discover-packages.js +32 -0
  85. package/dist/domains/add.d.ts +1 -0
  86. package/dist/domains/add.js +61 -0
  87. package/dist/domains/purchase.d.ts +1 -0
  88. package/dist/domains/purchase.js +66 -0
  89. package/dist/domains/remove.d.ts +1 -0
  90. package/dist/domains/remove.js +24 -0
  91. package/dist/examples.d.ts +5 -0
  92. package/dist/examples.js +34 -0
  93. package/dist/find-projects.d.ts +1 -0
  94. package/dist/find-projects.js +16 -0
  95. package/dist/fresh.d.ts +1 -0
  96. package/dist/fresh.js +17 -0
  97. package/dist/generate/action-types.d.ts +1 -0
  98. package/dist/generate/action-types.js +13 -0
  99. package/dist/generate/component-meta.d.ts +1 -0
  100. package/dist/generate/component-meta.js +9 -0
  101. package/dist/generate/custom-cli-file.d.ts +1 -0
  102. package/dist/generate/custom-cli-file.js +21 -0
  103. package/dist/generate/env-files.d.ts +1 -0
  104. package/dist/generate/env-files.js +66 -0
  105. package/dist/generate/ide-helpers.d.ts +1 -0
  106. package/dist/generate/ide-helpers.js +8 -0
  107. package/dist/generate/index.d.ts +36 -0
  108. package/dist/generate/index.js +158 -0
  109. package/dist/generate/lib-entries.d.ts +1 -0
  110. package/dist/generate/lib-entries.js +16 -0
  111. package/dist/generate/pantry-file.d.ts +1 -0
  112. package/dist/generate/pantry-file.js +46 -0
  113. package/dist/generate/symlink-core.d.ts +1 -0
  114. package/dist/generate/symlink-core.js +2 -0
  115. package/dist/generate/types.d.ts +1 -0
  116. package/dist/generate/types.js +3 -0
  117. package/dist/generate/vscode-custom-data.d.ts +1 -0
  118. package/dist/generate/vscode-custom-data.js +9 -0
  119. package/dist/generate/web-types.d.ts +1 -0
  120. package/dist/generate/web-types.js +0 -0
  121. package/dist/helpers/component-meta.d.ts +26 -0
  122. package/dist/helpers/component-meta.js +295 -0
  123. package/dist/helpers/index.d.ts +4 -0
  124. package/dist/helpers/index.js +1 -0
  125. package/dist/helpers/lib-entries.d.ts +12 -0
  126. package/dist/helpers/lib-entries.js +73 -0
  127. package/dist/helpers/package-json.d.ts +2 -0
  128. package/dist/helpers/package-json.js +74 -0
  129. package/dist/helpers/utils.d.ts +23 -0
  130. package/dist/helpers/utils.js +105 -0
  131. package/dist/helpers/vscode-custom-data.d.ts +3 -0
  132. package/dist/helpers/vscode-custom-data.js +30 -0
  133. package/dist/index.d.ts +62 -0
  134. package/dist/index.js +50 -0
  135. package/dist/key-generate.d.ts +1 -0
  136. package/dist/key-generate.js +24 -0
  137. package/dist/lint/fix.d.ts +1 -0
  138. package/dist/lint/fix.js +4 -0
  139. package/dist/lint/index.d.ts +1 -0
  140. package/dist/lint/index.js +4 -0
  141. package/dist/lint/lint.d.ts +14 -0
  142. package/dist/lint/lint.js +34 -0
  143. package/dist/make-command.d.ts +10 -0
  144. package/dist/make-command.js +95 -0
  145. package/dist/make-job.d.ts +5 -0
  146. package/dist/make-job.js +154 -0
  147. package/dist/make-policy.d.ts +10 -0
  148. package/dist/make-policy.js +142 -0
  149. package/dist/make-resource.d.ts +10 -0
  150. package/dist/make-resource.js +142 -0
  151. package/dist/make.d.ts +52 -0
  152. package/dist/make.js +328 -0
  153. package/dist/migrate/database.d.ts +1 -0
  154. package/dist/migrate/database.js +16 -0
  155. package/dist/migrate/fresh.d.ts +1 -0
  156. package/dist/migrate/fresh.js +31 -0
  157. package/dist/orm/base.d.ts +1 -0
  158. package/dist/orm/base.js +0 -0
  159. package/dist/orm/test.d.ts +1 -0
  160. package/dist/orm/test.js +0 -0
  161. package/dist/prepublish.d.ts +1 -0
  162. package/dist/prepublish.js +16 -0
  163. package/dist/queue/clear.d.ts +1 -0
  164. package/dist/queue/clear.js +42 -0
  165. package/dist/queue/dlq-purge.d.ts +1 -0
  166. package/dist/queue/dlq-purge.js +28 -0
  167. package/dist/queue/dlq-retry.d.ts +1 -0
  168. package/dist/queue/dlq-retry.js +35 -0
  169. package/dist/queue/dlq.d.ts +1 -0
  170. package/dist/queue/dlq.js +55 -0
  171. package/dist/queue/failed.d.ts +1 -0
  172. package/dist/queue/failed.js +69 -0
  173. package/dist/queue/flush.d.ts +1 -0
  174. package/dist/queue/flush.js +49 -0
  175. package/dist/queue/inspect.d.ts +1 -0
  176. package/dist/queue/inspect.js +154 -0
  177. package/dist/queue/list.d.ts +1 -0
  178. package/dist/queue/list.js +69 -0
  179. package/dist/queue/monitor.d.ts +1 -0
  180. package/dist/queue/monitor.js +95 -0
  181. package/dist/queue/pause.d.ts +1 -0
  182. package/dist/queue/pause.js +28 -0
  183. package/dist/queue/quarantine.d.ts +1 -0
  184. package/dist/queue/quarantine.js +42 -0
  185. package/dist/queue/resume.d.ts +1 -0
  186. package/dist/queue/resume.js +27 -0
  187. package/dist/queue/retry.d.ts +1 -0
  188. package/dist/queue/retry.js +41 -0
  189. package/dist/queue/schedule-list.d.ts +1 -0
  190. package/dist/queue/schedule-list.js +33 -0
  191. package/dist/queue/schedule.d.ts +1 -0
  192. package/dist/queue/schedule.js +12 -0
  193. package/dist/queue/status.d.ts +1 -0
  194. package/dist/queue/status.js +68 -0
  195. package/dist/queue/table.d.ts +1 -0
  196. package/dist/queue/table.js +10 -0
  197. package/dist/queue/unquarantine.d.ts +1 -0
  198. package/dist/queue/unquarantine.js +27 -0
  199. package/dist/queue/work.d.ts +1 -0
  200. package/dist/queue/work.js +57 -0
  201. package/dist/release.d.ts +1 -0
  202. package/dist/release.js +21 -0
  203. package/dist/route/list.d.ts +1 -0
  204. package/dist/route/list.js +78 -0
  205. package/dist/run-action.d.ts +2 -0
  206. package/dist/run-action.js +1 -0
  207. package/dist/saas/setup.d.ts +1 -0
  208. package/dist/saas/setup.js +9 -0
  209. package/dist/scaffold-crud.d.ts +25 -0
  210. package/dist/scaffold-crud.js +211 -0
  211. package/dist/schedule/run.d.ts +1 -0
  212. package/dist/schedule/run.js +7 -0
  213. package/dist/search/flush.d.ts +1 -0
  214. package/dist/search/flush.js +10 -0
  215. package/dist/search/import.d.ts +1 -0
  216. package/dist/search/import.js +10 -0
  217. package/dist/search/settings-list.d.ts +1 -0
  218. package/dist/search/settings-list.js +10 -0
  219. package/dist/search/settings.d.ts +1 -0
  220. package/dist/search/settings.js +9 -0
  221. package/dist/serve/api.d.ts +1 -0
  222. package/dist/serve/api.js +35 -0
  223. package/dist/setup/index.d.ts +1 -0
  224. package/dist/setup/index.js +1 -0
  225. package/dist/setup/ssl.d.ts +38 -0
  226. package/dist/setup/ssl.js +271 -0
  227. package/dist/stacks.d.ts +4 -0
  228. package/dist/stacks.js +265 -0
  229. package/dist/templates.d.ts +28 -0
  230. package/dist/templates.js +301 -0
  231. package/dist/test/feature.d.ts +1 -0
  232. package/dist/test/feature.js +11 -0
  233. package/dist/test/index.d.ts +1 -0
  234. package/dist/test/index.js +11 -0
  235. package/dist/test/ui.d.ts +1 -0
  236. package/dist/test/ui.js +4 -0
  237. package/dist/test/unit.d.ts +1 -0
  238. package/dist/test/unit.js +11 -0
  239. package/dist/typecheck.d.ts +1 -0
  240. package/dist/typecheck.js +4 -0
  241. package/dist/types.d.ts +3 -0
  242. package/dist/types.js +16 -0
  243. package/dist/upgrade/binary.d.ts +1 -0
  244. package/dist/upgrade/binary.js +29 -0
  245. package/dist/upgrade/bun.d.ts +1 -0
  246. package/dist/upgrade/bun.js +0 -0
  247. package/dist/upgrade/dependencies.d.ts +1 -0
  248. package/dist/upgrade/dependencies.js +0 -0
  249. package/dist/upgrade/framework-utils.d.ts +150 -0
  250. package/dist/upgrade/framework-utils.js +193 -0
  251. package/dist/upgrade/framework.d.ts +1 -0
  252. package/dist/upgrade/framework.js +310 -0
  253. package/dist/upgrade/index.d.ts +1 -0
  254. package/dist/upgrade/index.js +17 -0
  255. package/dist/upgrade/packages.d.ts +14 -0
  256. package/dist/upgrade/packages.js +99 -0
  257. package/dist/upgrade/shell.d.ts +1 -0
  258. package/dist/upgrade/shell.js +41 -0
  259. package/dist/upgrade.d.ts +7 -0
  260. package/dist/upgrade.js +38 -0
  261. package/package.json +16 -16
@@ -0,0 +1,49 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { FailedJob } from "@stacksjs/orm";
4
+ const options = parseArgs(), queueName = options.queue, force = options.force === "true";
5
+ try {
6
+ if (!force) {
7
+ log.warn("This will permanently delete all failed jobs. Use --force to confirm.");
8
+ process.exit(1);
9
+ }
10
+ let deletedCount = 0;
11
+ if (queueName) {
12
+ log.info(`Flushing all failed jobs from queue "${queueName}"...`);
13
+ const failedJobs = await FailedJob.where("queue", queueName).get();
14
+ deletedCount = failedJobs.length;
15
+ for (const job of failedJobs)
16
+ await job.delete();
17
+ } else {
18
+ log.info("Flushing all failed jobs from all queues...");
19
+ const failedJobs = await FailedJob.all();
20
+ deletedCount = failedJobs.length;
21
+ for (const job of failedJobs)
22
+ await job.delete();
23
+ }
24
+ log.success(`Flushed ${deletedCount} failed job(s)`);
25
+ process.exit(0);
26
+ } catch (error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ if (/no such table:\s*(?:jobs|failed_jobs)\b/i.test(message)) {
29
+ process.stdout.write(`Queue tables are not set up yet.
30
+ `);
31
+ process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
32
+ process.exit(0);
33
+ }
34
+ log.error("Failed to flush failed jobs", error);
35
+ process.exit(1);
36
+ }
37
+ function parseArgs() {
38
+ const args = {};
39
+ process.argv.forEach((arg) => {
40
+ if (arg.startsWith("--")) {
41
+ const [key, value] = arg.slice(2).split("=");
42
+ if (key && value)
43
+ args[key] = value;
44
+ else if (key)
45
+ args[key] = "true";
46
+ }
47
+ });
48
+ return args;
49
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,154 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { Job, FailedJob } from "@stacksjs/orm";
4
+ const options = parseArgs(), jobId = options.id, failedFlag = options.failed === "true";
5
+ try {
6
+ if (!jobId) {
7
+ log.error("Please provide a job ID");
8
+ log.info("Usage: buddy queue:inspect --id=<jobId> [--failed]");
9
+ process.exit(1);
10
+ }
11
+ const id = Number.parseInt(jobId, 10);
12
+ if (Number.isNaN(id)) {
13
+ log.error("Invalid job ID provided");
14
+ process.exit(1);
15
+ }
16
+ if (failedFlag) {
17
+ const failedResult = await FailedJob.find(id);
18
+ if (!failedResult) {
19
+ log.error(`Failed job with ID ${id} not found`);
20
+ process.exit(1);
21
+ }
22
+ const job = failedResult;
23
+ console.log(`
24
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
25
+ console.log("\u2502 Failed Job Details \u2502");
26
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
27
+ console.log(`\u2502 ID: ${String(job.id).padEnd(52)} \u2502`);
28
+ console.log(`\u2502 Queue: ${(job.queue || "default").padEnd(52)} \u2502`);
29
+ console.log(`\u2502 Connection: ${(job.connection || "database").padEnd(52)} \u2502`);
30
+ console.log(`\u2502 Failed At: ${(job.failed_at || "N/A").padEnd(52)} \u2502`);
31
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
32
+ console.log("\u2502 Exception: \u2502");
33
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
34
+ const exception = job.exception || "Unknown error", lines = exception.match(/.{1,62}/g) || [exception];
35
+ for (const line of lines.slice(0, 20))
36
+ console.log(`\u2502 ${line.padEnd(62)} \u2502`);
37
+ if (lines.length > 20)
38
+ console.log(`\u2502 ... (${lines.length - 20} more lines)`.padEnd(64) + " \u2502");
39
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
40
+ console.log("\u2502 Payload: \u2502");
41
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
42
+ if (job.payload)
43
+ try {
44
+ const payload = JSON.parse(job.payload);
45
+ console.log(`\u2502 Name: ${payload.name.padEnd(52)} \u2502`);
46
+ console.log(`\u2502 Path: ${payload.path.padEnd(52)} \u2502`);
47
+ console.log(`\u2502 Max Tries: ${String(payload.maxTries).padEnd(52)} \u2502`);
48
+ console.log("\u2502 Parameters: \u2502");
49
+ const paramLines = JSON.stringify(payload.params, null, 2).split(`
50
+ `);
51
+ for (const line of paramLines.slice(0, 15))
52
+ console.log(`\u2502 ${line.substring(0, 60).padEnd(60)} \u2502`);
53
+ if (paramLines.length > 15)
54
+ console.log(`\u2502 ... (${paramLines.length - 15} more lines)`.padEnd(64) + " \u2502");
55
+ } catch {
56
+ console.log(`\u2502 Raw: ${job.payload.substring(0, 58).padEnd(58)} \u2502`);
57
+ }
58
+ else
59
+ console.log("\u2502 (No payload) \u2502");
60
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
61
+ console.log(`
62
+ Actions:`);
63
+ console.log(` Retry this job: buddy queue:retry --id=${id}`);
64
+ console.log(` Delete this job: buddy queue:flush --id=${id}`);
65
+ } else {
66
+ const jobResult = await Job.find(id);
67
+ if (!jobResult) {
68
+ log.error(`Job with ID ${id} not found`);
69
+ log.info("Tip: Use --failed flag to inspect failed jobs");
70
+ process.exit(1);
71
+ }
72
+ const job = jobResult, now = Math.floor(Date.now() / 1000);
73
+ let status = "Pending";
74
+ if (job.reserved_at)
75
+ status = "Processing";
76
+ else if (job.available_at && job.available_at > now)
77
+ status = "Delayed";
78
+ console.log(`
79
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
80
+ console.log("\u2502 Job Details \u2502");
81
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
82
+ console.log(`\u2502 ID: ${String(job.id).padEnd(50)} \u2502`);
83
+ console.log(`\u2502 Queue: ${(job.queue || "default").padEnd(50)} \u2502`);
84
+ console.log(`\u2502 Status: ${status.padEnd(50)} \u2502`);
85
+ console.log(`\u2502 Attempts: ${String(job.attempts || 0).padEnd(50)} \u2502`);
86
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
87
+ if (job.available_at) {
88
+ const availableDate = new Date(job.available_at * 1000);
89
+ console.log(`\u2502 Available At: ${availableDate.toISOString().padEnd(50)} \u2502`);
90
+ }
91
+ if (job.reserved_at) {
92
+ const reservedDate = new Date(job.reserved_at * 1000);
93
+ console.log(`\u2502 Reserved At: ${reservedDate.toISOString().padEnd(50)} \u2502`);
94
+ }
95
+ if (job.created_at)
96
+ console.log(`\u2502 Created At: ${String(job.created_at).padEnd(50)} \u2502`);
97
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
98
+ console.log("\u2502 Payload: \u2502");
99
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
100
+ if (job.payload)
101
+ try {
102
+ const payload = JSON.parse(job.payload);
103
+ console.log(`\u2502 Name: ${payload.name.padEnd(52)} \u2502`);
104
+ console.log(`\u2502 Path: ${payload.path.padEnd(52)} \u2502`);
105
+ console.log(`\u2502 Max Tries: ${String(payload.maxTries).padEnd(52)} \u2502`);
106
+ console.log(`\u2502 Timeout: ${String(payload.timeOut || "N/A").padEnd(52)} \u2502`);
107
+ console.log("\u2502 Parameters: \u2502");
108
+ const paramLines = JSON.stringify(payload.params, null, 2).split(`
109
+ `);
110
+ for (const line of paramLines.slice(0, 15))
111
+ console.log(`\u2502 ${line.substring(0, 60).padEnd(60)} \u2502`);
112
+ if (paramLines.length > 15)
113
+ console.log(`\u2502 ... (${paramLines.length - 15} more lines)`.padEnd(64) + " \u2502");
114
+ if (payload.classPayload)
115
+ try {
116
+ const classConfig = JSON.parse(payload.classPayload);
117
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
118
+ console.log("\u2502 Job Configuration: \u2502");
119
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
120
+ console.log(`\u2502 Tries: ${String(classConfig.tries || 3).padEnd(52)} \u2502`);
121
+ console.log(`\u2502 Timeout: ${String(classConfig.timeout || 60).padEnd(52)} \u2502`);
122
+ if (classConfig.backoff)
123
+ console.log(`\u2502 Backoff: ${String(JSON.stringify(classConfig.backoff)).substring(0, 52).padEnd(52)} \u2502`);
124
+ } catch {}
125
+ } catch {
126
+ console.log(`\u2502 Raw: ${job.payload.substring(0, 58).padEnd(58)} \u2502`);
127
+ }
128
+ else
129
+ console.log("\u2502 (No payload) \u2502");
130
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
131
+ if (status === "Delayed" && job.available_at) {
132
+ const waitTime = job.available_at - now;
133
+ console.log(`
134
+ This job will be available in ${waitTime} second(s)`);
135
+ }
136
+ }
137
+ process.exit(0);
138
+ } catch (error) {
139
+ log.error("Failed to inspect job", error);
140
+ process.exit(1);
141
+ }
142
+ function parseArgs() {
143
+ const args = {};
144
+ process.argv.forEach((arg) => {
145
+ if (arg.startsWith("--")) {
146
+ const [key, value] = arg.slice(2).split("=");
147
+ if (key && value)
148
+ args[key] = value;
149
+ else if (key)
150
+ args[key] = "true";
151
+ }
152
+ });
153
+ return args;
154
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { Job } from "@stacksjs/orm";
4
+ const options = parseArgs(), queueName = options.queue, statusFilter = options.status, limit = options.limit ? Number.parseInt(options.limit, 10) : 50;
5
+ try {
6
+ log.info(`Fetching queued jobs...
7
+ `);
8
+ let jobs = queueName ? await Job.where("queue", queueName).get() : await Job.all();
9
+ const nowSec = Math.floor(Date.now() / 1000);
10
+ if (statusFilter === "pending")
11
+ jobs = jobs.filter((j) => !j.reserved_at && (j.available_at ?? 0) <= nowSec);
12
+ else if (statusFilter === "reserved")
13
+ jobs = jobs.filter((j) => Boolean(j.reserved_at));
14
+ else if (statusFilter === "delayed")
15
+ jobs = jobs.filter((j) => !j.reserved_at && (j.available_at ?? 0) > nowSec);
16
+ if (Number.isFinite(limit) && limit > 0)
17
+ jobs = jobs.slice(0, limit);
18
+ if (jobs.length === 0) {
19
+ console.log("\u2713 No queued jobs found");
20
+ process.exit(0);
21
+ }
22
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
23
+ console.log("\u2502 ID \u2502 Queue \u2502 Job \u2502 Attempts \u2502 Status \u2502 Available At \u2502");
24
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
25
+ for (const j of jobs) {
26
+ const jobAny = j, id = String(jobAny.id ?? "").padEnd(3), queue = String(jobAny.queue ?? "default").substring(0, 18).padEnd(18), jobName = extractJobName(jobAny.payload).substring(0, 32).padEnd(32), attempts = String(jobAny.attempts ?? 0).padEnd(8), status = (jobAny.reserved_at ? "reserved" : (jobAny.available_at ?? 0) > nowSec ? "delayed" : "pending").padEnd(8), avail = formatUnixTime(jobAny.available_at).padEnd(19);
27
+ console.log(`\u2502 ${id} \u2502 ${queue} \u2502 ${jobName} \u2502 ${attempts} \u2502 ${status} \u2502 ${avail} \u2502`);
28
+ }
29
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
30
+ console.log(`
31
+ Showing ${jobs.length} job(s)${queueName ? ` on queue '${queueName}'` : ""}${statusFilter ? ` (status=${statusFilter})` : ""}`);
32
+ process.exit(0);
33
+ } catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ if (/no such table:\s*jobs\b/i.test(message)) {
36
+ process.stdout.write(`Queue tables are not set up yet.
37
+ `);
38
+ process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
39
+ process.exit(0);
40
+ }
41
+ log.error("Failed to list queued jobs", error);
42
+ process.exit(1);
43
+ }
44
+ function extractJobName(payload) {
45
+ if (typeof payload !== "string")
46
+ return "unknown";
47
+ try {
48
+ const parsed = JSON.parse(payload);
49
+ return parsed.jobName ?? parsed.name ?? "unknown";
50
+ } catch {
51
+ return "unknown";
52
+ }
53
+ }
54
+ function formatUnixTime(seconds) {
55
+ if (typeof seconds !== "number" || !Number.isFinite(seconds))
56
+ return "N/A";
57
+ return new Date(seconds * 1000).toISOString().slice(0, 19).replace("T", " ");
58
+ }
59
+ function parseArgs() {
60
+ const args = {};
61
+ process.argv.forEach((arg) => {
62
+ if (arg.startsWith("--")) {
63
+ const [key, value] = arg.slice(2).split("=");
64
+ if (key && value)
65
+ args[key] = value;
66
+ }
67
+ });
68
+ return args;
69
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { Job, FailedJob } from "@stacksjs/orm";
4
+ import { getActiveJobCount, isWorkerRunning } from "@stacksjs/queue";
5
+ const options = parseArgs(), queueName = options.queue, refreshInterval = Number(options.interval) || 2000;
6
+ let isRunning = !0;
7
+ process.on("SIGINT", () => {
8
+ isRunning = !1;
9
+ console.log(`
10
+
11
+ Monitoring stopped.`);
12
+ process.exit(0);
13
+ });
14
+ process.on("SIGTERM", () => {
15
+ isRunning = !1;
16
+ process.exit(0);
17
+ });
18
+ async function getStats() {
19
+ const allJobs = queueName ? await Job.where("queue", queueName).get() : await Job.all(), failedJobs = queueName ? await FailedJob.where("queue", queueName).get() : await FailedJob.all(), now = Math.floor(Date.now() / 1000);
20
+ let pending = 0, processing = 0, delayed = 0;
21
+ for (const job of allJobs)
22
+ if (job.reserved_at)
23
+ processing++;
24
+ else if (job.available_at && Number(job.available_at) > now)
25
+ delayed++;
26
+ else
27
+ pending++;
28
+ return {
29
+ pending,
30
+ processing,
31
+ delayed,
32
+ failed: failedJobs.length,
33
+ total: allJobs.length,
34
+ workerRunning: isWorkerRunning(),
35
+ activeJobs: getActiveJobCount()
36
+ };
37
+ }
38
+ async function displayStats() {
39
+ const stats = await getStats(), timestamp = new Date().toLocaleTimeString();
40
+ console.clear();
41
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
42
+ console.log("\u2502 Queue Monitor \u2502");
43
+ console.log("\u2502 Press Ctrl+C to exit \u2502");
44
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
45
+ console.log(`\u2502 Last Updated: ${timestamp.padEnd(48)} \u2502`);
46
+ console.log(`\u2502 Queue Filter: ${(queueName || "All Queues").padEnd(48)} \u2502`);
47
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
48
+ console.log("\u2502 \u2502");
49
+ console.log(`\u2502 Pending Jobs: ${String(stats.pending).padStart(8)} \u2502`);
50
+ console.log(`\u2502 Processing Jobs: ${String(stats.processing).padStart(8)} \u2502`);
51
+ console.log(`\u2502 Delayed Jobs: ${String(stats.delayed).padStart(8)} \u2502`);
52
+ console.log(`\u2502 Failed Jobs: ${String(stats.failed).padStart(8)} \u2502`);
53
+ console.log("\u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502");
54
+ console.log(`\u2502 Total Jobs: ${String(stats.total).padStart(8)} \u2502`);
55
+ console.log("\u2502 \u2502");
56
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
57
+ console.log("\u2502 Worker Status \u2502");
58
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
59
+ console.log(`\u2502 Worker Running: ${(stats.workerRunning ? "Yes" : "No").padEnd(8)} \u2502`);
60
+ console.log(`\u2502 Active Jobs: ${String(stats.activeJobs).padStart(8)} \u2502`);
61
+ console.log("\u2502 \u2502");
62
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
63
+ if (stats.failed > 0)
64
+ console.log(`
65
+ \u26A0\uFE0F Warning: ${stats.failed} failed job(s) - run 'buddy queue:failed' for details`);
66
+ if (!stats.workerRunning && stats.pending > 0)
67
+ console.log(`
68
+ \u26A0\uFE0F Warning: Worker not running but ${stats.pending} job(s) pending - run 'buddy queue:work'`);
69
+ }
70
+ try {
71
+ log.info(`Starting queue monitor...
72
+ `);
73
+ await displayStats();
74
+ while (isRunning) {
75
+ await new Promise((resolve) => setTimeout(resolve, refreshInterval));
76
+ if (isRunning)
77
+ await displayStats();
78
+ }
79
+ } catch (error) {
80
+ log.error("Monitor error:", error);
81
+ process.exit(1);
82
+ }
83
+ function parseArgs() {
84
+ const args = {};
85
+ process.argv.forEach((arg) => {
86
+ if (arg.startsWith("--")) {
87
+ const [key, value] = arg.slice(2).split("=");
88
+ if (key && value)
89
+ args[key] = value;
90
+ else if (key)
91
+ args[key] = "true";
92
+ }
93
+ });
94
+ return args;
95
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { pauseQueue } from "@stacksjs/queue";
4
+ const options = parseArgs(), queue = options.queue;
5
+ if (!queue) {
6
+ log.error("Usage: buddy queue:pause --queue=<name> [--for=300]");
7
+ process.exit(1);
8
+ }
9
+ const pauseSeconds = options.for ? Number.parseInt(options.for, 10) : 300;
10
+ try {
11
+ await pauseQueue(queue, pauseSeconds);
12
+ log.success(`Paused queue '${queue}' for ${pauseSeconds}s`);
13
+ process.exit(0);
14
+ } catch (error) {
15
+ log.error("Failed to pause queue", error);
16
+ process.exit(1);
17
+ }
18
+ function parseArgs() {
19
+ const args = {};
20
+ process.argv.forEach((arg) => {
21
+ if (arg.startsWith("--")) {
22
+ const [key, value] = arg.slice(2).split("=");
23
+ if (key && value)
24
+ args[key] = value;
25
+ }
26
+ });
27
+ return args;
28
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { listQuarantined, quarantineJob } from "@stacksjs/queue";
4
+ const options = parseArgs();
5
+ try {
6
+ if (options.add) {
7
+ const jobName = options.add;
8
+ await quarantineJob(jobName);
9
+ log.success(`Quarantined ${jobName}`);
10
+ process.exit(0);
11
+ }
12
+ const rows = await listQuarantined();
13
+ if (rows.length === 0) {
14
+ console.log("\u2713 No jobs currently quarantined");
15
+ process.exit(0);
16
+ }
17
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
18
+ console.log("\u2502 ID \u2502 Job Name \u2502 Payload Hash \u2502 Failures \u2502 Quarantined At \u2502");
19
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
20
+ for (const row of rows) {
21
+ const id = String(row.id).padEnd(3), jn = (row.job_name || "?").substring(0, 32).padEnd(32), ph = (row.payload_hash || "?").substring(0, 16).padEnd(16), fc = String(row.failure_count ?? 0).padEnd(8), qa = (row.quarantined_at || "N/A").substring(0, 24).padEnd(24);
22
+ console.log(`\u2502 ${id} \u2502 ${jn} \u2502 ${ph} \u2502 ${fc} \u2502 ${qa} \u2502`);
23
+ }
24
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
25
+ console.log(`
26
+ ${rows.length} quarantined entrie(s). Use \`queue:unquarantine <JobName>\` to lift.`);
27
+ process.exit(0);
28
+ } catch (error) {
29
+ log.error("Failed to handle queue:quarantine", error);
30
+ process.exit(1);
31
+ }
32
+ function parseArgs() {
33
+ const args = {};
34
+ process.argv.forEach((arg) => {
35
+ if (arg.startsWith("--")) {
36
+ const [key, value] = arg.slice(2).split("=");
37
+ if (key && value)
38
+ args[key] = value;
39
+ }
40
+ });
41
+ return args;
42
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { resumeQueue } from "@stacksjs/queue";
4
+ const options = parseArgs(), queue = options.queue;
5
+ if (!queue) {
6
+ log.error("Usage: buddy queue:resume --queue=<name>");
7
+ process.exit(1);
8
+ }
9
+ try {
10
+ await resumeQueue(queue);
11
+ log.success(`Resumed queue '${queue}'`);
12
+ process.exit(0);
13
+ } catch (error) {
14
+ log.error("Failed to resume queue", error);
15
+ process.exit(1);
16
+ }
17
+ function parseArgs() {
18
+ const args = {};
19
+ process.argv.forEach((arg) => {
20
+ if (arg.startsWith("--")) {
21
+ const [key, value] = arg.slice(2).split("=");
22
+ if (key && value)
23
+ args[key] = value;
24
+ }
25
+ });
26
+ return args;
27
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { executeFailedJobs, retryFailedJob } from "@stacksjs/queue";
4
+ const options = parseArgs(), jobId = options.id, all = options.all === "true";
5
+ try {
6
+ if (all) {
7
+ log.info("Retrying all failed jobs...");
8
+ await executeFailedJobs();
9
+ log.success("All failed jobs have been queued for retry");
10
+ } else if (jobId) {
11
+ const id = Number.parseInt(jobId, 10);
12
+ if (Number.isNaN(id)) {
13
+ log.error("Invalid job ID provided");
14
+ process.exit(1);
15
+ }
16
+ log.info(`Retrying failed job ${id}...`);
17
+ await retryFailedJob(id);
18
+ log.success(`Failed job ${id} has been queued for retry`);
19
+ } else {
20
+ log.warn("Please provide a job ID or use --all to retry all failed jobs");
21
+ log.info("Usage: buddy queue:retry <id> or buddy queue:retry --all");
22
+ process.exit(1);
23
+ }
24
+ process.exit(0);
25
+ } catch (error) {
26
+ log.error("Failed to retry job(s)", error);
27
+ process.exit(1);
28
+ }
29
+ function parseArgs() {
30
+ const args = {};
31
+ process.argv.forEach((arg) => {
32
+ if (arg.startsWith("--")) {
33
+ const [key, value] = arg.slice(2).split("=");
34
+ if (key && value)
35
+ args[key] = value;
36
+ else if (key)
37
+ args[key] = "true";
38
+ }
39
+ });
40
+ return args;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { discoverJobs, getScheduledJobs } from "@stacksjs/queue";
4
+ try {
5
+ log.info(`Discovering scheduled jobs...
6
+ `);
7
+ await discoverJobs();
8
+ const scheduledJobs = getScheduledJobs();
9
+ if (scheduledJobs.length === 0) {
10
+ log.info("No scheduled jobs found.");
11
+ log.info('Tip: Add a "rate" or "schedule" property to your job configuration.');
12
+ process.exit(0);
13
+ }
14
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
15
+ console.log("\u2502 Job Name \u2502 Schedule \u2502 Queue \u2502 Tries \u2502");
16
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
17
+ for (const job of scheduledJobs) {
18
+ const name = job.name.substring(0, 48).padEnd(48), schedule = (job.config.rate || job.config.schedule || "N/A").substring(0, 21).padEnd(21), queue = (job.config.queue || "default").substring(0, 9).padEnd(9), tries = String(job.config.tries || 3).padStart(7);
19
+ console.log(`\u2502 ${name} \u2502 ${schedule} \u2502 ${queue} \u2502${tries} \u2502`);
20
+ }
21
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
22
+ console.log(`
23
+ Total: ${scheduledJobs.length} scheduled job(s)`);
24
+ console.log(`
25
+ Schedule Formats:`);
26
+ console.log(' \u2022 Cron: "* * * * *" (minute hour day month dayOfWeek)');
27
+ console.log(" \u2022 Presets: @hourly, @daily, @weekly, @monthly");
28
+ console.log(" \u2022 Every: Every.Minute, Every.Hour, Every.Day");
29
+ process.exit(0);
30
+ } catch (error) {
31
+ log.error("Failed to list scheduled jobs:", error);
32
+ process.exit(1);
33
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import process from "node:process";
2
+ import { log } from "@stacksjs/logging";
3
+ import { startScheduler } from "@stacksjs/queue";
4
+ log.info("Starting job scheduler...");
5
+ try {
6
+ await startScheduler();
7
+ log.success("Scheduler is running. Press Ctrl+C to stop.");
8
+ await new Promise(() => {});
9
+ } catch (error) {
10
+ log.error("Failed to start scheduler:", error);
11
+ process.exit(1);
12
+ }
@@ -0,0 +1 @@
1
+ export {};