bunqueue-dashboard 0.0.16 → 0.0.17

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 (61) hide show
  1. package/agent/index.ts +8 -3
  2. package/agent/manager.ts +4 -2
  3. package/agent/server.ts +66 -2
  4. package/dist/.vite/manifest.json +63 -63
  5. package/dist/assets/{AddJob-CMIT6e17.js → AddJob-vk3jh1Zk.js} +2 -2
  6. package/dist/assets/Benchmark-CpViF2ZC.js +1 -0
  7. package/dist/assets/{CopilotPanel-BDZzDmVy.js → CopilotPanel-C9ojQ_8d.js} +3 -3
  8. package/dist/assets/{CopyButton-XT7ykzf5.js → CopyButton-BC6QECSJ.js} +1 -1
  9. package/dist/assets/{Cron-9hndZ-Z5.js → Cron-Bbf7mRaK.js} +1 -1
  10. package/dist/assets/{CronManager-BQupx6wZ.js → CronManager-CeNUeoOc.js} +1 -1
  11. package/dist/assets/Database--bK9pYZF.js +3 -0
  12. package/dist/assets/{Diagnostics-BzVDq9CH.js → Diagnostics-CGJPsWZQ.js} +1 -1
  13. package/dist/assets/Dlq-Bs1pupY2.js +1 -0
  14. package/dist/assets/{DlqControl-Cu2i1oq5.js → DlqControl-BLKVzYQC.js} +1 -1
  15. package/dist/assets/{DlqPro-HBrCftLD.js → DlqPro-D8SmIQUs.js} +1 -1
  16. package/dist/assets/{Flows-D3Bvkmd6.js → Flows-BOogljnP.js} +1 -1
  17. package/dist/assets/{JobInspector-B7zEuFhM.js → JobInspector-Cp4ZuQGI.js} +2 -2
  18. package/dist/assets/Jobs-C2HYkZXi.js +1 -0
  19. package/dist/assets/JobsPro-D0uclU0B.js +1 -0
  20. package/dist/assets/Logs-yn92V_T8.js +1 -0
  21. package/dist/assets/{LogsPro-P73LCkap.js → LogsPro-DSiV8Ajj.js} +1 -1
  22. package/dist/assets/{McpServer-CUK20-uN.js → McpServer-CNt7kssG.js} +2 -2
  23. package/dist/assets/{Metrics-BodjiKpf.js → Metrics-CbscCpvx.js} +1 -1
  24. package/dist/assets/MetricsPro-CBiFDVne.js +1 -0
  25. package/dist/assets/Overview-BOuOPWsb.js +1 -0
  26. package/dist/assets/{Pagination-Cd6lHj2E.js → Pagination-Bj1z6OlD.js} +1 -1
  27. package/dist/assets/QueueControl-Bl4l9dT6.js +1 -0
  28. package/dist/assets/QueueDetail-BSUH0Nl6.js +1 -0
  29. package/dist/assets/{Queues-LrodynCj.js → Queues-BEQlaWVc.js} +1 -1
  30. package/dist/assets/{QueuesOverview-DrYjyped.js → QueuesOverview-BBjcyzz2.js} +1 -1
  31. package/dist/assets/{S3Backup-et1PcCC0.js → S3Backup-BmRt-Z8V.js} +1 -1
  32. package/dist/assets/S3BackupPro-Dsq0erDm.js +1 -0
  33. package/dist/assets/ServerControl-Bhr9FEXF.js +3 -0
  34. package/dist/assets/Settings-46jsrfhd.js +1 -0
  35. package/dist/assets/{Usage-CHCg6VNy.js → Usage-BFLZC7pV.js} +1 -1
  36. package/dist/assets/{UsagePro-Cto9k5OI.js → UsagePro-D0k-82eG.js} +1 -1
  37. package/dist/assets/{Webhooks-Cm3vZEp7.js → Webhooks-DChTcBSv.js} +1 -1
  38. package/dist/assets/Workers-DBXrLvfS.js +1 -0
  39. package/dist/assets/{WorkersPro-BidtV_Bp.js → WorkersPro-B6I9Ilbq.js} +1 -1
  40. package/dist/assets/{connectionStore-DI-LYcct.js → connectionStore-CCopJeU7.js} +1 -1
  41. package/dist/assets/index-BFjeS9FG.js +8 -0
  42. package/dist/assets/{install-BvB40Zk0.js → install-C019EM5j.js} +2 -2
  43. package/dist/index.html +2 -2
  44. package/package.json +12 -10
  45. package/scripts/embedded.gen.ts +95 -94
  46. package/scripts/serve.ts +34 -2
  47. package/dist/assets/Benchmark-Dq1-vJ2k.js +0 -1
  48. package/dist/assets/Database-Difs7xYV.js +0 -3
  49. package/dist/assets/Dlq-BCUVh_NO.js +0 -1
  50. package/dist/assets/Jobs-ovYRwmwi.js +0 -1
  51. package/dist/assets/JobsPro-DNZivuzq.js +0 -1
  52. package/dist/assets/Logs-CjM7MNYN.js +0 -1
  53. package/dist/assets/MetricsPro-CqcH6gJp.js +0 -1
  54. package/dist/assets/Overview-AwCA3XI2.js +0 -1
  55. package/dist/assets/QueueControl-D7J1JObu.js +0 -1
  56. package/dist/assets/QueueDetail-BtiN0s3b.js +0 -1
  57. package/dist/assets/S3BackupPro-BEo_EVAO.js +0 -1
  58. package/dist/assets/ServerControl-BRLFRj7k.js +0 -3
  59. package/dist/assets/Settings-CeRZgZU6.js +0 -1
  60. package/dist/assets/Workers-CVfx3TK-.js +0 -1
  61. package/dist/assets/index-C9fPU4bV.js +0 -8
package/agent/index.ts CHANGED
@@ -13,14 +13,19 @@
13
13
  */
14
14
  import { logger } from './logger';
15
15
  import { ProcessManager } from './manager';
16
- import { createFetchHandler, resolveAllowedOrigins } from './server';
16
+ import { createFetchHandler, resolveAllowedHosts, resolveAllowedOrigins } from './server';
17
17
 
18
18
  const mgr = new ProcessManager();
19
19
  const PORT = Number(process.env.AGENT_PORT) || 6800;
20
20
  const allowedOrigins = resolveAllowedOrigins();
21
+ // The agent binds loopback only, so a legitimate Host is always a loopback
22
+ // hostname (localhost / 127.0.0.1). Enforcing the allowlist blocks a page whose
23
+ // DNS was rebound to 127.0.0.1 from reading /control or /db over same-origin
24
+ // GETs. Extend via AGENT_ALLOWED_HOSTS when fronted by a proxy on another host.
25
+ const allowedHosts = resolveAllowedHosts();
21
26
  const token = process.env.AGENT_TOKEN || undefined;
22
27
 
23
- const handle = createFetchHandler(mgr, { allowedOrigins, token });
28
+ const handle = createFetchHandler(mgr, { allowedOrigins, allowedHosts, token });
24
29
 
25
30
  Bun.serve({
26
31
  port: PORT,
@@ -42,6 +47,6 @@ process.on('SIGINT', () => shutdown('SIGINT'));
42
47
  process.on('SIGTERM', () => shutdown('SIGTERM'));
43
48
 
44
49
  logger.info(
45
- { url: `http://127.0.0.1:${PORT}/control`, allowedOrigins, tokenAuth: Boolean(token) },
50
+ { url: `http://127.0.0.1:${PORT}/control`, allowedOrigins, allowedHosts, tokenAuth: Boolean(token) },
46
51
  'bunqueue dashboard control agent ready'
47
52
  );
package/agent/manager.ts CHANGED
@@ -192,8 +192,10 @@ export class ProcessManager {
192
192
  this.status = 'running';
193
193
  this.runningConfig = { ...this.config, extraEnv: { ...this.config.extraEnv } };
194
194
  this.push('sys', `started: ${this.config.command} (pid ${this.proc.pid})`);
195
- void this.pipe(this.proc.stdout as ReadableStream<Uint8Array>, 'stdout');
196
- void this.pipe(this.proc.stderr as ReadableStream<Uint8Array>, 'stderr');
195
+ // stdout/stderr are spawned as pipes, so they are ReadableStreams at
196
+ // runtime; Bun types them as a union that also includes a numeric fd.
197
+ void this.pipe(this.proc.stdout as unknown as ReadableStream<Uint8Array>, 'stdout');
198
+ void this.pipe(this.proc.stderr as unknown as ReadableStream<Uint8Array>, 'stderr');
197
199
  return this.getStatus();
198
200
  }
199
201
 
package/agent/server.ts CHANGED
@@ -14,7 +14,15 @@
14
14
  * always sends `Origin`, so a drive-by page cannot start/stop/reconfigure
15
15
  * the server. Non-browser callers (curl, same-process) send no Origin and
16
16
  * still work for local use.
17
- * 3. Optional bearer token (AGENT_TOKEN): when set, state-changing requests
17
+ * 3. Host-header allowlist (DNS-rebinding defense). The Origin gate does NOT
18
+ * cover a *same-origin* request: a page whose DNS name is rebound to
19
+ * 127.0.0.1 issues same-origin GETs that carry no `Origin` header, so it
20
+ * could otherwise read /control/status, /control/logs and the /db/*
21
+ * inspector (job payloads) even with a token set (the token exempts reads).
22
+ * When `allowedHosts` is configured, a request whose `Host` header names a
23
+ * hostname outside the allowlist is rejected (403) — the rebinding page's
24
+ * `Host` is the attacker's domain, never a loopback/allowlisted host.
25
+ * 4. Optional bearer token (AGENT_TOKEN): when set, state-changing requests
18
26
  * must present it (`Authorization: Bearer <t>` or `x-agent-token: <t>`).
19
27
  */
20
28
  import { type DbFilter, dbCell, dbInfo, dbRows, dbSchema, dbTables, MissingDbError, queryWithTimeout } from './db';
@@ -22,12 +30,23 @@ import type { ProcessManager, ServerConfig } from './manager';
22
30
 
23
31
  export interface AgentOptions {
24
32
  allowedOrigins: string[];
33
+ /**
34
+ * DNS-rebinding defense: when set (non-empty), a request whose `Host` header
35
+ * resolves to a hostname outside this list is rejected. Compared by hostname
36
+ * only (port stripped). Leave undefined to disable the check — e.g. when the
37
+ * agent is fronted by a proxy that already validates Host, or bound to a
38
+ * non-loopback interface where the user opted into network exposure.
39
+ */
40
+ allowedHosts?: string[];
25
41
  /** When set, POST/PUT requests must present this token. */
26
42
  token?: string;
27
43
  }
28
44
 
29
45
  const DEFAULT_ORIGINS = ['http://localhost:5273', 'http://127.0.0.1:5273'];
30
46
 
47
+ /** Hostnames always trusted as loopback for the Host-header allowlist. */
48
+ const LOOPBACK_HOSTS = ['localhost', '127.0.0.1', '::1', '0.0.0.0'];
49
+
31
50
  /** Parse AGENT_ALLOWED_ORIGINS (comma-separated) merged with sane dev defaults. */
32
51
  export function resolveAllowedOrigins(env = process.env): string[] {
33
52
  const extra = (env.AGENT_ALLOWED_ORIGINS ?? '')
@@ -37,11 +56,49 @@ export function resolveAllowedOrigins(env = process.env): string[] {
37
56
  return Array.from(new Set([...DEFAULT_ORIGINS, ...extra]));
38
57
  }
39
58
 
59
+ /**
60
+ * Extract the bare hostname from a `Host` header or an origin/URL (strips a
61
+ * leading scheme and any port, unwraps IPv6 brackets, lowercases).
62
+ */
63
+ export function hostnameOf(host: string): string {
64
+ const s = host.trim().replace(/^[a-z][a-z0-9+.-]*:\/\//i, ''); // drop scheme:// if present
65
+ const v6 = s.match(/^\[([^\]]+)\]/); // [::1]:6800 → ::1
66
+ if (v6) return v6[1].toLowerCase();
67
+ const i = s.indexOf(':');
68
+ return (i === -1 ? s : s.slice(0, i)).toLowerCase();
69
+ }
70
+
71
+ /**
72
+ * Loopback hostnames plus any from AGENT_ALLOWED_HOSTS (comma-separated) and
73
+ * `extra` (hostnames or full origins of the served/allowlisted origins).
74
+ * Reduced to bare hostnames, deduped.
75
+ */
76
+ export function resolveAllowedHosts(env = process.env, extra: string[] = []): string[] {
77
+ const fromEnv = (env.AGENT_ALLOWED_HOSTS ?? '')
78
+ .split(',')
79
+ .map((s) => hostnameOf(s.trim()))
80
+ .filter(Boolean);
81
+ const extraHosts = extra.map((s) => hostnameOf(s)).filter(Boolean);
82
+ return Array.from(new Set([...LOOPBACK_HOSTS, ...extraHosts, ...fromEnv]));
83
+ }
84
+
40
85
  export function isOriginAllowed(origin: string | null, allowed: string[]): boolean {
41
86
  if (!origin) return true; // non-browser caller (curl / same process) — no Origin header
42
87
  return allowed.includes(origin.replace(/\/$/, ''));
43
88
  }
44
89
 
90
+ /**
91
+ * Host-header allowlist. Disabled (always true) when `allowed` is undefined. A
92
+ * missing Host header is a non-browser/loopback caller and is allowed; a
93
+ * present Host must match by hostname. A DNS-rebinding page always sends its
94
+ * own domain as Host, so it fails this check.
95
+ */
96
+ export function isHostAllowed(host: string | null, allowed?: string[]): boolean {
97
+ if (!allowed) return true;
98
+ if (!host) return true; // non-browser caller — no Host header
99
+ return allowed.includes(hostnameOf(host));
100
+ }
101
+
45
102
  /** CORS headers. ACAO is reflected only for an allowed origin (never `*`). */
46
103
  export function corsHeaders(origin: string | null, allowed: string[]): Record<string, string> {
47
104
  const h: Record<string, string> = {
@@ -67,7 +124,7 @@ function tokenOk(req: Request, token?: string): boolean {
67
124
  * ProcessManager and policy, returns an async (req) => Response.
68
125
  */
69
126
  export function createFetchHandler(mgr: ProcessManager, opts: AgentOptions) {
70
- const { allowedOrigins, token } = opts;
127
+ const { allowedOrigins, allowedHosts, token } = opts;
71
128
 
72
129
  const json = (data: unknown, status: number, origin: string | null): Response =>
73
130
  new Response(JSON.stringify(data), {
@@ -107,6 +164,13 @@ export function createFetchHandler(mgr: ProcessManager, opts: AgentOptions) {
107
164
  return new Response(null, { status: 204, headers: corsHeaders(origin, allowedOrigins) });
108
165
  }
109
166
 
167
+ // DNS-rebinding defense: reject a same-origin request whose Host header is
168
+ // an attacker domain rebound to loopback (no Origin header would be sent,
169
+ // so the Origin gate below can't see it). No-op when allowedHosts is unset.
170
+ if (!isHostAllowed(req.headers.get('host'), allowedHosts)) {
171
+ return json({ ok: false, error: 'Host not allowed' }, 403, origin);
172
+ }
173
+
110
174
  // Block any request from a disallowed browser origin before it can act.
111
175
  if (!isOriginAllowed(origin, allowedOrigins)) {
112
176
  return json({ ok: false, error: 'Origin not allowed' }, 403, origin);
@@ -7,8 +7,8 @@
7
7
  "_react-vendor-CHIHtdAC.js"
8
8
  ]
9
9
  },
10
- "_CopyButton-XT7ykzf5.js": {
11
- "file": "assets/CopyButton-XT7ykzf5.js",
10
+ "_CopyButton-BC6QECSJ.js": {
11
+ "file": "assets/CopyButton-BC6QECSJ.js",
12
12
  "name": "CopyButton",
13
13
  "imports": [
14
14
  "_cn-CMFYpumL.js",
@@ -16,8 +16,8 @@
16
16
  "index.html"
17
17
  ]
18
18
  },
19
- "_Pagination-Cd6lHj2E.js": {
20
- "file": "assets/Pagination-Cd6lHj2E.js",
19
+ "_Pagination-Bj1z6OlD.js": {
20
+ "file": "assets/Pagination-Bj1z6OlD.js",
21
21
  "name": "Pagination",
22
22
  "imports": [
23
23
  "_cn-CMFYpumL.js",
@@ -29,8 +29,8 @@
29
29
  "file": "assets/cn-CMFYpumL.js",
30
30
  "name": "cn"
31
31
  },
32
- "_connectionStore-DI-LYcct.js": {
33
- "file": "assets/connectionStore-DI-LYcct.js",
32
+ "_connectionStore-CCopJeU7.js": {
33
+ "file": "assets/connectionStore-CCopJeU7.js",
34
34
  "name": "connectionStore",
35
35
  "imports": [
36
36
  "_cn-CMFYpumL.js",
@@ -57,14 +57,14 @@
57
57
  ]
58
58
  },
59
59
  "index.html": {
60
- "file": "assets/index-C9fPU4bV.js",
60
+ "file": "assets/index-BFjeS9FG.js",
61
61
  "name": "index",
62
62
  "src": "index.html",
63
63
  "isEntry": true,
64
64
  "imports": [
65
65
  "_cn-CMFYpumL.js",
66
66
  "_react-vendor-CHIHtdAC.js",
67
- "_connectionStore-DI-LYcct.js"
67
+ "_connectionStore-CCopJeU7.js"
68
68
  ],
69
69
  "dynamicImports": [
70
70
  "src/components/copilot/CopilotPanel.tsx",
@@ -129,7 +129,7 @@
129
129
  "src": "node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-latin-wght-normal.woff2"
130
130
  },
131
131
  "src/components/copilot/CopilotPanel.tsx": {
132
- "file": "assets/CopilotPanel-BDZzDmVy.js",
132
+ "file": "assets/CopilotPanel-C9ojQ_8d.js",
133
133
  "name": "CopilotPanel",
134
134
  "src": "src/components/copilot/CopilotPanel.tsx",
135
135
  "isDynamicEntry": true,
@@ -141,13 +141,13 @@
141
141
  ]
142
142
  },
143
143
  "src/lib/demo/install.ts": {
144
- "file": "assets/install-BvB40Zk0.js",
144
+ "file": "assets/install-C019EM5j.js",
145
145
  "name": "install",
146
146
  "src": "src/lib/demo/install.ts",
147
147
  "isDynamicEntry": true
148
148
  },
149
149
  "src/pages/Cron.tsx": {
150
- "file": "assets/Cron-9hndZ-Z5.js",
150
+ "file": "assets/Cron-Bbf7mRaK.js",
151
151
  "name": "Cron",
152
152
  "src": "src/pages/Cron.tsx",
153
153
  "isDynamicEntry": true,
@@ -155,11 +155,11 @@
155
155
  "_cn-CMFYpumL.js",
156
156
  "_react-vendor-CHIHtdAC.js",
157
157
  "index.html",
158
- "_Pagination-Cd6lHj2E.js"
158
+ "_Pagination-Bj1z6OlD.js"
159
159
  ]
160
160
  },
161
161
  "src/pages/Dlq.tsx": {
162
- "file": "assets/Dlq-BCUVh_NO.js",
162
+ "file": "assets/Dlq-Bs1pupY2.js",
163
163
  "name": "Dlq",
164
164
  "src": "src/pages/Dlq.tsx",
165
165
  "isDynamicEntry": true,
@@ -168,11 +168,11 @@
168
168
  "_react-vendor-CHIHtdAC.js",
169
169
  "index.html",
170
170
  "_form-PtDLk33Z.js",
171
- "_Pagination-Cd6lHj2E.js"
171
+ "_Pagination-Bj1z6OlD.js"
172
172
  ]
173
173
  },
174
174
  "src/pages/Jobs.tsx": {
175
- "file": "assets/Jobs-ovYRwmwi.js",
175
+ "file": "assets/Jobs-C2HYkZXi.js",
176
176
  "name": "Jobs",
177
177
  "src": "src/pages/Jobs.tsx",
178
178
  "isDynamicEntry": true,
@@ -184,7 +184,7 @@
184
184
  ]
185
185
  },
186
186
  "src/pages/Logs.tsx": {
187
- "file": "assets/Logs-CjM7MNYN.js",
187
+ "file": "assets/Logs-yn92V_T8.js",
188
188
  "name": "Logs",
189
189
  "src": "src/pages/Logs.tsx",
190
190
  "isDynamicEntry": true,
@@ -193,11 +193,11 @@
193
193
  "_react-vendor-CHIHtdAC.js",
194
194
  "index.html",
195
195
  "_form-PtDLk33Z.js",
196
- "_Pagination-Cd6lHj2E.js"
196
+ "_Pagination-Bj1z6OlD.js"
197
197
  ]
198
198
  },
199
199
  "src/pages/Metrics.tsx": {
200
- "file": "assets/Metrics-BodjiKpf.js",
200
+ "file": "assets/Metrics-CbscCpvx.js",
201
201
  "name": "Metrics",
202
202
  "src": "src/pages/Metrics.tsx",
203
203
  "isDynamicEntry": true,
@@ -207,7 +207,7 @@
207
207
  ]
208
208
  },
209
209
  "src/pages/Overview.tsx": {
210
- "file": "assets/Overview-AwCA3XI2.js",
210
+ "file": "assets/Overview-BOuOPWsb.js",
211
211
  "name": "Overview",
212
212
  "src": "src/pages/Overview.tsx",
213
213
  "isDynamicEntry": true,
@@ -217,7 +217,7 @@
217
217
  ]
218
218
  },
219
219
  "src/pages/QueueDetail.tsx": {
220
- "file": "assets/QueueDetail-BtiN0s3b.js",
220
+ "file": "assets/QueueDetail-BSUH0Nl6.js",
221
221
  "name": "QueueDetail",
222
222
  "src": "src/pages/QueueDetail.tsx",
223
223
  "isDynamicEntry": true,
@@ -229,7 +229,7 @@
229
229
  ]
230
230
  },
231
231
  "src/pages/Queues.tsx": {
232
- "file": "assets/Queues-LrodynCj.js",
232
+ "file": "assets/Queues-BEQlaWVc.js",
233
233
  "name": "Queues",
234
234
  "src": "src/pages/Queues.tsx",
235
235
  "isDynamicEntry": true,
@@ -237,11 +237,11 @@
237
237
  "_cn-CMFYpumL.js",
238
238
  "_react-vendor-CHIHtdAC.js",
239
239
  "index.html",
240
- "_Pagination-Cd6lHj2E.js"
240
+ "_Pagination-Bj1z6OlD.js"
241
241
  ]
242
242
  },
243
243
  "src/pages/S3Backup.tsx": {
244
- "file": "assets/S3Backup-et1PcCC0.js",
244
+ "file": "assets/S3Backup-BmRt-Z8V.js",
245
245
  "name": "S3Backup",
246
246
  "src": "src/pages/S3Backup.tsx",
247
247
  "isDynamicEntry": true,
@@ -251,20 +251,20 @@
251
251
  ]
252
252
  },
253
253
  "src/pages/Settings.tsx": {
254
- "file": "assets/Settings-CeRZgZU6.js",
254
+ "file": "assets/Settings-46jsrfhd.js",
255
255
  "name": "Settings",
256
256
  "src": "src/pages/Settings.tsx",
257
257
  "isDynamicEntry": true,
258
258
  "imports": [
259
259
  "_cn-CMFYpumL.js",
260
260
  "_react-vendor-CHIHtdAC.js",
261
- "_connectionStore-DI-LYcct.js",
261
+ "_connectionStore-CCopJeU7.js",
262
262
  "index.html",
263
263
  "_form-PtDLk33Z.js"
264
264
  ]
265
265
  },
266
266
  "src/pages/Usage.tsx": {
267
- "file": "assets/Usage-CHCg6VNy.js",
267
+ "file": "assets/Usage-BFLZC7pV.js",
268
268
  "name": "Usage",
269
269
  "src": "src/pages/Usage.tsx",
270
270
  "isDynamicEntry": true,
@@ -274,7 +274,7 @@
274
274
  ]
275
275
  },
276
276
  "src/pages/Workers.tsx": {
277
- "file": "assets/Workers-CVfx3TK-.js",
277
+ "file": "assets/Workers-DBXrLvfS.js",
278
278
  "name": "Workers",
279
279
  "src": "src/pages/Workers.tsx",
280
280
  "isDynamicEntry": true,
@@ -282,11 +282,11 @@
282
282
  "_cn-CMFYpumL.js",
283
283
  "_react-vendor-CHIHtdAC.js",
284
284
  "index.html",
285
- "_Pagination-Cd6lHj2E.js"
285
+ "_Pagination-Bj1z6OlD.js"
286
286
  ]
287
287
  },
288
288
  "src/pages/control/AddJob.tsx": {
289
- "file": "assets/AddJob-CMIT6e17.js",
289
+ "file": "assets/AddJob-vk3jh1Zk.js",
290
290
  "name": "AddJob",
291
291
  "src": "src/pages/control/AddJob.tsx",
292
292
  "isDynamicEntry": true,
@@ -298,7 +298,7 @@
298
298
  ]
299
299
  },
300
300
  "src/pages/control/Benchmark.tsx": {
301
- "file": "assets/Benchmark-Dq1-vJ2k.js",
301
+ "file": "assets/Benchmark-CpViF2ZC.js",
302
302
  "name": "Benchmark",
303
303
  "src": "src/pages/control/Benchmark.tsx",
304
304
  "isDynamicEntry": true,
@@ -308,11 +308,11 @@
308
308
  "index.html",
309
309
  "_form-PtDLk33Z.js",
310
310
  "_AreaChart-DzUXW8u3.js",
311
- "_CopyButton-XT7ykzf5.js"
311
+ "_CopyButton-BC6QECSJ.js"
312
312
  ]
313
313
  },
314
314
  "src/pages/control/CronManager.tsx": {
315
- "file": "assets/CronManager-BQupx6wZ.js",
315
+ "file": "assets/CronManager-CeNUeoOc.js",
316
316
  "name": "CronManager",
317
317
  "src": "src/pages/control/CronManager.tsx",
318
318
  "isDynamicEntry": true,
@@ -321,11 +321,11 @@
321
321
  "_react-vendor-CHIHtdAC.js",
322
322
  "index.html",
323
323
  "_form-PtDLk33Z.js",
324
- "_Pagination-Cd6lHj2E.js"
324
+ "_Pagination-Bj1z6OlD.js"
325
325
  ]
326
326
  },
327
327
  "src/pages/control/Database.tsx": {
328
- "file": "assets/Database-Difs7xYV.js",
328
+ "file": "assets/Database--bK9pYZF.js",
329
329
  "name": "Database",
330
330
  "src": "src/pages/control/Database.tsx",
331
331
  "isDynamicEntry": true,
@@ -334,12 +334,12 @@
334
334
  "_react-vendor-CHIHtdAC.js",
335
335
  "index.html",
336
336
  "_form-PtDLk33Z.js",
337
- "_Pagination-Cd6lHj2E.js",
338
- "_CopyButton-XT7ykzf5.js"
337
+ "_Pagination-Bj1z6OlD.js",
338
+ "_CopyButton-BC6QECSJ.js"
339
339
  ]
340
340
  },
341
341
  "src/pages/control/Diagnostics.tsx": {
342
- "file": "assets/Diagnostics-BzVDq9CH.js",
342
+ "file": "assets/Diagnostics-CGJPsWZQ.js",
343
343
  "name": "Diagnostics",
344
344
  "src": "src/pages/control/Diagnostics.tsx",
345
345
  "isDynamicEntry": true,
@@ -350,7 +350,7 @@
350
350
  ]
351
351
  },
352
352
  "src/pages/control/DlqControl.tsx": {
353
- "file": "assets/DlqControl-Cu2i1oq5.js",
353
+ "file": "assets/DlqControl-BLKVzYQC.js",
354
354
  "name": "DlqControl",
355
355
  "src": "src/pages/control/DlqControl.tsx",
356
356
  "isDynamicEntry": true,
@@ -359,11 +359,11 @@
359
359
  "_react-vendor-CHIHtdAC.js",
360
360
  "index.html",
361
361
  "_form-PtDLk33Z.js",
362
- "_Pagination-Cd6lHj2E.js"
362
+ "_Pagination-Bj1z6OlD.js"
363
363
  ]
364
364
  },
365
365
  "src/pages/control/DlqPro.tsx": {
366
- "file": "assets/DlqPro-HBrCftLD.js",
366
+ "file": "assets/DlqPro-D8SmIQUs.js",
367
367
  "name": "DlqPro",
368
368
  "src": "src/pages/control/DlqPro.tsx",
369
369
  "isDynamicEntry": true,
@@ -372,11 +372,11 @@
372
372
  "_react-vendor-CHIHtdAC.js",
373
373
  "index.html",
374
374
  "_form-PtDLk33Z.js",
375
- "_Pagination-Cd6lHj2E.js"
375
+ "_Pagination-Bj1z6OlD.js"
376
376
  ]
377
377
  },
378
378
  "src/pages/control/Flows.tsx": {
379
- "file": "assets/Flows-D3Bvkmd6.js",
379
+ "file": "assets/Flows-BOogljnP.js",
380
380
  "name": "Flows",
381
381
  "src": "src/pages/control/Flows.tsx",
382
382
  "isDynamicEntry": true,
@@ -387,7 +387,7 @@
387
387
  ]
388
388
  },
389
389
  "src/pages/control/JobInspector.tsx": {
390
- "file": "assets/JobInspector-B7zEuFhM.js",
390
+ "file": "assets/JobInspector-Cp4ZuQGI.js",
391
391
  "name": "JobInspector",
392
392
  "src": "src/pages/control/JobInspector.tsx",
393
393
  "isDynamicEntry": true,
@@ -396,12 +396,12 @@
396
396
  "_react-vendor-CHIHtdAC.js",
397
397
  "index.html",
398
398
  "_form-PtDLk33Z.js",
399
- "_CopyButton-XT7ykzf5.js",
399
+ "_CopyButton-BC6QECSJ.js",
400
400
  "_jobActions-CuOdMglt.js"
401
401
  ]
402
402
  },
403
403
  "src/pages/control/JobsPro.tsx": {
404
- "file": "assets/JobsPro-DNZivuzq.js",
404
+ "file": "assets/JobsPro-D0uclU0B.js",
405
405
  "name": "JobsPro",
406
406
  "src": "src/pages/control/JobsPro.tsx",
407
407
  "isDynamicEntry": true,
@@ -410,12 +410,12 @@
410
410
  "_react-vendor-CHIHtdAC.js",
411
411
  "index.html",
412
412
  "_form-PtDLk33Z.js",
413
- "_Pagination-Cd6lHj2E.js",
413
+ "_Pagination-Bj1z6OlD.js",
414
414
  "_jobActions-CuOdMglt.js"
415
415
  ]
416
416
  },
417
417
  "src/pages/control/LogsPro.tsx": {
418
- "file": "assets/LogsPro-P73LCkap.js",
418
+ "file": "assets/LogsPro-DSiV8Ajj.js",
419
419
  "name": "LogsPro",
420
420
  "src": "src/pages/control/LogsPro.tsx",
421
421
  "isDynamicEntry": true,
@@ -424,22 +424,22 @@
424
424
  "_react-vendor-CHIHtdAC.js",
425
425
  "index.html",
426
426
  "_form-PtDLk33Z.js",
427
- "_Pagination-Cd6lHj2E.js"
427
+ "_Pagination-Bj1z6OlD.js"
428
428
  ]
429
429
  },
430
430
  "src/pages/control/McpServer.tsx": {
431
- "file": "assets/McpServer-CUK20-uN.js",
431
+ "file": "assets/McpServer-CNt7kssG.js",
432
432
  "name": "McpServer",
433
433
  "src": "src/pages/control/McpServer.tsx",
434
434
  "isDynamicEntry": true,
435
435
  "imports": [
436
436
  "_react-vendor-CHIHtdAC.js",
437
437
  "index.html",
438
- "_CopyButton-XT7ykzf5.js"
438
+ "_CopyButton-BC6QECSJ.js"
439
439
  ]
440
440
  },
441
441
  "src/pages/control/MetricsPro.tsx": {
442
- "file": "assets/MetricsPro-CqcH6gJp.js",
442
+ "file": "assets/MetricsPro-CBiFDVne.js",
443
443
  "name": "MetricsPro",
444
444
  "src": "src/pages/control/MetricsPro.tsx",
445
445
  "isDynamicEntry": true,
@@ -447,12 +447,12 @@
447
447
  "_cn-CMFYpumL.js",
448
448
  "_react-vendor-CHIHtdAC.js",
449
449
  "index.html",
450
- "_Pagination-Cd6lHj2E.js",
450
+ "_Pagination-Bj1z6OlD.js",
451
451
  "_AreaChart-DzUXW8u3.js"
452
452
  ]
453
453
  },
454
454
  "src/pages/control/QueueControl.tsx": {
455
- "file": "assets/QueueControl-D7J1JObu.js",
455
+ "file": "assets/QueueControl-Bl4l9dT6.js",
456
456
  "name": "QueueControl",
457
457
  "src": "src/pages/control/QueueControl.tsx",
458
458
  "isDynamicEntry": true,
@@ -464,7 +464,7 @@
464
464
  ]
465
465
  },
466
466
  "src/pages/control/QueuesOverview.tsx": {
467
- "file": "assets/QueuesOverview-DrYjyped.js",
467
+ "file": "assets/QueuesOverview-BBjcyzz2.js",
468
468
  "name": "QueuesOverview",
469
469
  "src": "src/pages/control/QueuesOverview.tsx",
470
470
  "isDynamicEntry": true,
@@ -472,24 +472,24 @@
472
472
  "_cn-CMFYpumL.js",
473
473
  "_react-vendor-CHIHtdAC.js",
474
474
  "index.html",
475
- "_Pagination-Cd6lHj2E.js"
475
+ "_Pagination-Bj1z6OlD.js"
476
476
  ]
477
477
  },
478
478
  "src/pages/control/S3BackupPro.tsx": {
479
- "file": "assets/S3BackupPro-BEo_EVAO.js",
479
+ "file": "assets/S3BackupPro-Dsq0erDm.js",
480
480
  "name": "S3BackupPro",
481
481
  "src": "src/pages/control/S3BackupPro.tsx",
482
482
  "isDynamicEntry": true,
483
483
  "imports": [
484
484
  "_cn-CMFYpumL.js",
485
485
  "_react-vendor-CHIHtdAC.js",
486
- "_connectionStore-DI-LYcct.js",
486
+ "_connectionStore-CCopJeU7.js",
487
487
  "index.html",
488
488
  "_form-PtDLk33Z.js"
489
489
  ]
490
490
  },
491
491
  "src/pages/control/ServerControl.tsx": {
492
- "file": "assets/ServerControl-BRLFRj7k.js",
492
+ "file": "assets/ServerControl-Bhr9FEXF.js",
493
493
  "name": "ServerControl",
494
494
  "src": "src/pages/control/ServerControl.tsx",
495
495
  "isDynamicEntry": true,
@@ -498,11 +498,11 @@
498
498
  "_react-vendor-CHIHtdAC.js",
499
499
  "index.html",
500
500
  "_form-PtDLk33Z.js",
501
- "_CopyButton-XT7ykzf5.js"
501
+ "_CopyButton-BC6QECSJ.js"
502
502
  ]
503
503
  },
504
504
  "src/pages/control/UsagePro.tsx": {
505
- "file": "assets/UsagePro-Cto9k5OI.js",
505
+ "file": "assets/UsagePro-D0k-82eG.js",
506
506
  "name": "UsagePro",
507
507
  "src": "src/pages/control/UsagePro.tsx",
508
508
  "isDynamicEntry": true,
@@ -512,7 +512,7 @@
512
512
  ]
513
513
  },
514
514
  "src/pages/control/Webhooks.tsx": {
515
- "file": "assets/Webhooks-Cm3vZEp7.js",
515
+ "file": "assets/Webhooks-DChTcBSv.js",
516
516
  "name": "Webhooks",
517
517
  "src": "src/pages/control/Webhooks.tsx",
518
518
  "isDynamicEntry": true,
@@ -521,11 +521,11 @@
521
521
  "_react-vendor-CHIHtdAC.js",
522
522
  "index.html",
523
523
  "_form-PtDLk33Z.js",
524
- "_Pagination-Cd6lHj2E.js"
524
+ "_Pagination-Bj1z6OlD.js"
525
525
  ]
526
526
  },
527
527
  "src/pages/control/WorkersPro.tsx": {
528
- "file": "assets/WorkersPro-BidtV_Bp.js",
528
+ "file": "assets/WorkersPro-B6I9Ilbq.js",
529
529
  "name": "WorkersPro",
530
530
  "src": "src/pages/control/WorkersPro.tsx",
531
531
  "isDynamicEntry": true,
@@ -1,3 +1,3 @@
1
- import{r as e}from"./cn-CMFYpumL.js";import{m as t,t as n}from"./react-vendor-CHIHtdAC.js";import{D as r,E as i,T as a,g as o,j as s,v as c}from"./index-C9fPU4bV.js";import{n as l,o as u,t as d}from"./form-PtDLk33Z.js";var f=e(t(),1),p=n();function m(){let{data:e}=s(()=>o.queues(),[],{intervalMs:3e4}),[t,n]=(0,f.useState)(``),[u,m]=(0,f.useState)(`{
1
+ import{r as e}from"./cn-CMFYpumL.js";import{m as t,t as n}from"./react-vendor-CHIHtdAC.js";import{C as r,O as i,S as a,Z as o,h as s,w as c}from"./index-BFjeS9FG.js";import{n as l,o as u,t as d}from"./form-PtDLk33Z.js";var f=e(t(),1),p=n();function m(){let{data:e}=i(()=>o.queues(),[],{intervalMs:3e4}),[t,n]=(0,f.useState)(``),[u,m]=(0,f.useState)(`{
2
2
  "hello": "world"
3
- }`),[g,_]=(0,f.useState)(`1`),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(``),[E,D]=(0,f.useState)(``),[O,k]=(0,f.useState)(``),[A,j]=(0,f.useState)(!1),[M,N]=(0,f.useState)(!1),[P,F]=(0,f.useState)(!1),[I,L]=(0,f.useState)(!1),[R,z]=(0,f.useState)(!1),[B,V]=(0,f.useState)(null),[H,U]=(0,f.useState)(null),W=e=>{let t=Number(e);return e.trim()!==``&&Number.isFinite(t)?t:void 0},G=async()=>{if(V(null),U(null),!t.trim()){V({ok:!1,msg:`Choose a queue`});return}let e;try{e=JSON.parse(u)}catch(e){U(`Invalid JSON: ${e.message}`);return}let n={data:e,priority:W(v),delay:W(b),maxAttempts:W(S),backoff:W(w),timeout:W(E),jobId:O.trim()||void 0,removeOnComplete:A||void 0,removeOnFail:M||void 0,durable:P||void 0,lifo:I||void 0},r=W(g)??1;if(!Number.isInteger(r)||r<1){V({ok:!1,msg:`Count must be an integer of at least 1`});return}if(r>1e4){V({ok:!1,msg:`Count must be 10000 or fewer`});return}z(!0);try{if(r===1)V({ok:!0,msg:`Created job ${(await o.addJob(t,n)).id}`});else{let e=await o.addJobsBulk(t,Array.from({length:r},()=>n)),i=new Set(e.ids).size;V({ok:!0,msg:`Created ${i} job${i===1?``:`s`}`})}}catch(e){V({ok:!1,msg:e.message})}finally{z(!1)}};return(0,p.jsxs)(`div`,{children:[(0,p.jsx)(c,{title:`Add Job`,description:`Enqueue a job with full options.`}),(0,p.jsxs)(`form`,{className:`grid grid-cols-1 gap-6 lg:grid-cols-2`,onSubmit:e=>{e.preventDefault(),G()},children:[(0,p.jsxs)(a,{children:[(0,p.jsx)(i,{title:`Job`}),(0,p.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,p.jsxs)(d,{label:`Queue`,children:[(0,p.jsx)(l,{list:`queue-options`,value:t,onChange:e=>n(e.target.value),placeholder:`queue name (existing or new)`}),(0,p.jsx)(`datalist`,{id:`queue-options`,children:(e?.queues??[]).map(e=>(0,p.jsx)(`option`,{value:e.name},e.name))})]}),(0,p.jsxs)(`div`,{children:[(0,p.jsx)(d,{label:`Data (JSON)`,children:(0,p.jsx)(`textarea`,{value:u,onChange:e=>m(e.target.value),spellCheck:!1,rows:7,className:`w-full rounded-lg border border-line bg-surface-2 p-3 font-mono text-sm text-fg focus:border-accent/60 focus:outline-none focus:ring-2 focus:ring-accent/30`})}),H&&(0,p.jsx)(`p`,{className:`mt-2 text-xs text-danger`,children:H})]})]})]}),(0,p.jsxs)(a,{children:[(0,p.jsx)(i,{title:`Options`}),(0,p.jsxs)(`div`,{className:`grid grid-cols-2 gap-4 md:grid-cols-3`,children:[(0,p.jsx)(d,{label:`Priority`,children:(0,p.jsx)(l,{type:`number`,value:v,onChange:e=>y(e.target.value),placeholder:`0`})}),(0,p.jsx)(d,{label:`Delay (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:b,onChange:e=>x(e.target.value),placeholder:`0`})}),(0,p.jsx)(d,{label:`Max attempts`,children:(0,p.jsx)(l,{type:`number`,min:1,value:S,onChange:e=>C(e.target.value),placeholder:`3`})}),(0,p.jsx)(d,{label:`Backoff (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:w,onChange:e=>T(e.target.value),placeholder:`1000`})}),(0,p.jsx)(d,{label:`Timeout (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:E,onChange:e=>D(e.target.value),placeholder:`—`})}),(0,p.jsx)(d,{label:`Custom job ID`,children:(0,p.jsx)(l,{value:O,onChange:e=>k(e.target.value),placeholder:`idempotency key`})})]}),(0,p.jsxs)(`div`,{className:`mt-4 flex flex-wrap gap-6`,children:[(0,p.jsx)(h,{label:`removeOnComplete`,checked:A,onChange:j}),(0,p.jsx)(h,{label:`removeOnFail`,checked:M,onChange:N}),(0,p.jsx)(h,{label:`durable`,checked:P,onChange:F}),(0,p.jsx)(h,{label:`lifo`,checked:I,onChange:L})]})]}),(0,p.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3 lg:col-span-2`,children:[(0,p.jsx)(`div`,{className:`w-28`,children:(0,p.jsx)(d,{label:`Count`,children:(0,p.jsx)(l,{type:`number`,min:1,value:g,onChange:e=>_(e.target.value)})})}),(0,p.jsx)(r,{type:`submit`,variant:`accent`,disabled:R,children:R?`Adding…`:`Add job`}),B&&(0,p.jsx)(`span`,{className:B.ok?`text-sm text-success`:`text-sm text-danger`,children:B.msg})]})]})]})}function h({label:e,checked:t,onChange:n}){return(0,p.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,p.jsx)(u,{checked:t,onChange:n,label:e}),(0,p.jsx)(`span`,{className:`font-mono text-xs text-muted`,children:e})]})}export{m as AddJob};
3
+ }`),[g,_]=(0,f.useState)(`1`),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(``),[E,D]=(0,f.useState)(``),[O,k]=(0,f.useState)(``),[A,j]=(0,f.useState)(!1),[M,N]=(0,f.useState)(!1),[P,F]=(0,f.useState)(!1),[I,L]=(0,f.useState)(!1),[R,z]=(0,f.useState)(!1),[B,V]=(0,f.useState)(null),[H,U]=(0,f.useState)(null),W=e=>{let t=Number(e);return e.trim()!==``&&Number.isFinite(t)?t:void 0},G=async()=>{if(V(null),U(null),!t.trim()){V({ok:!1,msg:`Choose a queue`});return}let e;try{e=JSON.parse(u)}catch(e){U(`Invalid JSON: ${e.message}`);return}let n={data:e,priority:W(v),delay:W(b),maxAttempts:W(S),backoff:W(w),timeout:W(E),jobId:O.trim()||void 0,removeOnComplete:A||void 0,removeOnFail:M||void 0,durable:P||void 0,lifo:I||void 0},r=W(g)??1;if(!Number.isInteger(r)||r<1){V({ok:!1,msg:`Count must be an integer of at least 1`});return}if(r>1e4){V({ok:!1,msg:`Count must be 10000 or fewer`});return}z(!0);try{if(r===1)V({ok:!0,msg:`Created job ${(await o.addJob(t,n)).id}`});else{let e=await o.addJobsBulk(t,Array.from({length:r},()=>n)),i=new Set(e.ids).size;V({ok:!0,msg:`Created ${i} job${i===1?``:`s`}`})}}catch(e){V({ok:!1,msg:e.message})}finally{z(!1)}};return(0,p.jsxs)(`div`,{children:[(0,p.jsx)(s,{title:`Add Job`,description:`Enqueue a job with full options.`}),(0,p.jsxs)(`form`,{className:`grid grid-cols-1 gap-6 lg:grid-cols-2`,onSubmit:e=>{e.preventDefault(),G()},children:[(0,p.jsxs)(a,{children:[(0,p.jsx)(r,{title:`Job`}),(0,p.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,p.jsxs)(d,{label:`Queue`,children:[(0,p.jsx)(l,{list:`queue-options`,value:t,onChange:e=>n(e.target.value),placeholder:`queue name (existing or new)`}),(0,p.jsx)(`datalist`,{id:`queue-options`,children:(e?.queues??[]).map(e=>(0,p.jsx)(`option`,{value:e.name},e.name))})]}),(0,p.jsxs)(`div`,{children:[(0,p.jsx)(d,{label:`Data (JSON)`,children:(0,p.jsx)(`textarea`,{value:u,onChange:e=>m(e.target.value),spellCheck:!1,rows:7,className:`w-full rounded-lg border border-line bg-surface-2 p-3 font-mono text-sm text-fg focus:border-accent/60 focus:outline-none focus:ring-2 focus:ring-accent/30`})}),H&&(0,p.jsx)(`p`,{className:`mt-2 text-xs text-danger`,children:H})]})]})]}),(0,p.jsxs)(a,{children:[(0,p.jsx)(r,{title:`Options`}),(0,p.jsxs)(`div`,{className:`grid grid-cols-2 gap-4 md:grid-cols-3`,children:[(0,p.jsx)(d,{label:`Priority`,children:(0,p.jsx)(l,{type:`number`,value:v,onChange:e=>y(e.target.value),placeholder:`0`})}),(0,p.jsx)(d,{label:`Delay (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:b,onChange:e=>x(e.target.value),placeholder:`0`})}),(0,p.jsx)(d,{label:`Max attempts`,children:(0,p.jsx)(l,{type:`number`,min:1,value:S,onChange:e=>C(e.target.value),placeholder:`3`})}),(0,p.jsx)(d,{label:`Backoff (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:w,onChange:e=>T(e.target.value),placeholder:`1000`})}),(0,p.jsx)(d,{label:`Timeout (ms)`,children:(0,p.jsx)(l,{type:`number`,min:0,value:E,onChange:e=>D(e.target.value),placeholder:`—`})}),(0,p.jsx)(d,{label:`Custom job ID`,children:(0,p.jsx)(l,{value:O,onChange:e=>k(e.target.value),placeholder:`idempotency key`})})]}),(0,p.jsxs)(`div`,{className:`mt-4 flex flex-wrap gap-6`,children:[(0,p.jsx)(h,{label:`removeOnComplete`,checked:A,onChange:j}),(0,p.jsx)(h,{label:`removeOnFail`,checked:M,onChange:N}),(0,p.jsx)(h,{label:`durable`,checked:P,onChange:F}),(0,p.jsx)(h,{label:`lifo`,checked:I,onChange:L})]})]}),(0,p.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3 lg:col-span-2`,children:[(0,p.jsx)(`div`,{className:`w-28`,children:(0,p.jsx)(d,{label:`Count`,children:(0,p.jsx)(l,{type:`number`,min:1,value:g,onChange:e=>_(e.target.value)})})}),(0,p.jsx)(c,{type:`submit`,variant:`accent`,disabled:R,children:R?`Adding…`:`Add job`}),B&&(0,p.jsx)(`span`,{className:B.ok?`text-sm text-success`:`text-sm text-danger`,children:B.msg})]})]})]})}function h({label:e,checked:t,onChange:n}){return(0,p.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,p.jsx)(u,{checked:t,onChange:n,label:e}),(0,p.jsx)(`span`,{className:`font-mono text-xs text-muted`,children:e})]})}export{m as AddJob};