@pg-boss/dashboard 1.0.1 → 1.1.1

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 (41) hide show
  1. package/README.md +25 -173
  2. package/build/client/assets/MenuTrigger-CEHCnGow.js +1 -0
  3. package/build/client/assets/{_index-Bcg_-XSd.js → _index-9fLquIe1.js} +1 -1
  4. package/build/client/assets/{badge-Cd8v3tl3.js → badge-B5ZugmiV.js} +1 -1
  5. package/build/client/assets/{button-BaXUPm8v.js → button-Djse56Dx.js} +1 -1
  6. package/build/client/assets/{chevron-down-xu6Uceu-.js → chevron-down-B4tDL9Ah.js} +1 -1
  7. package/build/client/assets/chunk-LFPYN7LY-Cj1DJmJR.js +26 -0
  8. package/build/client/assets/{createLucideIcon-BXGwbdrh.js → createLucideIcon-B0YqJFaz.js} +1 -1
  9. package/build/client/assets/db-link-DmvfwdX4.js +1 -0
  10. package/build/client/assets/dialog-CQzw3QVH.js +1 -0
  11. package/build/client/assets/{entry.client-COnaNoy-.js → entry.client-Szv-xmaE.js} +4 -4
  12. package/build/client/assets/{error-card-DmoxS3Ao.js → error-card-CXoOCvsg.js} +1 -1
  13. package/build/client/assets/{filter-select-mMC79WOR.js → filter-select-DXyBBVm8.js} +1 -1
  14. package/build/client/assets/{index-DhMkYPMa.js → index-x2yWco1W.js} +1 -1
  15. package/build/client/assets/{jobs-DtmTCs8I.js → jobs-CM6xcK-O.js} +1 -1
  16. package/build/client/assets/manifest-acaa4b8e.js +1 -0
  17. package/build/client/assets/{pagination-NfhvsUbp.js → pagination-C4yyCmBA.js} +1 -1
  18. package/build/client/assets/{queues._index-Cw1B49mg.js → queues._index-Dn3ieC5d.js} +1 -1
  19. package/build/client/assets/{queues._name-D0cG_qDX.js → queues._name-GrviLLx2.js} +1 -1
  20. package/build/client/assets/{queues._name.jobs._jobId-uJ3dfM3J.js → queues._name.jobs._jobId-s_wYs79w.js} +1 -1
  21. package/build/client/assets/{queues.create-BGXDhJ3m.js → queues.create-Ch3Mqw52.js} +1 -1
  22. package/build/client/assets/root-Bpb4WtY4.css +1 -0
  23. package/build/client/assets/{root-NWrBrGvr.js → root-D0qqtdF7.js} +1 -1
  24. package/build/client/assets/{schedules-DzgBEayh.js → schedules-DwnuuhxF.js} +1 -1
  25. package/build/client/assets/{schedules._name._key-i42S9kw2.js → schedules._name._key-DJn-u3Cm.js} +1 -1
  26. package/build/client/assets/{schedules.new-Dt78KptL.js → schedules.new-CQuE2Uhz.js} +1 -1
  27. package/build/client/assets/{send-0eWgiWNl.js → send-DVfuC6NR.js} +1 -1
  28. package/build/client/assets/{table-CTo0I5HG.js → table-CtSLyG7m.js} +1 -1
  29. package/build/client/assets/useOpenInteractionType-Ss_6xZdw.js +12 -0
  30. package/build/client/assets/{warnings-BhQM6lFV.js → warnings-DqRQYomb.js} +1 -1
  31. package/build/server/assets/auth.server-DgTIakNo.js +17 -0
  32. package/build/server/assets/server-build.js +305 -39
  33. package/build/server/index.js +5 -0
  34. package/package.json +16 -15
  35. package/build/client/assets/MenuTrigger-SThQHnlb.js +0 -1
  36. package/build/client/assets/chunk-JZWAC4HX-DC8i-F7r.js +0 -26
  37. package/build/client/assets/db-link-CtPnIrIr.js +0 -1
  38. package/build/client/assets/dialog-Bl8T588f.js +0 -1
  39. package/build/client/assets/manifest-25954681.js +0 -1
  40. package/build/client/assets/root-DJRlbyb5.css +0 -1
  41. package/build/client/assets/useOpenInteractionType-C_L8nZ_l.js +0 -12
@@ -1428,6 +1428,7 @@ function createTableQueue(schema) {
1428
1428
  warning_queued int NOT NULL default 0,
1429
1429
  active_count int NOT NULL default 0,
1430
1430
  total_count int NOT NULL default 0,
1431
+ heartbeat_seconds int,
1431
1432
  singletons_active text[],
1432
1433
  monitor_on timestamp with time zone,
1433
1434
  maintain_on timestamp with time zone,
@@ -1610,11 +1611,13 @@ function createTableJob(schema) {
1610
1611
  keep_until timestamp with time zone NOT NULL default now() + interval '${QUEUE_DEFAULTS.retention_seconds}',
1611
1612
  output jsonb,
1612
1613
  dead_letter text,
1613
- policy text
1614
+ policy text,
1615
+ heartbeat_on timestamp with time zone,
1616
+ heartbeat_seconds int
1614
1617
  ) PARTITION BY LIST (name)
1615
1618
  `;
1616
1619
  }
1617
- const JOB_COLUMNS_MIN = 'id, name, data, expire_seconds as "expireInSeconds", group_id as "groupId", group_tier as "groupTier"';
1620
+ const JOB_COLUMNS_MIN = 'id, name, data, expire_seconds as "expireInSeconds", heartbeat_seconds as "heartbeatSeconds", group_id as "groupId", group_tier as "groupTier"';
1618
1621
  const JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
1619
1622
  policy,
1620
1623
  state,
@@ -1629,6 +1632,7 @@ const JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
1629
1632
  singleton_key as "singletonKey",
1630
1633
  singleton_on as "singletonOn",
1631
1634
  deletion_seconds as "deleteAfterSeconds",
1635
+ heartbeat_on as "heartbeatOn",
1632
1636
  created_on as "createdOn",
1633
1637
  completed_on as "completedOn",
1634
1638
  keep_until as "keepUntil",
@@ -1682,7 +1686,8 @@ function createQueueFunction(schema) {
1682
1686
  warning_queued,
1683
1687
  dead_letter,
1684
1688
  partition,
1685
- table_name
1689
+ table_name,
1690
+ heartbeat_seconds
1686
1691
  )
1687
1692
  VALUES (
1688
1693
  queue_name,
@@ -1697,7 +1702,8 @@ function createQueueFunction(schema) {
1697
1702
  COALESCE((options->>'warningQueueSize')::int, ${QUEUE_DEFAULTS.warning_queued}),
1698
1703
  options->>'deadLetter',
1699
1704
  COALESCE((options->>'partition')::bool, ${QUEUE_DEFAULTS.partition}),
1700
- tablename
1705
+ tablename,
1706
+ (options->>'heartbeatSeconds')::int
1701
1707
  )
1702
1708
  ON CONFLICT DO NOTHING
1703
1709
  RETURNING created_on
@@ -1854,6 +1860,9 @@ function updateQueue(schema, { deadLetter } = {}) {
1854
1860
  retention_seconds = COALESCE((o.data->>'retentionSeconds')::int, retention_seconds),
1855
1861
  deletion_seconds = COALESCE((o.data->>'deleteAfterSeconds')::int, deletion_seconds),
1856
1862
  warning_queued = COALESCE((o.data->>'warningQueueSize')::int, warning_queued),
1863
+ heartbeat_seconds = CASE WHEN o.data ? 'heartbeatSeconds'
1864
+ THEN (o.data->>'heartbeatSeconds')::int
1865
+ ELSE heartbeat_seconds END,
1857
1866
  ${deadLetter === void 0 ? "" : `dead_letter = CASE WHEN '${deadLetter}' IS DISTINCT FROM dead_letter THEN '${deadLetter}' ELSE dead_letter END,`}
1858
1867
  updated_on = now()
1859
1868
  FROM options o
@@ -1875,6 +1884,7 @@ function getQueues$1(schema, names) {
1875
1884
  q.retention_seconds as "retentionSeconds",
1876
1885
  q.deletion_seconds as "deleteAfterSeconds",
1877
1886
  q.partition,
1887
+ q.heartbeat_seconds as "heartbeatSeconds",
1878
1888
  q.dead_letter as "deadLetter",
1879
1889
  q.deferred_count as "deferredCount",
1880
1890
  q.warning_queued as "warningQueueSize",
@@ -2091,6 +2101,7 @@ function fetchNextJob(options) {
2091
2101
  UPDATE ${schema}.${table} j SET
2092
2102
  state = '${JOB_STATES.active}',
2093
2103
  started_on = now(),
2104
+ heartbeat_on = now(),
2094
2105
  retry_count = CASE WHEN started_on IS NOT NULL THEN retry_count + 1 ELSE retry_count END
2095
2106
  FROM ${finalCte}
2096
2107
  WHERE name = '${name}' AND j.id = ${finalCte}.id
@@ -2172,7 +2183,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
2172
2183
  retry_backoff,
2173
2184
  retry_delay_max,
2174
2185
  policy,
2175
- dead_letter
2186
+ dead_letter,
2187
+ heartbeat_seconds
2176
2188
  )
2177
2189
  SELECT
2178
2190
  COALESCE(id, gen_random_uuid()) as id,
@@ -2195,7 +2207,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
2195
2207
  COALESCE("retryBackoff", q.retry_backoff, false) as retry_backoff,
2196
2208
  COALESCE("retryDelayMax", q.retry_delay_max) as retry_delay_max,
2197
2209
  q.policy,
2198
- COALESCE("deadLetter", q.dead_letter) as dead_letter
2210
+ COALESCE("deadLetter", q.dead_letter) as dead_letter,
2211
+ COALESCE("heartbeatSeconds", q.heartbeat_seconds) as heartbeat_seconds
2199
2212
  FROM (
2200
2213
  SELECT *,
2201
2214
  CASE
@@ -2219,7 +2232,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
2219
2232
  "expireInSeconds" integer,
2220
2233
  "deleteAfterSeconds" integer,
2221
2234
  "retentionSeconds" integer,
2222
- "deadLetter" text
2235
+ "deadLetter" text,
2236
+ "heartbeatSeconds" integer
2223
2237
  )
2224
2238
  ) j
2225
2239
  JOIN ${schema}.queue q ON q.name = '${name}'
@@ -2240,6 +2254,27 @@ function failJobsByTimeout(schema, table, queues) {
2240
2254
  const output = `'{ "value": { "message": "job timed out" } }'::jsonb`;
2241
2255
  return locked(schema, failJobs(schema, table, where, output), table + "failJobsByTimeout");
2242
2256
  }
2257
+ function failJobsByHeartbeat(schema, table, queues) {
2258
+ const where = `state = '${JOB_STATES.active}'
2259
+ AND heartbeat_seconds IS NOT NULL
2260
+ AND (heartbeat_on + heartbeat_seconds * interval '1s') < now()
2261
+ AND name = ANY(${serializeArrayParam(queues)})`;
2262
+ const output = `'{ "value": { "message": "job heartbeat timeout" } }'::jsonb`;
2263
+ return locked(schema, failJobs(schema, table, where, output), table + "failJobsByHeartbeat");
2264
+ }
2265
+ function touchJobs(schema, table) {
2266
+ return `
2267
+ WITH results AS (
2268
+ UPDATE ${schema}.${table}
2269
+ SET heartbeat_on = now()
2270
+ WHERE name = $1
2271
+ AND id IN (SELECT UNNEST($2::uuid[]))
2272
+ AND state = '${JOB_STATES.active}'
2273
+ RETURNING 1
2274
+ )
2275
+ SELECT COUNT(*) FROM results
2276
+ `;
2277
+ }
2243
2278
  function failJobs(schema, table, where, output) {
2244
2279
  return `
2245
2280
  WITH deleted_jobs AS (
@@ -2272,7 +2307,9 @@ function failJobs(schema, table, where, output) {
2272
2307
  keep_until,
2273
2308
  policy,
2274
2309
  output,
2275
- dead_letter
2310
+ dead_letter,
2311
+ heartbeat_on,
2312
+ heartbeat_seconds
2276
2313
  )
2277
2314
  SELECT
2278
2315
  id,
@@ -2310,7 +2347,9 @@ function failJobs(schema, table, where, output) {
2310
2347
  keep_until,
2311
2348
  policy,
2312
2349
  ${output},
2313
- dead_letter
2350
+ dead_letter,
2351
+ NULL as heartbeat_on,
2352
+ heartbeat_seconds
2314
2353
  FROM deleted_jobs
2315
2354
  ON CONFLICT DO NOTHING
2316
2355
  RETURNING *
@@ -2340,7 +2379,9 @@ function failJobs(schema, table, where, output) {
2340
2379
  keep_until,
2341
2380
  policy,
2342
2381
  output,
2343
- dead_letter
2382
+ dead_letter,
2383
+ heartbeat_on,
2384
+ heartbeat_seconds
2344
2385
  )
2345
2386
  SELECT
2346
2387
  id,
@@ -2366,7 +2407,9 @@ function failJobs(schema, table, where, output) {
2366
2407
  keep_until,
2367
2408
  policy,
2368
2409
  ${output},
2369
- dead_letter
2410
+ dead_letter,
2411
+ NULL as heartbeat_on,
2412
+ heartbeat_seconds
2370
2413
  FROM deleted_jobs
2371
2414
  WHERE id NOT IN (SELECT id from retried_jobs)
2372
2415
  RETURNING *
@@ -2579,7 +2622,7 @@ const POLICY = {
2579
2622
  MAX_RETENTION_DAYS: 365
2580
2623
  };
2581
2624
  function assertObjectName(value, name = "Name") {
2582
- assert(/^[\w.-]+$/.test(value), `${name} can only contain alphanumeric characters, underscores, hyphens, or periods`);
2625
+ assert(/^[\w.\-/]+$/.test(value), `${name} can only contain alphanumeric characters, underscores, hyphens, periods, or forward slashes`);
2583
2626
  }
2584
2627
  function validateQueueArgs(config = {}) {
2585
2628
  assert(!("deadLetter" in config) || config.deadLetter === null || typeof config.deadLetter === "string", "deadLetter must be a string");
@@ -2590,6 +2633,7 @@ function validateQueueArgs(config = {}) {
2590
2633
  validateExpirationConfig(config);
2591
2634
  validateRetentionConfig(config);
2592
2635
  validateDeletionConfig(config);
2636
+ validateHeartbeatConfig(config);
2593
2637
  }
2594
2638
  function checkSendArgs(args) {
2595
2639
  let name, data, options;
@@ -2618,6 +2662,7 @@ function checkSendArgs(args) {
2618
2662
  validateRetentionConfig(options);
2619
2663
  validateDeletionConfig(options);
2620
2664
  validateGroupConfig(options);
2665
+ validateHeartbeatConfig(options);
2621
2666
  return { name, data, options };
2622
2667
  }
2623
2668
  function validateGroupConfig(config) {
@@ -2697,6 +2742,7 @@ function checkWorkArgs(name, args) {
2697
2742
  assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
2698
2743
  assert(!("localConcurrency" in options) || Number.isInteger(options.localConcurrency) && options.localConcurrency >= 1, "localConcurrency must be an integer >= 1");
2699
2744
  validateGroupConcurrencyConfig(options);
2745
+ validateHeartbeatRefreshConfig(options);
2700
2746
  return { options, callback };
2701
2747
  }
2702
2748
  function checkFetchArgs(name, options) {
@@ -2783,6 +2829,19 @@ function validateRetryConfig(config) {
2783
2829
  assert(!("retryDelayMax" in config) || config.retryDelayMax === null || config.retryBackoff === true, "retryDelayMax can only be set if retryBackoff is true");
2784
2830
  assert(!("retryDelayMax" in config) || config.retryDelayMax === null || Number.isInteger(config.retryDelayMax) && config.retryDelayMax >= 0, "retryDelayMax must be an integer >= 0");
2785
2831
  }
2832
+ function validateHeartbeatConfig(config) {
2833
+ assert(
2834
+ !("heartbeatSeconds" in config) || config.heartbeatSeconds === null || Number.isInteger(config.heartbeatSeconds) && config.heartbeatSeconds >= 10,
2835
+ "heartbeatSeconds must be an integer >= 10"
2836
+ );
2837
+ }
2838
+ function validateHeartbeatRefreshConfig(config) {
2839
+ if (!("heartbeatRefreshSeconds" in config) || config.heartbeatRefreshSeconds == null) return;
2840
+ assert(
2841
+ typeof config.heartbeatRefreshSeconds === "number" && config.heartbeatRefreshSeconds > 0,
2842
+ "heartbeatRefreshSeconds must be a number > 0"
2843
+ );
2844
+ }
2786
2845
  function applyPollingInterval(config) {
2787
2846
  assert(
2788
2847
  !("pollingIntervalSeconds" in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1e3,
@@ -3478,10 +3537,190 @@ function getAll(schema) {
3478
3537
  `DROP INDEX ${schema}.warning_i1`,
3479
3538
  `DROP TABLE ${schema}.warning`
3480
3539
  ]
3540
+ },
3541
+ {
3542
+ release: "12.12.0",
3543
+ version: 30,
3544
+ previous: 29,
3545
+ install: [
3546
+ `ALTER TABLE ${schema}.job ADD COLUMN heartbeat_on timestamp with time zone`,
3547
+ `ALTER TABLE ${schema}.job ADD COLUMN heartbeat_seconds int`,
3548
+ `ALTER TABLE ${schema}.queue ADD COLUMN heartbeat_seconds int`,
3549
+ `
3550
+ CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
3551
+ RETURNS VOID AS
3552
+ $$
3553
+ DECLARE
3554
+ tablename varchar := CASE WHEN options->>'partition' = 'true'
3555
+ THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
3556
+ ELSE 'job_common'
3557
+ END;
3558
+ queue_created_on timestamptz;
3559
+ BEGIN
3560
+
3561
+ WITH q as (
3562
+ INSERT INTO ${schema}.queue (
3563
+ name,
3564
+ policy,
3565
+ retry_limit,
3566
+ retry_delay,
3567
+ retry_backoff,
3568
+ retry_delay_max,
3569
+ expire_seconds,
3570
+ retention_seconds,
3571
+ deletion_seconds,
3572
+ warning_queued,
3573
+ dead_letter,
3574
+ partition,
3575
+ table_name,
3576
+ heartbeat_seconds
3577
+ )
3578
+ VALUES (
3579
+ queue_name,
3580
+ options->>'policy',
3581
+ COALESCE((options->>'retryLimit')::int, 2),
3582
+ COALESCE((options->>'retryDelay')::int, 0),
3583
+ COALESCE((options->>'retryBackoff')::bool, false),
3584
+ (options->>'retryDelayMax')::int,
3585
+ COALESCE((options->>'expireInSeconds')::int, 900),
3586
+ COALESCE((options->>'retentionSeconds')::int, 1209600),
3587
+ COALESCE((options->>'deleteAfterSeconds')::int, 604800),
3588
+ COALESCE((options->>'warningQueueSize')::int, 0),
3589
+ options->>'deadLetter',
3590
+ COALESCE((options->>'partition')::bool, false),
3591
+ tablename,
3592
+ (options->>'heartbeatSeconds')::int
3593
+ )
3594
+ ON CONFLICT DO NOTHING
3595
+ RETURNING created_on
3596
+ )
3597
+ SELECT created_on into queue_created_on from q;
3598
+
3599
+ IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
3600
+ RETURN;
3601
+ END IF;
3602
+
3603
+ EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
3604
+
3605
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
3606
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
3607
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
3608
+
3609
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
3610
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
3611
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
3612
+
3613
+ IF options->>'policy' = 'short' THEN
3614
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
3615
+ ELSIF options->>'policy' = 'singleton' THEN
3616
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
3617
+ ELSIF options->>'policy' = 'stately' THEN
3618
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
3619
+ ELSIF options->>'policy' = 'exclusive' THEN
3620
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
3621
+ ELSIF options->>'policy' = 'key_strict_fifo' THEN
3622
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
3623
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
3624
+ END IF;
3625
+
3626
+ EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
3627
+ EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
3628
+ END;
3629
+ $$
3630
+ LANGUAGE plpgsql;
3631
+ `
3632
+ ],
3633
+ uninstall: [
3634
+ // Restore previous version of create_queue function (without heartbeat_seconds)
3635
+ `
3636
+ CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
3637
+ RETURNS VOID AS
3638
+ $$
3639
+ DECLARE
3640
+ tablename varchar := CASE WHEN options->>'partition' = 'true'
3641
+ THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
3642
+ ELSE 'job_common'
3643
+ END;
3644
+ queue_created_on timestamptz;
3645
+ BEGIN
3646
+
3647
+ WITH q as (
3648
+ INSERT INTO ${schema}.queue (
3649
+ name,
3650
+ policy,
3651
+ retry_limit,
3652
+ retry_delay,
3653
+ retry_backoff,
3654
+ retry_delay_max,
3655
+ expire_seconds,
3656
+ retention_seconds,
3657
+ deletion_seconds,
3658
+ warning_queued,
3659
+ dead_letter,
3660
+ partition,
3661
+ table_name
3662
+ )
3663
+ VALUES (
3664
+ queue_name,
3665
+ options->>'policy',
3666
+ COALESCE((options->>'retryLimit')::int, 2),
3667
+ COALESCE((options->>'retryDelay')::int, 0),
3668
+ COALESCE((options->>'retryBackoff')::bool, false),
3669
+ (options->>'retryDelayMax')::int,
3670
+ COALESCE((options->>'expireInSeconds')::int, 900),
3671
+ COALESCE((options->>'retentionSeconds')::int, 1209600),
3672
+ COALESCE((options->>'deleteAfterSeconds')::int, 604800),
3673
+ COALESCE((options->>'warningQueueSize')::int, 0),
3674
+ options->>'deadLetter',
3675
+ COALESCE((options->>'partition')::bool, false),
3676
+ tablename
3677
+ )
3678
+ ON CONFLICT DO NOTHING
3679
+ RETURNING created_on
3680
+ )
3681
+ SELECT created_on into queue_created_on from q;
3682
+
3683
+ IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
3684
+ RETURN;
3685
+ END IF;
3686
+
3687
+ EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
3688
+
3689
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
3690
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
3691
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
3692
+
3693
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
3694
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
3695
+ EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
3696
+
3697
+ IF options->>'policy' = 'short' THEN
3698
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
3699
+ ELSIF options->>'policy' = 'singleton' THEN
3700
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
3701
+ ELSIF options->>'policy' = 'stately' THEN
3702
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
3703
+ ELSIF options->>'policy' = 'exclusive' THEN
3704
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
3705
+ ELSIF options->>'policy' = 'key_strict_fifo' THEN
3706
+ EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
3707
+ EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
3708
+ END IF;
3709
+
3710
+ EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
3711
+ EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
3712
+ END;
3713
+ $$
3714
+ LANGUAGE plpgsql;
3715
+ `,
3716
+ `ALTER TABLE ${schema}.queue DROP COLUMN heartbeat_seconds`,
3717
+ `ALTER TABLE ${schema}.job DROP COLUMN heartbeat_seconds`,
3718
+ `ALTER TABLE ${schema}.job DROP COLUMN heartbeat_on`
3719
+ ]
3481
3720
  }
3482
3721
  ];
3483
3722
  }
3484
- const pgboss = { "schema": 29 };
3723
+ const pgboss = { "schema": 30 };
3485
3724
  const packageJson = {
3486
3725
  pgboss
3487
3726
  };
@@ -4098,9 +4337,10 @@ class Manager extends EventEmitter {
4098
4337
  }
4099
4338
  }
4100
4339
  }
4101
- async #processJobs(name, jobs2, callback, worker) {
4340
+ async #processJobs(name, jobs2, callback, worker, heartbeatRefreshSeconds) {
4102
4341
  const jobIds = jobs2.map((job) => job.id);
4103
4342
  const maxExpiration = jobs2.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0);
4343
+ const heartbeatSeconds = jobs2.reduce((acc, j) => Math.max(acc, j.heartbeatSeconds || 0), 0);
4104
4344
  const ac = new AbortController();
4105
4345
  jobs2.forEach((job) => {
4106
4346
  job.signal = ac.signal;
@@ -4108,6 +4348,18 @@ class Manager extends EventEmitter {
4108
4348
  if (worker) {
4109
4349
  worker.abortController = ac;
4110
4350
  }
4351
+ let heartbeatTimer = null;
4352
+ if (heartbeatSeconds > 0) {
4353
+ const refreshSeconds = heartbeatRefreshSeconds ?? heartbeatSeconds / 2;
4354
+ const intervalMs = refreshSeconds * 1e3;
4355
+ heartbeatTimer = setInterval(async () => {
4356
+ try {
4357
+ await this.touch(name, jobIds);
4358
+ } catch (err) {
4359
+ this.emit(events$3.error, err);
4360
+ }
4361
+ }, intervalMs);
4362
+ }
4111
4363
  try {
4112
4364
  const result = await resolveWithinSeconds(callback(jobs2), maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
4113
4365
  await this.complete(name, jobIds, jobIds.length === 1 ? result : void 0);
@@ -4116,6 +4368,7 @@ class Manager extends EventEmitter {
4116
4368
  await this.fail(name, jobIds, err);
4117
4369
  this.#trackJobsFailed(name, jobs2, err);
4118
4370
  } finally {
4371
+ if (heartbeatTimer) clearInterval(heartbeatTimer);
4119
4372
  if (worker) {
4120
4373
  worker.abortController = null;
4121
4374
  }
@@ -4182,7 +4435,8 @@ class Manager extends EventEmitter {
4182
4435
  localConcurrency = 1,
4183
4436
  localGroupConcurrency,
4184
4437
  groupConcurrency,
4185
- orderByCreatedOn = true
4438
+ orderByCreatedOn = true,
4439
+ heartbeatRefreshSeconds
4186
4440
  } = options;
4187
4441
  if (localGroupConcurrency != null) {
4188
4442
  this.#storeLocalGroupConfig(name, localGroupConcurrency);
@@ -4200,7 +4454,7 @@ class Manager extends EventEmitter {
4200
4454
  this.#trackJobsActive(name, jobs2);
4201
4455
  const worker = this.workers.get(workerId);
4202
4456
  if (localGroupConcurrency == null) {
4203
- await this.#processJobs(name, jobs2, callback, worker);
4457
+ await this.#processJobs(name, jobs2, callback, worker, heartbeatRefreshSeconds);
4204
4458
  } else {
4205
4459
  const { allowed, excess, groupedJobs } = this.#trackLocalGroupStart(name, jobs2);
4206
4460
  if (excess.length > 0) {
@@ -4209,7 +4463,7 @@ class Manager extends EventEmitter {
4209
4463
  }
4210
4464
  if (allowed.length > 0) {
4211
4465
  try {
4212
- await this.#processJobs(name, allowed, callback, worker);
4466
+ await this.#processJobs(name, allowed, callback, worker, heartbeatRefreshSeconds);
4213
4467
  } finally {
4214
4468
  this.#trackLocalGroupEnd(name, groupedJobs);
4215
4469
  }
@@ -4346,6 +4600,7 @@ class Manager extends EventEmitter {
4346
4600
  retryDelay,
4347
4601
  retryBackoff,
4348
4602
  retryDelayMax,
4603
+ heartbeatSeconds,
4349
4604
  group,
4350
4605
  deadLetter = null
4351
4606
  } = options;
@@ -4368,6 +4623,7 @@ class Manager extends EventEmitter {
4368
4623
  retryDelay,
4369
4624
  retryBackoff,
4370
4625
  retryDelayMax,
4626
+ heartbeatSeconds,
4371
4627
  deadLetter
4372
4628
  };
4373
4629
  const db = wrapper || this.db;
@@ -4543,6 +4799,15 @@ class Manager extends EventEmitter {
4543
4799
  const result = await db.executeSql(sql, [name, ids]);
4544
4800
  return this.mapCommandResponse(ids, result);
4545
4801
  }
4802
+ async touch(name, id, options = {}) {
4803
+ assertQueueName(name);
4804
+ const db = this.assertDb(options);
4805
+ const ids = this.mapCompletionIdArg(id, "touch");
4806
+ const { table } = await this.getQueueCache(name);
4807
+ const sql = touchJobs(this.config.schema, table);
4808
+ const result = await db.executeSql(sql, [name, ids]);
4809
+ return this.mapCommandResponse(ids, result);
4810
+ }
4546
4811
  async createQueue(name, options = {}) {
4547
4812
  name = name || options.name;
4548
4813
  assertQueueName(name);
@@ -4756,21 +5021,10 @@ class Boss extends EventEmitter {
4756
5021
  errorEvent: events$2.error
4757
5022
  };
4758
5023
  }
4759
- async #executeSql(sql) {
4760
- const started = Date.now();
4761
- const result = unwrapSQLResult(await this.#db.executeSql(sql));
4762
- const elapsed = (Date.now() - started) / 1e3;
4763
- if (elapsed > WARNINGS.SLOW_QUERY.seconds || this.#config.__test__warn_slow_query) {
4764
- await emitAndPersistWarning(
4765
- this.#warningContext,
4766
- WARNING_TYPES.SLOW_QUERY,
4767
- WARNINGS.SLOW_QUERY.message,
4768
- { elapsed, sql }
4769
- );
4770
- }
4771
- return result;
4772
- }
4773
5024
  async #executeQuery(query2) {
5025
+ if (typeof query2 === "string") {
5026
+ query2 = { text: query2, values: [] };
5027
+ }
4774
5028
  const started = Date.now();
4775
5029
  const result = unwrapSQLResult(await this.#db.executeSql(query2.text, query2.values));
4776
5030
  const elapsed = (Date.now() - started) / 1e3;
@@ -4806,7 +5060,7 @@ class Boss extends EventEmitter {
4806
5060
  return;
4807
5061
  }
4808
5062
  const sql = deleteOldWarnings(this.#config.schema, this.#config.warningRetentionDays);
4809
- await this.#executeSql(sql);
5063
+ await this.#executeQuery(sql);
4810
5064
  }
4811
5065
  async supervise(value) {
4812
5066
  let queues;
@@ -4821,6 +5075,9 @@ class Boss extends EventEmitter {
4821
5075
  acc[table].queues.push(q);
4822
5076
  return acc;
4823
5077
  }, {});
5078
+ const heartbeatQueueNames = new Set(
5079
+ queues.filter((q) => q.heartbeatSeconds != null).map((q) => q.name)
5080
+ );
4824
5081
  for (const queueGroup of Object.values(queueGroups)) {
4825
5082
  if (this.#stopping) return;
4826
5083
  const { table, queues: queues2 } = queueGroup;
@@ -4828,12 +5085,12 @@ class Boss extends EventEmitter {
4828
5085
  while (names.length) {
4829
5086
  if (this.#stopping) return;
4830
5087
  const chunk = names.splice(0, 100);
4831
- await this.#monitor(table, chunk);
5088
+ await this.#monitor(table, chunk, heartbeatQueueNames);
4832
5089
  await this.#maintain(table, chunk);
4833
5090
  }
4834
5091
  }
4835
5092
  }
4836
- async #monitor(table, names) {
5093
+ async #monitor(table, names, heartbeatQueueNames) {
4837
5094
  if (this.#stopping) return;
4838
5095
  const command = trySetQueueMonitorTime(
4839
5096
  this.#config.schema,
@@ -4845,7 +5102,7 @@ class Boss extends EventEmitter {
4845
5102
  if (rows.length) {
4846
5103
  const queues = rows.map((q) => q.name);
4847
5104
  const cacheStatsSql = cacheQueueStats(this.#config.schema, table, queues);
4848
- const { rows: rowsCacheStats } = await this.#executeSql(cacheStatsSql);
5105
+ const { rows: rowsCacheStats } = await this.#executeQuery(cacheStatsSql);
4849
5106
  if (this.#stopping) return;
4850
5107
  const warnings2 = rowsCacheStats.filter((i) => i.queuedCount > (i.warningQueueSize || WARNINGS.LARGE_QUEUE.size));
4851
5108
  for (const warning of warnings2) {
@@ -4857,7 +5114,13 @@ class Boss extends EventEmitter {
4857
5114
  );
4858
5115
  }
4859
5116
  const sql = failJobsByTimeout(this.#config.schema, table, queues);
4860
- await this.#executeSql(sql);
5117
+ await this.#executeQuery(sql);
5118
+ if (this.#stopping) return;
5119
+ const heartbeatQueues = queues.filter((q) => heartbeatQueueNames.has(q));
5120
+ if (heartbeatQueues.length) {
5121
+ const heartbeatSql = failJobsByHeartbeat(this.#config.schema, table, heartbeatQueues);
5122
+ await this.#executeQuery(heartbeatSql);
5123
+ }
4861
5124
  }
4862
5125
  }
4863
5126
  async #maintain(table, names) {
@@ -4872,7 +5135,7 @@ class Boss extends EventEmitter {
4872
5135
  if (rows.length) {
4873
5136
  const queues = rows.map((q) => q.name);
4874
5137
  const sql = deletion(this.#config.schema, table, queues);
4875
- await this.#executeSql(sql);
5138
+ await this.#executeQuery(sql);
4876
5139
  }
4877
5140
  }
4878
5141
  }
@@ -5187,6 +5450,9 @@ class PgBoss extends EventEmitter {
5187
5450
  fail(name, id, data, options) {
5188
5451
  return this.#manager.fail(name, id, data, options);
5189
5452
  }
5453
+ touch(name, id, options) {
5454
+ return this.#manager.touch(name, id, options);
5455
+ }
5190
5456
  /**
5191
5457
  * @deprecated Use findJobs() instead
5192
5458
  */
@@ -9559,10 +9825,10 @@ const route11 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
9559
9825
  default: warnings,
9560
9826
  loader
9561
9827
  }, Symbol.toStringTag, { value: "Module" }));
9562
- const serverManifest = { "entry": { "module": "/assets/entry.client-COnaNoy-.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/index-DhMkYPMa.js"], "css": [] }, "routes": { "root": { "id": "root", "parentId": void 0, "path": "", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/root-NWrBrGvr.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/index-DhMkYPMa.js", "/assets/db-link-CtPnIrIr.js", "/assets/createLucideIcon-BXGwbdrh.js", "/assets/MenuTrigger-SThQHnlb.js", "/assets/useOpenInteractionType-C_L8nZ_l.js"], "css": ["/assets/root-DJRlbyb5.css"], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/_index": { "id": "routes/_index", "parentId": "root", "path": void 0, "index": true, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/_index-Bcg_-XSd.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/table-CTo0I5HG.js", "/assets/error-card-DmoxS3Ao.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/jobs": { "id": "routes/jobs", "parentId": "root", "path": "jobs", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/jobs-DtmTCs8I.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/table-CTo0I5HG.js", "/assets/pagination-NfhvsUbp.js", "/assets/filter-select-mMC79WOR.js", "/assets/error-card-DmoxS3Ao.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues._index": { "id": "routes/queues._index", "parentId": "root", "path": "queues", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/queues._index-Cw1B49mg.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/filter-select-mMC79WOR.js", "/assets/table-CTo0I5HG.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.create": { "id": "routes/queues.create", "parentId": "root", "path": "queues/create", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/queues.create-BGXDhJ3m.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/chevron-down-xu6Uceu-.js", "/assets/error-card-DmoxS3Ao.js", "/assets/createLucideIcon-BXGwbdrh.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name": { "id": "routes/queues.$name", "parentId": "root", "path": "queues/:name", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/queues._name-D0cG_qDX.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/table-CTo0I5HG.js", "/assets/pagination-NfhvsUbp.js", "/assets/filter-select-mMC79WOR.js", "/assets/dialog-Bl8T588f.js", "/assets/error-card-DmoxS3Ao.js", "/assets/chevron-down-xu6Uceu-.js", "/assets/createLucideIcon-BXGwbdrh.js", "/assets/MenuTrigger-SThQHnlb.js", "/assets/useOpenInteractionType-C_L8nZ_l.js", "/assets/index-DhMkYPMa.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name.jobs.$jobId": { "id": "routes/queues.$name.jobs.$jobId", "parentId": "root", "path": "queues/:name/jobs/:jobId", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/queues._name.jobs._jobId-uJ3dfM3J.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/dialog-Bl8T588f.js", "/assets/error-card-DmoxS3Ao.js", "/assets/createLucideIcon-BXGwbdrh.js", "/assets/useOpenInteractionType-C_L8nZ_l.js", "/assets/index-DhMkYPMa.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules": { "id": "routes/schedules", "parentId": "root", "path": "schedules", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/schedules-DzgBEayh.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/table-CTo0I5HG.js", "/assets/pagination-NfhvsUbp.js", "/assets/error-card-DmoxS3Ao.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.$name.$key": { "id": "routes/schedules.$name.$key", "parentId": "root", "path": "schedules/:name/:key", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/schedules._name._key-i42S9kw2.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/dialog-Bl8T588f.js", "/assets/error-card-DmoxS3Ao.js", "/assets/createLucideIcon-BXGwbdrh.js", "/assets/useOpenInteractionType-C_L8nZ_l.js", "/assets/index-DhMkYPMa.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.new": { "id": "routes/schedules.new", "parentId": "root", "path": "schedules/new", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/schedules.new-Dt78KptL.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/error-card-DmoxS3Ao.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/send": { "id": "routes/send", "parentId": "root", "path": "send", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/send-0eWgiWNl.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/db-link-CtPnIrIr.js", "/assets/button-BaXUPm8v.js", "/assets/error-card-DmoxS3Ao.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/warnings": { "id": "routes/warnings", "parentId": "root", "path": "warnings", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasErrorBoundary": true, "module": "/assets/warnings-BhQM6lFV.js", "imports": ["/assets/chunk-JZWAC4HX-DC8i-F7r.js", "/assets/button-BaXUPm8v.js", "/assets/badge-Cd8v3tl3.js", "/assets/table-CTo0I5HG.js", "/assets/pagination-NfhvsUbp.js", "/assets/filter-select-mMC79WOR.js", "/assets/error-card-DmoxS3Ao.js", "/assets/db-link-CtPnIrIr.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 } }, "url": "/assets/manifest-25954681.js", "version": "25954681", "sri": void 0 };
9828
+ const serverManifest = { "entry": { "module": "/assets/entry.client-Szv-xmaE.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/index-x2yWco1W.js"], "css": [] }, "routes": { "root": { "id": "root", "parentId": void 0, "path": "", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/root-D0qqtdF7.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/index-x2yWco1W.js", "/assets/db-link-DmvfwdX4.js", "/assets/createLucideIcon-B0YqJFaz.js", "/assets/MenuTrigger-CEHCnGow.js", "/assets/useOpenInteractionType-Ss_6xZdw.js"], "css": ["/assets/root-Bpb4WtY4.css"], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/_index": { "id": "routes/_index", "parentId": "root", "path": void 0, "index": true, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/_index-9fLquIe1.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/table-CtSLyG7m.js", "/assets/error-card-CXoOCvsg.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/jobs": { "id": "routes/jobs", "parentId": "root", "path": "jobs", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/jobs-CM6xcK-O.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/table-CtSLyG7m.js", "/assets/pagination-C4yyCmBA.js", "/assets/filter-select-DXyBBVm8.js", "/assets/error-card-CXoOCvsg.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues._index": { "id": "routes/queues._index", "parentId": "root", "path": "queues", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._index-Dn3ieC5d.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/filter-select-DXyBBVm8.js", "/assets/table-CtSLyG7m.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.create": { "id": "routes/queues.create", "parentId": "root", "path": "queues/create", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues.create-Ch3Mqw52.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/chevron-down-B4tDL9Ah.js", "/assets/error-card-CXoOCvsg.js", "/assets/createLucideIcon-B0YqJFaz.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name": { "id": "routes/queues.$name", "parentId": "root", "path": "queues/:name", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._name-GrviLLx2.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/table-CtSLyG7m.js", "/assets/pagination-C4yyCmBA.js", "/assets/filter-select-DXyBBVm8.js", "/assets/dialog-CQzw3QVH.js", "/assets/error-card-CXoOCvsg.js", "/assets/chevron-down-B4tDL9Ah.js", "/assets/createLucideIcon-B0YqJFaz.js", "/assets/MenuTrigger-CEHCnGow.js", "/assets/useOpenInteractionType-Ss_6xZdw.js", "/assets/index-x2yWco1W.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name.jobs.$jobId": { "id": "routes/queues.$name.jobs.$jobId", "parentId": "root", "path": "queues/:name/jobs/:jobId", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._name.jobs._jobId-s_wYs79w.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/dialog-CQzw3QVH.js", "/assets/error-card-CXoOCvsg.js", "/assets/createLucideIcon-B0YqJFaz.js", "/assets/useOpenInteractionType-Ss_6xZdw.js", "/assets/index-x2yWco1W.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules": { "id": "routes/schedules", "parentId": "root", "path": "schedules", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules-DwnuuhxF.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/table-CtSLyG7m.js", "/assets/pagination-C4yyCmBA.js", "/assets/error-card-CXoOCvsg.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.$name.$key": { "id": "routes/schedules.$name.$key", "parentId": "root", "path": "schedules/:name/:key", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules._name._key-DJn-u3Cm.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/dialog-CQzw3QVH.js", "/assets/error-card-CXoOCvsg.js", "/assets/createLucideIcon-B0YqJFaz.js", "/assets/useOpenInteractionType-Ss_6xZdw.js", "/assets/index-x2yWco1W.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.new": { "id": "routes/schedules.new", "parentId": "root", "path": "schedules/new", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules.new-CQuE2Uhz.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/error-card-CXoOCvsg.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/send": { "id": "routes/send", "parentId": "root", "path": "send", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/send-DVfuC6NR.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/db-link-DmvfwdX4.js", "/assets/button-Djse56Dx.js", "/assets/error-card-CXoOCvsg.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/warnings": { "id": "routes/warnings", "parentId": "root", "path": "warnings", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/warnings-DqRQYomb.js", "imports": ["/assets/chunk-LFPYN7LY-Cj1DJmJR.js", "/assets/button-Djse56Dx.js", "/assets/badge-B5ZugmiV.js", "/assets/table-CtSLyG7m.js", "/assets/pagination-C4yyCmBA.js", "/assets/filter-select-DXyBBVm8.js", "/assets/error-card-CXoOCvsg.js", "/assets/db-link-DmvfwdX4.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 } }, "url": "/assets/manifest-acaa4b8e.js", "version": "acaa4b8e", "sri": void 0 };
9563
9829
  const assetsBuildDirectory = "build/client";
9564
9830
  const basename = "/";
9565
- const future = { "unstable_optimizeDeps": false, "unstable_subResourceIntegrity": false, "unstable_trailingSlashAwareDataRequests": false, "v8_middleware": false, "v8_splitRouteModules": false, "v8_viteEnvironmentApi": false };
9831
+ const future = { "unstable_optimizeDeps": false, "unstable_subResourceIntegrity": false, "unstable_trailingSlashAwareDataRequests": false, "unstable_previewServerPrerendering": false, "v8_middleware": false, "v8_splitRouteModules": false, "v8_viteEnvironmentApi": false };
9566
9832
  const ssr = true;
9567
9833
  const isSpaMode = false;
9568
9834
  const prerender = [];