velocious 1.0.574 → 1.0.576

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 (82) hide show
  1. package/README.md +17 -3
  2. package/build/background-jobs/client.js +71 -3
  3. package/build/background-jobs/job.js +30 -0
  4. package/build/background-jobs/main.js +100 -14
  5. package/build/background-jobs/store.js +344 -41
  6. package/build/background-jobs/types.js +25 -1
  7. package/build/background-jobs/web/controller.js +1 -0
  8. package/build/database/advisory-lock-runner.js +27 -17
  9. package/build/database/drivers/mssql/index.js +98 -3
  10. package/build/database/record/index.js +10 -8
  11. package/build/database/table-data/table-column.js +2 -0
  12. package/build/frontend-models/resource-definition.js +1 -138
  13. package/build/src/background-jobs/client.d.ts +30 -0
  14. package/build/src/background-jobs/client.d.ts.map +1 -1
  15. package/build/src/background-jobs/client.js +64 -4
  16. package/build/src/background-jobs/job.d.ts +19 -0
  17. package/build/src/background-jobs/job.d.ts.map +1 -1
  18. package/build/src/background-jobs/job.js +27 -1
  19. package/build/src/background-jobs/main.d.ts +41 -0
  20. package/build/src/background-jobs/main.d.ts.map +1 -1
  21. package/build/src/background-jobs/main.js +95 -14
  22. package/build/src/background-jobs/store.d.ts +136 -0
  23. package/build/src/background-jobs/store.d.ts.map +1 -1
  24. package/build/src/background-jobs/store.js +314 -42
  25. package/build/src/background-jobs/types.d.ts +86 -2
  26. package/build/src/background-jobs/types.d.ts.map +1 -1
  27. package/build/src/background-jobs/types.js +26 -2
  28. package/build/src/background-jobs/web/controller.d.ts.map +1 -1
  29. package/build/src/background-jobs/web/controller.js +2 -1
  30. package/build/src/database/advisory-lock-runner.d.ts +27 -14
  31. package/build/src/database/advisory-lock-runner.d.ts.map +1 -1
  32. package/build/src/database/advisory-lock-runner.js +27 -18
  33. package/build/src/database/drivers/mssql/index.d.ts +32 -0
  34. package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
  35. package/build/src/database/drivers/mssql/index.js +86 -4
  36. package/build/src/database/record/index.d.ts +12 -8
  37. package/build/src/database/record/index.d.ts.map +1 -1
  38. package/build/src/database/record/index.js +11 -9
  39. package/build/src/database/table-data/table-column.d.ts.map +1 -1
  40. package/build/src/database/table-data/table-column.js +4 -1
  41. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  42. package/build/src/frontend-models/resource-definition.js +2 -124
  43. package/build/src/sync/local-mutation-log.d.ts +7 -1
  44. package/build/src/sync/local-mutation-log.d.ts.map +1 -1
  45. package/build/src/sync/local-mutation-log.js +18 -7
  46. package/build/src/sync/peer-mutation-bundle.d.ts.map +1 -1
  47. package/build/src/sync/peer-mutation-bundle.js +9 -7
  48. package/build/src/sync/signed-sync-envelope-replay-service.d.ts.map +1 -1
  49. package/build/src/sync/signed-sync-envelope-replay-service.js +3 -1
  50. package/build/src/sync/sync-envelope-replay-service.d.ts +69 -0
  51. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  52. package/build/src/sync/sync-envelope-replay-service.js +186 -18
  53. package/build/src/testing/test-runner.d.ts.map +1 -1
  54. package/build/src/testing/test-runner.js +17 -22
  55. package/build/src/utils/sha256-hex.d.ts +10 -0
  56. package/build/src/utils/sha256-hex.d.ts.map +1 -0
  57. package/build/src/utils/sha256-hex.js +126 -0
  58. package/build/sync/local-mutation-log.js +19 -5
  59. package/build/sync/peer-mutation-bundle.js +8 -6
  60. package/build/sync/signed-sync-envelope-replay-service.js +2 -0
  61. package/build/sync/sync-envelope-replay-service.js +205 -17
  62. package/build/testing/test-runner.js +17 -22
  63. package/build/tsconfig.tsbuildinfo +1 -1
  64. package/build/utils/sha256-hex.js +141 -0
  65. package/package.json +1 -1
  66. package/src/background-jobs/client.js +71 -3
  67. package/src/background-jobs/job.js +30 -0
  68. package/src/background-jobs/main.js +100 -14
  69. package/src/background-jobs/store.js +344 -41
  70. package/src/background-jobs/types.js +25 -1
  71. package/src/background-jobs/web/controller.js +1 -0
  72. package/src/database/advisory-lock-runner.js +27 -17
  73. package/src/database/drivers/mssql/index.js +98 -3
  74. package/src/database/record/index.js +10 -8
  75. package/src/database/table-data/table-column.js +2 -0
  76. package/src/frontend-models/resource-definition.js +1 -138
  77. package/src/sync/local-mutation-log.js +19 -5
  78. package/src/sync/peer-mutation-bundle.js +8 -6
  79. package/src/sync/signed-sync-envelope-replay-service.js +2 -0
  80. package/src/sync/sync-envelope-replay-service.js +205 -17
  81. package/src/testing/test-runner.js +17 -22
  82. package/src/utils/sha256-hex.js +141 -0
@@ -52,7 +52,8 @@ class AdvisoryLockHoldTimeoutError extends Error {
52
52
 
53
53
  /**
54
54
  * Runs advisory locks on the caller connection by default, using a dedicated
55
- * lock connection only when a positive hold timeout needs separate ownership.
55
+ * lock connection when `dedicatedConnection` is requested or when a positive
56
+ * hold timeout needs separate ownership.
56
57
  */
57
58
  export default class AdvisoryLockRunner {
58
59
  /**
@@ -67,17 +68,21 @@ export default class AdvisoryLockRunner {
67
68
 
68
69
  /**
69
70
  * Runs a callback after acquiring the advisory lock, waiting up to `timeoutMs`.
70
- * When a `holdTimeoutMs` is set the callback receives a `TimeoutControl` from
71
- * awaitery for cooperative cancellation (`control.check()`, `control.signal`,
72
- * `control.timedOut`, `control.remaining()`).
71
+ * When `dedicatedConnection` is true the lock is acquired on a spawned
72
+ * connection that is released after the callback finishes, while the callback
73
+ * itself still runs against the caller/model connection. When a `holdTimeoutMs`
74
+ * is set the callback receives a `TimeoutControl` from awaitery for cooperative
75
+ * cancellation (`control.check()`, `control.signal`, `control.timedOut`,
76
+ * `control.remaining()`); a dedicated connection is also used so timeout
77
+ * cleanup can release the lock even if callback database work is stuck.
73
78
  * @template T
74
79
  * @param {string} name - Lock name.
75
80
  * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback to invoke while the lock is held.
76
- * @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null}} [args] - Lock and hold timeout options.
81
+ * @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Lock and hold timeout options.
77
82
  * @returns {Promise<T>} - Resolves with the callback result.
78
83
  */
79
84
  async withAdvisoryLock(name, callback, args = {}) {
80
- return await this.withLockConnection(args.holdTimeoutMs, async (connection) => {
85
+ return await this.withLockConnection(args, async (connection) => {
81
86
  const acquired = await connection.acquireAdvisoryLock(name, args)
82
87
 
83
88
  if (!acquired) {
@@ -90,16 +95,19 @@ export default class AdvisoryLockRunner {
90
95
 
91
96
  /**
92
97
  * Runs a callback only if the advisory lock can be acquired immediately.
93
- * When a `holdTimeoutMs` is set the callback receives a `TimeoutControl` from
94
- * awaitery for cooperative cancellation.
98
+ * When `dedicatedConnection` is true the lock is acquired on a spawned
99
+ * connection that is released after the callback finishes, while the callback
100
+ * itself still runs against the caller/model connection. When a `holdTimeoutMs`
101
+ * is set the callback receives a `TimeoutControl` from awaitery for cooperative
102
+ * cancellation.
95
103
  * @template T
96
104
  * @param {string} name - Lock name.
97
105
  * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback to invoke while the lock is held.
98
- * @param {{holdTimeoutMs?: number | null}} [args] - Hold timeout options.
106
+ * @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Hold timeout options.
99
107
  * @returns {Promise<T>} - Resolves with the callback result.
100
108
  */
101
109
  async withAdvisoryLockOrFail(name, callback, args = {}) {
102
- return await this.withLockConnection(args.holdTimeoutMs, async (connection) => {
110
+ return await this.withLockConnection(args, async (connection) => {
103
111
  const acquired = await connection.tryAcquireAdvisoryLock(name)
104
112
 
105
113
  if (!acquired) {
@@ -125,15 +133,17 @@ export default class AdvisoryLockRunner {
125
133
  }
126
134
 
127
135
  /**
128
- * Runs lock work on the caller connection unless a positive hold timeout needs
129
- * its own lock connection.
136
+ * Runs lock work on the caller connection unless `dedicatedConnection` is
137
+ * requested or a positive hold timeout needs its own lock connection.
130
138
  * @template T
131
- * @param {number | null | undefined} holdTimeoutMs - Max hold time; positive values use a dedicated lock connection.
139
+ * @param {{dedicatedConnection?: boolean, holdTimeoutMs?: number | null}} args - Lock connection options.
132
140
  * @param {(connection: import("./drivers/base.js").default) => Promise<T>} callback - Callback receiving the connection that owns the advisory lock.
133
141
  * @returns {Promise<T>} - Resolves with the callback result.
134
142
  */
135
- async withLockConnection(holdTimeoutMs, callback) {
136
- if (holdTimeoutMs && holdTimeoutMs > 0) {
143
+ async withLockConnection(args, callback) {
144
+ const holdTimeoutMs = args.holdTimeoutMs
145
+
146
+ if (args.dedicatedConnection || (holdTimeoutMs && holdTimeoutMs > 0)) {
137
147
  return await this.withDedicatedConnection(callback)
138
148
  }
139
149
 
@@ -141,8 +151,8 @@ export default class AdvisoryLockRunner {
141
151
  }
142
152
 
143
153
  /**
144
- * Spawns a hold-timeout lock connection and closes it after lock work completes when
145
- * the spawned driver owns the underlying physical connection.
154
+ * Spawns a dedicated lock connection and closes it after lock work completes
155
+ * when the spawned driver owns the underlying physical connection.
146
156
  * @template T
147
157
  * @param {(connection: import("./drivers/base.js").default) => Promise<T>} callback - Callback that receives the dedicated lock connection.
148
158
  * @returns {Promise<T>} - Resolves with the callback result.
@@ -35,6 +35,9 @@ import UUID from "pure-uuid"
35
35
  const APPLOCK_NOT_HELD_ERROR_NUMBER = 1223
36
36
 
37
37
  export default class VelociousDatabaseDriversMssql extends Base{
38
+ /** @type {import("mssql").Transaction | null} */
39
+ _advisoryLockTransaction = null
40
+
38
41
  async connect() {
39
42
  const args = this.getArgs()
40
43
  const sqlConfig = digg(args, "sqlConfig")
@@ -65,12 +68,22 @@ export default class VelociousDatabaseDriversMssql extends Base{
65
68
  this.connection = undefined
66
69
  this._currentTransaction = null
67
70
  this._transactionsCount = 0
71
+ /** @type {Error | undefined} */
72
+ let sessionError
73
+
74
+ try {
75
+ await this._closeAdvisoryLockTransaction()
76
+ } catch (error) {
77
+ sessionError = error instanceof Error ? error : new Error("Failed to close MSSQL advisory-lock session", {cause: error})
78
+ }
68
79
 
69
80
  try {
70
81
  await timeout({timeout: 2000}, () => connection.close())
71
82
  } catch (error) {
72
83
  this.logger.warn("Failed to close MSSQL connection cleanly", {error})
73
84
  }
85
+
86
+ if (sessionError) throw sessionError
74
87
  }
75
88
 
76
89
  /**
@@ -662,12 +675,15 @@ export default class VelociousDatabaseDriversMssql extends Base{
662
675
  */
663
676
  async _acquireAdvisoryLock(name, {timeoutMs} = {}) {
664
677
  const timeoutValue = typeof timeoutMs === "number" && timeoutMs >= 0 ? Math.ceil(timeoutMs) : -1
665
- const rows = await this.query(
678
+ const rows = await this._advisoryLockQuery(
666
679
  `DECLARE @velocious_advisory_lock_result INT; EXEC @velocious_advisory_lock_result = sp_getapplock @Resource = ${this.quote(name)}, @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = ${timeoutValue}; SELECT @velocious_advisory_lock_result AS velocious_advisory_lock_result`
667
680
  )
668
681
  const result = Number(rows?.[0]?.velocious_advisory_lock_result)
669
682
 
670
683
  if (result === 0 || result === 1) return true
684
+
685
+ await this._closeAdvisoryLockTransaction()
686
+
671
687
  if (result === -1) return false
672
688
 
673
689
  throw new Error(`sp_getapplock returned ${result} for advisory lock ${JSON.stringify(name)} (see SQL Server documentation for sp_getapplock return codes)`)
@@ -698,20 +714,99 @@ export default class VelociousDatabaseDriversMssql extends Base{
698
714
  let rows
699
715
 
700
716
  try {
701
- rows = await this.query(
717
+ rows = await this._advisoryLockQuery(
702
718
  `DECLARE @velocious_advisory_lock_result INT; EXEC @velocious_advisory_lock_result = sp_releaseapplock @Resource = ${this.quote(name)}, @LockOwner = 'Session'; SELECT @velocious_advisory_lock_result AS velocious_advisory_lock_result`
703
719
  )
704
720
  } catch (error) {
705
- if (this._isApplockNotHeldError(error)) return false
721
+ if (this._isApplockNotHeldError(error)) {
722
+ await this._closeAdvisoryLockTransactionIfFinalRelease()
723
+
724
+ return false
725
+ }
706
726
 
707
727
  throw error
708
728
  }
709
729
 
710
730
  const result = Number(rows?.[0]?.velocious_advisory_lock_result)
711
731
 
732
+ await this._closeAdvisoryLockTransactionIfFinalRelease()
733
+
712
734
  return result === 0
713
735
  }
714
736
 
737
+ /**
738
+ * Runs an advisory-lock statement through one transaction request parent.
739
+ * node-mssql reserves one physical session for a Transaction, whereas
740
+ * separate ConnectionPool requests may check out different sessions. The
741
+ * transaction contains only application-lock statements; caller/model work
742
+ * continues through its original connection.
743
+ * @param {string} sql - Advisory-lock SQL.
744
+ * @returns {Promise<import("../base.js").QueryResultType>} - Result rows.
745
+ */
746
+ async _advisoryLockQuery(sql) {
747
+ const transaction = await this._ensureAdvisoryLockTransaction()
748
+
749
+ try {
750
+ const request = new mssql.Request(transaction)
751
+ const result = await request.query(sql)
752
+
753
+ return Array.isArray(result.recordsets) ? result.recordsets[0] || [] : []
754
+ } catch (error) {
755
+ if (error instanceof Error) {
756
+ throw new Error(`Query failed '${error.message}': ${sql}`, {cause: error})
757
+ }
758
+
759
+ throw new Error(`Query failed '${error}': ${sql}`, {cause: error})
760
+ }
761
+ }
762
+
763
+ /**
764
+ * Starts the transaction request parent that reserves the advisory-lock
765
+ * session until the final release or driver close.
766
+ * @returns {Promise<import("mssql").Transaction>} - Session-affine parent.
767
+ */
768
+ async _ensureAdvisoryLockTransaction() {
769
+ if (this._advisoryLockTransaction) return this._advisoryLockTransaction
770
+ if (!this.connection) await this.connect()
771
+ if (!this.connection) throw new Error("MSSQL connection unavailable for advisory lock")
772
+
773
+ const transaction = new mssql.Transaction(this.connection)
774
+
775
+ await transaction.begin()
776
+ this._advisoryLockTransaction = transaction
777
+
778
+ return transaction
779
+ }
780
+
781
+ /**
782
+ * Releases the reserved session after the last tracked lock release.
783
+ * Base untracks the current release after the driver hook returns, so a
784
+ * current total of one means this is the final release.
785
+ * @returns {Promise<void>} - Resolves after cleanup when this is final.
786
+ */
787
+ async _closeAdvisoryLockTransactionIfFinalRelease() {
788
+ let heldCount = 0
789
+
790
+ for (const count of this._heldAdvisoryLocks.values()) heldCount += count
791
+
792
+ if (heldCount <= 1) await this._closeAdvisoryLockTransaction()
793
+ }
794
+
795
+ /**
796
+ * Rolls back the otherwise-empty transaction and returns its physical
797
+ * session to node-mssql. Rollback is cleanup only; advisory locks are
798
+ * explicitly released first whenever their release statement succeeds.
799
+ * @returns {Promise<void>} - Resolves after session cleanup.
800
+ */
801
+ async _closeAdvisoryLockTransaction() {
802
+ const transaction = this._advisoryLockTransaction
803
+
804
+ if (!transaction) return
805
+
806
+ this._advisoryLockTransaction = null
807
+ await transaction.rollback()
808
+ }
809
+
715
810
  /**
716
811
  * Detects the SQL Server "application lock is not currently held" error
717
812
  * raised by `sp_releaseapplock`. It walks the wrapped-error cause chain
@@ -2677,12 +2677,14 @@ class VelociousDatabaseRecord {
2677
2677
 
2678
2678
  /**
2679
2679
  * Runs the callback while holding a named advisory lock. Calls without
2680
- * a positive `holdTimeoutMs` use the caller connection; calls with a positive
2681
- * `holdTimeoutMs` use a dedicated lock connection so timeout cleanup can
2682
- * release the lock even when callback database work is stuck. Advisory locks
2683
- * are cooperative and session-scoped: they serialize callers that opt into
2684
- * the same `name`, without touching row or table locks, so unrelated traffic
2685
- * is free to proceed.
2680
+ * By default calls use the caller connection. Calls with `dedicatedConnection`
2681
+ * use a spawned lock connection that is released after the callback finishes,
2682
+ * while the callback itself still runs against the caller/model connection.
2683
+ * Calls with a positive `holdTimeoutMs` use a dedicated lock connection so
2684
+ * timeout cleanup can release the lock even when callback database work is
2685
+ * stuck. Advisory locks are cooperative and session-scoped: they serialize
2686
+ * callers that opt into the same `name`, without touching row or table locks,
2687
+ * so unrelated traffic is free to proceed.
2686
2688
  *
2687
2689
  * The lock is acquired before the callback runs and released in a
2688
2690
  * `finally` block afterwards, so the callback's return value is
@@ -2690,7 +2692,7 @@ class VelociousDatabaseRecord {
2690
2692
  * @template T
2691
2693
  * @param {string} name - Lock name.
2692
2694
  * @param {() => Promise<T>} callback - Callback to invoke while the lock is held.
2693
- * @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null}} [args] - `timeoutMs` caps how long we wait to acquire the lock; `holdTimeoutMs` caps how long the callback may hold it before the lock is released and `AdvisoryLockHoldTimeoutError` is thrown.
2695
+ * @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - `timeoutMs` caps how long we wait to acquire the lock; `holdTimeoutMs` caps how long the callback may hold it before the lock is released and `AdvisoryLockHoldTimeoutError` is thrown; `dedicatedConnection` spawns a separate lock session without enabling a hold timeout.
2694
2696
  * @returns {Promise<T>} - Resolves with the callback's return value.
2695
2697
  * @throws {AdvisoryLockTimeoutError} - If `timeoutMs` elapses before the lock is granted.
2696
2698
  * @throws {AdvisoryLockHoldTimeoutError} - If `holdTimeoutMs` elapses while the callback holds the lock.
@@ -2716,7 +2718,7 @@ class VelociousDatabaseRecord {
2716
2718
  * @template T
2717
2719
  * @param {string} name - Lock name.
2718
2720
  * @param {() => Promise<T>} callback - Callback to invoke while the lock is held.
2719
- * @param {{holdTimeoutMs?: number | null}} [args] - `holdTimeoutMs` caps how long the callback may hold the lock before it is released and `AdvisoryLockHoldTimeoutError` is thrown.
2721
+ * @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - `holdTimeoutMs` caps how long the callback may hold the lock before it is released and `AdvisoryLockHoldTimeoutError` is thrown; `dedicatedConnection` spawns a separate lock session without enabling a hold timeout.
2720
2722
  * @returns {Promise<T>} - Resolves with the callback's return value.
2721
2723
  * @throws {AdvisoryLockBusyError} - If the lock is already held.
2722
2724
  * @throws {AdvisoryLockHoldTimeoutError} - If `holdTimeoutMs` elapses while the callback holds the lock.
@@ -349,6 +349,8 @@ export default class TableColumn {
349
349
 
350
350
  if (precision !== undefined && precision !== null) {
351
351
  sql += scale !== undefined && scale !== null ? `(${precision}, ${scale})` : `(${precision})`
352
+ } else if (databaseType == "mysql" && type == "DATETIME") {
353
+ sql += "(3)"
352
354
  } else if (type && maxlength !== undefined && maxlength !== null) {
353
355
  sql += `(${maxlength})`
354
356
  }
@@ -3,6 +3,7 @@
3
3
  import * as inflection from "inflection"
4
4
  import FrontendModelBaseResource from "../frontend-model-resource/base-resource.js"
5
5
  import restArgsError from "../utils/rest-args-error.js"
6
+ import sha256Hex from "../utils/sha256-hex.js"
6
7
  import {validateFrontendModelResourceCommandName} from "./resource-config-validation.js"
7
8
 
8
9
  /**
@@ -13,28 +14,6 @@ import {validateFrontendModelResourceCommandName} from "./resource-config-valida
13
14
  * @property {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration} resourceConfiguration - Normalized resource configuration.
14
15
  */
15
16
  const BASE_FRONTEND_MODEL_ABILITY_ACTIONS = ["create", "destroy", "read", "update"]
16
- const SHA256_INITIAL_HASH = [
17
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
18
- 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
19
- ]
20
- const SHA256_K = [
21
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
22
- 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
23
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
24
- 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
25
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
26
- 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
27
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
28
- 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
29
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
30
- 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
31
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
32
- 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
33
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
34
- 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
35
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
36
- 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
37
- ]
38
17
  const RESOURCE_STATIC_CONFIG_KEYS = new Set([
39
18
  "abilities",
40
19
  "attachments",
@@ -529,122 +508,6 @@ function syncPolicyHash(value) {
529
508
  return `sha256-${sha256Hex(stableJsonStringify(value))}`
530
509
  }
531
510
 
532
- /**
533
- * Computes SHA-256 without importing Node-only crypto modules, keeping this
534
- * resource-definition module safe for Expo/browser bundles.
535
- * @param {string} message - UTF-8 message.
536
- * @returns {string} - Hex digest.
537
- */
538
- function sha256Hex(message) {
539
- const bytes = utf8Bytes(message)
540
- const padded = [...bytes]
541
- const bitLength = bytes.length * 8
542
- const hash = [...SHA256_INITIAL_HASH]
543
- /** @type {number[]} */
544
- const words = new Array(64)
545
-
546
- padded.push(0x80)
547
- while (padded.length % 64 !== 56) padded.push(0)
548
-
549
- const highLength = Math.floor(bitLength / 0x100000000)
550
- const lowLength = bitLength >>> 0
551
-
552
- for (const value of [highLength, lowLength]) {
553
- padded.push((value >>> 24) & 0xff, (value >>> 16) & 0xff, (value >>> 8) & 0xff, value & 0xff)
554
- }
555
-
556
- for (let offset = 0; offset < padded.length; offset += 64) {
557
- for (let i = 0; i < 16; i++) {
558
- const index = offset + (i * 4)
559
-
560
- words[i] = (((padded[index] || 0) << 24) | ((padded[index + 1] || 0) << 16) | ((padded[index + 2] || 0) << 8) | (padded[index + 3] || 0)) >>> 0
561
- }
562
-
563
- for (let i = 16; i < 64; i++) {
564
- const s0 = rotateRight(words[i - 15], 7) ^ rotateRight(words[i - 15], 18) ^ (words[i - 15] >>> 3)
565
- const s1 = rotateRight(words[i - 2], 17) ^ rotateRight(words[i - 2], 19) ^ (words[i - 2] >>> 10)
566
-
567
- words[i] = add32(words[i - 16], s0, words[i - 7], s1)
568
- }
569
-
570
- let [a, b, c, d, e, f, g, h] = hash
571
-
572
- for (let i = 0; i < 64; i++) {
573
- const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25)
574
- const ch = (e & f) ^ ((~e) & g)
575
- const temp1 = add32(h, s1, ch, SHA256_K[i], words[i])
576
- const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22)
577
- const maj = (a & b) ^ (a & c) ^ (b & c)
578
- const temp2 = add32(s0, maj)
579
-
580
- h = g
581
- g = f
582
- f = e
583
- e = add32(d, temp1)
584
- d = c
585
- c = b
586
- b = a
587
- a = add32(temp1, temp2)
588
- }
589
-
590
- hash[0] = add32(hash[0], a)
591
- hash[1] = add32(hash[1], b)
592
- hash[2] = add32(hash[2], c)
593
- hash[3] = add32(hash[3], d)
594
- hash[4] = add32(hash[4], e)
595
- hash[5] = add32(hash[5], f)
596
- hash[6] = add32(hash[6], g)
597
- hash[7] = add32(hash[7], h)
598
- }
599
-
600
- return hash.map((value) => value.toString(16).padStart(8, "0")).join("")
601
- }
602
-
603
- /**
604
- * Converts a string to UTF-8 bytes.
605
- * @param {string} value - String value.
606
- * @returns {number[]} - UTF-8 bytes.
607
- */
608
- function utf8Bytes(value) {
609
- /** @type {number[]} */
610
- const bytes = []
611
-
612
- for (const character of value) {
613
- const codePoint = /** @type {number} */ (character.codePointAt(0))
614
-
615
- if (codePoint <= 0x7f) {
616
- bytes.push(codePoint)
617
- } else if (codePoint <= 0x7ff) {
618
- bytes.push(0xc0 | (codePoint >>> 6), 0x80 | (codePoint & 0x3f))
619
- } else if (codePoint <= 0xffff) {
620
- bytes.push(0xe0 | (codePoint >>> 12), 0x80 | ((codePoint >>> 6) & 0x3f), 0x80 | (codePoint & 0x3f))
621
- } else {
622
- bytes.push(0xf0 | (codePoint >>> 18), 0x80 | ((codePoint >>> 12) & 0x3f), 0x80 | ((codePoint >>> 6) & 0x3f), 0x80 | (codePoint & 0x3f))
623
- }
624
- }
625
-
626
- return bytes
627
- }
628
-
629
- /**
630
- * Adds unsigned 32-bit integers.
631
- * @param {...number} values - Values to add.
632
- * @returns {number} - Unsigned 32-bit result.
633
- */
634
- function add32(...values) {
635
- return values.reduce((sum, value) => (sum + value) >>> 0, 0)
636
- }
637
-
638
- /**
639
- * Rotates a 32-bit integer right.
640
- * @param {number} value - Value to rotate.
641
- * @param {number} bits - Bit count.
642
- * @returns {number} - Rotated value.
643
- */
644
- function rotateRight(value, bits) {
645
- return (value >>> bits) | (value << (32 - bits))
646
- }
647
-
648
511
  /**
649
512
  * Validates that a sync config subtree is deterministic JSON and does not contain obvious secrets.
650
513
  * @param {object} args - Arguments.
@@ -8,6 +8,11 @@ export default class BackgroundJobsClient {
8
8
  configuration?: import("../configuration.js").default | undefined;
9
9
  });
10
10
  configurationPromise: Promise<import("../configuration.js").default>;
11
+ /**
12
+ * Builds a one-shot client socket request from the resolved configuration.
13
+ * @returns {Promise<BackgroundJobsSocketRequest>} - Socket request.
14
+ */
15
+ _request(): Promise<BackgroundJobsSocketRequest>;
11
16
  /**
12
17
  * Runs enqueue.
13
18
  * @param {object} args - Options.
@@ -21,5 +26,30 @@ export default class BackgroundJobsClient {
21
26
  args: Array<unknown>;
22
27
  options?: import("./types.js").BackgroundJobOptions | undefined;
23
28
  }): Promise<string>;
29
+ /**
30
+ * Atomically replaces the queued owner of a stable schedule key.
31
+ * @param {object} args - Options.
32
+ * @param {string} args.scheduleKey - Stable logical schedule key.
33
+ * @param {string} args.jobName - Job name.
34
+ * @param {Array<?>} args.args - Job args.
35
+ * @param {import("./types.js").BackgroundJobOptions} [args.options] - Job options.
36
+ * @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
37
+ */
38
+ replaceScheduled({ scheduleKey, jobName, args, options }: {
39
+ scheduleKey: string;
40
+ jobName: string;
41
+ args: Array<unknown>;
42
+ options?: import("./types.js").BackgroundJobOptions | undefined;
43
+ }): Promise<import("./types.js").BackgroundJobReplacementResult>;
44
+ /**
45
+ * Cancels or detaches the current owner of a stable schedule key.
46
+ * @param {object} args - Options.
47
+ * @param {string} args.scheduleKey - Stable logical schedule key.
48
+ * @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
49
+ */
50
+ cancelScheduled({ scheduleKey }: {
51
+ scheduleKey: string;
52
+ }): Promise<import("./types.js").BackgroundJobCancellationResult>;
24
53
  }
54
+ import BackgroundJobsSocketRequest from "./socket-request.js";
25
55
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/client.js"],"names":[],"mappings":"AAKA;IACE;;;;OAIG;IACH,gCAFG;QAAqD,aAAa;KACpE,EAGA;IADC,qEAAoG;IAGtG;;;;;;;OAOG;IACH,oCALG;QAAqB,OAAO,EAApB,MAAM;QACS,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CA2B3B;CACF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/client.js"],"names":[],"mappings":"AAKA;IACE;;;;OAIG;IACH,gCAFG;QAAqD,aAAa;KACpE,EAGA;IADC,qEAAoG;IAGtG;;;OAGG;IACH,YAFa,OAAO,CAAC,2BAA2B,CAAC,CAOhD;IAED;;;;;;;OAOG;IACH,oCALG;QAAqB,OAAO,EAApB,MAAM;QACS,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CAyB3B;IAED;;;;;;;;OAQG;IACH,0DANG;QAAqB,WAAW,EAAxB,MAAM;QACO,OAAO,EAApB,MAAM;QACS,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,OAAO,YAAY,EAAE,8BAA8B,CAAC,CAwBxE;IAED;;;;;OAKG;IACH,iCAHG;QAAqB,WAAW,EAAxB,MAAM;KACd,GAAU,OAAO,CAAC,OAAO,YAAY,EAAE,+BAA+B,CAAC,CAoBzE;CACF;wCAlHuC,qBAAqB"}
@@ -10,6 +10,15 @@ export default class BackgroundJobsClient {
10
10
  constructor({ configuration } = {}) {
11
11
  this.configurationPromise = configuration ? Promise.resolve(configuration) : configurationResolver();
12
12
  }
13
+ /**
14
+ * Builds a one-shot client socket request from the resolved configuration.
15
+ * @returns {Promise<BackgroundJobsSocketRequest>} - Socket request.
16
+ */
17
+ async _request() {
18
+ const configuration = await this.configurationPromise;
19
+ const { host, port } = configuration.getBackgroundJobsConfig();
20
+ return new BackgroundJobsSocketRequest({ host, port, role: "client" });
21
+ }
13
22
  /**
14
23
  * Runs enqueue.
15
24
  * @param {object} args - Options.
@@ -19,9 +28,7 @@ export default class BackgroundJobsClient {
19
28
  * @returns {Promise<string>} - Job id.
20
29
  */
21
30
  async enqueue({ jobName, args, options }) {
22
- const configuration = await this.configurationPromise;
23
- const { host, port } = configuration.getBackgroundJobsConfig();
24
- const request = new BackgroundJobsSocketRequest({ host, port, role: "client" });
31
+ const request = await this._request();
25
32
  return await request.run({
26
33
  onConnect: (jsonSocket) => {
27
34
  jsonSocket.send({
@@ -42,5 +49,58 @@ export default class BackgroundJobsClient {
42
49
  }
43
50
  });
44
51
  }
52
+ /**
53
+ * Atomically replaces the queued owner of a stable schedule key.
54
+ * @param {object} args - Options.
55
+ * @param {string} args.scheduleKey - Stable logical schedule key.
56
+ * @param {string} args.jobName - Job name.
57
+ * @param {Array<?>} args.args - Job args.
58
+ * @param {import("./types.js").BackgroundJobOptions} [args.options] - Job options.
59
+ * @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
60
+ */
61
+ async replaceScheduled({ scheduleKey, jobName, args, options }) {
62
+ const request = await this._request();
63
+ return await request.run({
64
+ onConnect: (jsonSocket) => {
65
+ jsonSocket.send({ type: "replace-scheduled", scheduleKey, jobName, args, options });
66
+ },
67
+ onMessage: ({ message, resolve, reject }) => {
68
+ if (message?.type === "schedule-replaced") {
69
+ resolve({
70
+ jobId: message.jobId,
71
+ previousJobId: message.previousJobId,
72
+ previousStatus: message.previousStatus
73
+ });
74
+ return;
75
+ }
76
+ if (message?.type === "replace-scheduled-error") {
77
+ reject(new Error(message.error || "Failed to replace scheduled job"));
78
+ }
79
+ }
80
+ });
81
+ }
82
+ /**
83
+ * Cancels or detaches the current owner of a stable schedule key.
84
+ * @param {object} args - Options.
85
+ * @param {string} args.scheduleKey - Stable logical schedule key.
86
+ * @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
87
+ */
88
+ async cancelScheduled({ scheduleKey }) {
89
+ const request = await this._request();
90
+ return await request.run({
91
+ onConnect: (jsonSocket) => {
92
+ jsonSocket.send({ type: "cancel-scheduled", scheduleKey });
93
+ },
94
+ onMessage: ({ message, resolve, reject }) => {
95
+ if (message?.type === "schedule-cancelled") {
96
+ resolve({ jobId: message.jobId, outcome: message.outcome });
97
+ return;
98
+ }
99
+ if (message?.type === "cancel-scheduled-error") {
100
+ reject(new Error(message.error || "Failed to cancel scheduled job"));
101
+ }
102
+ }
103
+ });
104
+ }
45
105
  }
46
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JhY2tncm91bmQtam9icy9jbGllbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8scUJBQXFCLE1BQU0sOEJBQThCLENBQUE7QUFDaEUsT0FBTywyQkFBMkIsTUFBTSxxQkFBcUIsQ0FBQTtBQUU3RCxNQUFNLENBQUMsT0FBTyxPQUFPLG9CQUFvQjtJQUN2Qzs7OztPQUlHO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBQyxHQUFHLEVBQUU7UUFDOUIsSUFBSSxDQUFDLG9CQUFvQixHQUFHLGFBQWEsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMscUJBQXFCLEVBQUUsQ0FBQTtJQUN0RyxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBQztRQUNwQyxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQTtRQUNyRCxNQUFNLEVBQUMsSUFBSSxFQUFFLElBQUksRUFBQyxHQUFHLGFBQWEsQ0FBQyx1QkFBdUIsRUFBRSxDQUFBO1FBQzVELE1BQU0sT0FBTyxHQUFHLElBQUksMkJBQTJCLENBQUMsRUFBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUMsQ0FBQyxDQUFBO1FBRTdFLE9BQU8sTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1lBQ3ZCLFNBQVMsRUFBRSxDQUFDLFVBQVUsRUFBRSxFQUFFO2dCQUN4QixVQUFVLENBQUMsSUFBSSxDQUFDO29CQUNkLElBQUksRUFBRSxTQUFTO29CQUNmLE9BQU87b0JBQ1AsSUFBSTtvQkFDSixPQUFPO2lCQUNSLENBQUMsQ0FBQTtZQUNKLENBQUM7WUFDRCxTQUFTLEVBQUUsQ0FBQyxFQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFDLEVBQUUsRUFBRTtnQkFDeEMsSUFBSSxPQUFPLEVBQUUsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO29CQUNqQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO29CQUN0QixPQUFNO2dCQUNSLENBQUM7Z0JBRUQsSUFBSSxPQUFPLEVBQUUsSUFBSSxLQUFLLGVBQWUsRUFBRSxDQUFDO29CQUN0QyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSx1QkFBdUIsQ0FBQyxDQUFDLENBQUE7Z0JBQzdELENBQUM7WUFDSCxDQUFDO1NBQ0YsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBjb25maWd1cmF0aW9uUmVzb2x2ZXIgZnJvbSBcIi4uL2NvbmZpZ3VyYXRpb24tcmVzb2x2ZXIuanNcIlxuaW1wb3J0IEJhY2tncm91bmRKb2JzU29ja2V0UmVxdWVzdCBmcm9tIFwiLi9zb2NrZXQtcmVxdWVzdC5qc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzQ2xpZW50IHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gW2FyZ3MuY29uZmlndXJhdGlvbl0gLSBDb25maWd1cmF0aW9uLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbmZpZ3VyYXRpb259ID0ge30pIHtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlID0gY29uZmlndXJhdGlvbiA/IFByb21pc2UucmVzb2x2ZShjb25maWd1cmF0aW9uKSA6IGNvbmZpZ3VyYXRpb25SZXNvbHZlcigpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBlbnF1ZXVlLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYk5hbWUgLSBKb2IgbmFtZS5cbiAgICogQHBhcmFtIHtBcnJheTw/Pn0gYXJncy5hcmdzIC0gSm9iIGFyZ3MuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iT3B0aW9uc30gW2FyZ3Mub3B0aW9uc10gLSBKb2Igb3B0aW9ucy5cbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gLSBKb2IgaWQuXG4gICAqL1xuICBhc3luYyBlbnF1ZXVlKHtqb2JOYW1lLCBhcmdzLCBvcHRpb25zfSkge1xuICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlXG4gICAgY29uc3Qge2hvc3QsIHBvcnR9ID0gY29uZmlndXJhdGlvbi5nZXRCYWNrZ3JvdW5kSm9ic0NvbmZpZygpXG4gICAgY29uc3QgcmVxdWVzdCA9IG5ldyBCYWNrZ3JvdW5kSm9ic1NvY2tldFJlcXVlc3Qoe2hvc3QsIHBvcnQsIHJvbGU6IFwiY2xpZW50XCJ9KVxuXG4gICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucnVuKHtcbiAgICAgIG9uQ29ubmVjdDogKGpzb25Tb2NrZXQpID0+IHtcbiAgICAgICAganNvblNvY2tldC5zZW5kKHtcbiAgICAgICAgICB0eXBlOiBcImVucXVldWVcIixcbiAgICAgICAgICBqb2JOYW1lLFxuICAgICAgICAgIGFyZ3MsXG4gICAgICAgICAgb3B0aW9uc1xuICAgICAgICB9KVxuICAgICAgfSxcbiAgICAgIG9uTWVzc2FnZTogKHttZXNzYWdlLCByZXNvbHZlLCByZWplY3R9KSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImVucXVldWVkXCIpIHtcbiAgICAgICAgICByZXNvbHZlKG1lc3NhZ2Uuam9iSWQpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJlbnF1ZXVlLWVycm9yXCIpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKG1lc3NhZ2UuZXJyb3IgfHwgXCJGYWlsZWQgdG8gZW5xdWV1ZSBqb2JcIikpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuICB9XG59XG4iXX0=
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JhY2tncm91bmQtam9icy9jbGllbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8scUJBQXFCLE1BQU0sOEJBQThCLENBQUE7QUFDaEUsT0FBTywyQkFBMkIsTUFBTSxxQkFBcUIsQ0FBQTtBQUU3RCxNQUFNLENBQUMsT0FBTyxPQUFPLG9CQUFvQjtJQUN2Qzs7OztPQUlHO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBQyxHQUFHLEVBQUU7UUFDOUIsSUFBSSxDQUFDLG9CQUFvQixHQUFHLGFBQWEsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMscUJBQXFCLEVBQUUsQ0FBQTtJQUN0RyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLFFBQVE7UUFDWixNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQTtRQUNyRCxNQUFNLEVBQUMsSUFBSSxFQUFFLElBQUksRUFBQyxHQUFHLGFBQWEsQ0FBQyx1QkFBdUIsRUFBRSxDQUFBO1FBRTVELE9BQU8sSUFBSSwyQkFBMkIsQ0FBQyxFQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBQyxDQUFDLENBQUE7SUFDdEUsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUM7UUFDcEMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUE7UUFFckMsT0FBTyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdkIsU0FBUyxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxJQUFJLENBQUM7b0JBQ2QsSUFBSSxFQUFFLFNBQVM7b0JBQ2YsT0FBTztvQkFDUCxJQUFJO29CQUNKLE9BQU87aUJBQ1IsQ0FBQyxDQUFBO1lBQ0osQ0FBQztZQUNELFNBQVMsRUFBRSxDQUFDLEVBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUMsRUFBRSxFQUFFO2dCQUN4QyxJQUFJLE9BQU8sRUFBRSxJQUFJLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQ2pDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7b0JBQ3RCLE9BQU07Z0JBQ1IsQ0FBQztnQkFFRCxJQUFJLE9BQU8sRUFBRSxJQUFJLEtBQUssZUFBZSxFQUFFLENBQUM7b0JBQ3RDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxJQUFJLHVCQUF1QixDQUFDLENBQUMsQ0FBQTtnQkFDN0QsQ0FBQztZQUNILENBQUM7U0FDRixDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxLQUFLLENBQUMsZ0JBQWdCLENBQUMsRUFBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUM7UUFDMUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUE7UUFFckMsT0FBTyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdkIsU0FBUyxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBQyxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQTtZQUNuRixDQUFDO1lBQ0QsU0FBUyxFQUFFLENBQUMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBQyxFQUFFLEVBQUU7Z0JBQ3hDLElBQUksT0FBTyxFQUFFLElBQUksS0FBSyxtQkFBbUIsRUFBRSxDQUFDO29CQUMxQyxPQUFPLENBQUM7d0JBQ04sS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO3dCQUNwQixhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWE7d0JBQ3BDLGNBQWMsRUFBRSxPQUFPLENBQUMsY0FBYztxQkFDdkMsQ0FBQyxDQUFBO29CQUNGLE9BQU07Z0JBQ1IsQ0FBQztnQkFFRCxJQUFJLE9BQU8sRUFBRSxJQUFJLEtBQUsseUJBQXlCLEVBQUUsQ0FBQztvQkFDaEQsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksaUNBQWlDLENBQUMsQ0FBQyxDQUFBO2dCQUN2RSxDQUFDO1lBQ0gsQ0FBQztTQUNGLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxlQUFlLENBQUMsRUFBQyxXQUFXLEVBQUM7UUFDakMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUE7UUFFckMsT0FBTyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdkIsU0FBUyxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBQyxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsV0FBVyxFQUFDLENBQUMsQ0FBQTtZQUMxRCxDQUFDO1lBQ0QsU0FBUyxFQUFFLENBQUMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBQyxFQUFFLEVBQUU7Z0JBQ3hDLElBQUksT0FBTyxFQUFFLElBQUksS0FBSyxvQkFBb0IsRUFBRSxDQUFDO29CQUMzQyxPQUFPLENBQUMsRUFBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sRUFBQyxDQUFDLENBQUE7b0JBQ3pELE9BQU07Z0JBQ1IsQ0FBQztnQkFFRCxJQUFJLE9BQU8sRUFBRSxJQUFJLEtBQUssd0JBQXdCLEVBQUUsQ0FBQztvQkFDL0MsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksZ0NBQWdDLENBQUMsQ0FBQyxDQUFBO2dCQUN0RSxDQUFDO1lBQ0gsQ0FBQztTQUNGLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgY29uZmlndXJhdGlvblJlc29sdmVyIGZyb20gXCIuLi9jb25maWd1cmF0aW9uLXJlc29sdmVyLmpzXCJcbmltcG9ydCBCYWNrZ3JvdW5kSm9ic1NvY2tldFJlcXVlc3QgZnJvbSBcIi4vc29ja2V0LXJlcXVlc3QuanNcIlxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCYWNrZ3JvdW5kSm9ic0NsaWVudCB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge29iamVjdH0gW2FyZ3NdIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IFthcmdzLmNvbmZpZ3VyYXRpb25dIC0gQ29uZmlndXJhdGlvbi5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25maWd1cmF0aW9ufSA9IHt9KSB7XG4gICAgdGhpcy5jb25maWd1cmF0aW9uUHJvbWlzZSA9IGNvbmZpZ3VyYXRpb24gPyBQcm9taXNlLnJlc29sdmUoY29uZmlndXJhdGlvbikgOiBjb25maWd1cmF0aW9uUmVzb2x2ZXIoKVxuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIG9uZS1zaG90IGNsaWVudCBzb2NrZXQgcmVxdWVzdCBmcm9tIHRoZSByZXNvbHZlZCBjb25maWd1cmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxCYWNrZ3JvdW5kSm9ic1NvY2tldFJlcXVlc3Q+fSAtIFNvY2tldCByZXF1ZXN0LlxuICAgKi9cbiAgYXN5bmMgX3JlcXVlc3QoKSB7XG4gICAgY29uc3QgY29uZmlndXJhdGlvbiA9IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvblByb21pc2VcbiAgICBjb25zdCB7aG9zdCwgcG9ydH0gPSBjb25maWd1cmF0aW9uLmdldEJhY2tncm91bmRKb2JzQ29uZmlnKClcblxuICAgIHJldHVybiBuZXcgQmFja2dyb3VuZEpvYnNTb2NrZXRSZXF1ZXN0KHtob3N0LCBwb3J0LCByb2xlOiBcImNsaWVudFwifSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGVucXVldWUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iTmFtZSAtIEpvYiBuYW1lLlxuICAgKiBAcGFyYW0ge0FycmF5PD8+fSBhcmdzLmFyZ3MgLSBKb2IgYXJncy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JPcHRpb25zfSBbYXJncy5vcHRpb25zXSAtIEpvYiBvcHRpb25zLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSAtIEpvYiBpZC5cbiAgICovXG4gIGFzeW5jIGVucXVldWUoe2pvYk5hbWUsIGFyZ3MsIG9wdGlvbnN9KSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGF3YWl0IHRoaXMuX3JlcXVlc3QoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucnVuKHtcbiAgICAgIG9uQ29ubmVjdDogKGpzb25Tb2NrZXQpID0+IHtcbiAgICAgICAganNvblNvY2tldC5zZW5kKHtcbiAgICAgICAgICB0eXBlOiBcImVucXVldWVcIixcbiAgICAgICAgICBqb2JOYW1lLFxuICAgICAgICAgIGFyZ3MsXG4gICAgICAgICAgb3B0aW9uc1xuICAgICAgICB9KVxuICAgICAgfSxcbiAgICAgIG9uTWVzc2FnZTogKHttZXNzYWdlLCByZXNvbHZlLCByZWplY3R9KSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImVucXVldWVkXCIpIHtcbiAgICAgICAgICByZXNvbHZlKG1lc3NhZ2Uuam9iSWQpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJlbnF1ZXVlLWVycm9yXCIpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKG1lc3NhZ2UuZXJyb3IgfHwgXCJGYWlsZWQgdG8gZW5xdWV1ZSBqb2JcIikpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEF0b21pY2FsbHkgcmVwbGFjZXMgdGhlIHF1ZXVlZCBvd25lciBvZiBhIHN0YWJsZSBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc2NoZWR1bGVLZXkgLSBTdGFibGUgbG9naWNhbCBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYk5hbWUgLSBKb2IgbmFtZS5cbiAgICogQHBhcmFtIHtBcnJheTw/Pn0gYXJncy5hcmdzIC0gSm9iIGFyZ3MuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iT3B0aW9uc30gW2FyZ3Mub3B0aW9uc10gLSBKb2Igb3B0aW9ucy5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUmVwbGFjZW1lbnRSZXN1bHQ+fSAtIFJlcGxhY2VtZW50IHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIHJlcGxhY2VTY2hlZHVsZWQoe3NjaGVkdWxlS2V5LCBqb2JOYW1lLCBhcmdzLCBvcHRpb25zfSkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBhd2FpdCB0aGlzLl9yZXF1ZXN0KClcblxuICAgIHJldHVybiBhd2FpdCByZXF1ZXN0LnJ1bih7XG4gICAgICBvbkNvbm5lY3Q6IChqc29uU29ja2V0KSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJyZXBsYWNlLXNjaGVkdWxlZFwiLCBzY2hlZHVsZUtleSwgam9iTmFtZSwgYXJncywgb3B0aW9uc30pXG4gICAgICB9LFxuICAgICAgb25NZXNzYWdlOiAoe21lc3NhZ2UsIHJlc29sdmUsIHJlamVjdH0pID0+IHtcbiAgICAgICAgaWYgKG1lc3NhZ2U/LnR5cGUgPT09IFwic2NoZWR1bGUtcmVwbGFjZWRcIikge1xuICAgICAgICAgIHJlc29sdmUoe1xuICAgICAgICAgICAgam9iSWQ6IG1lc3NhZ2Uuam9iSWQsXG4gICAgICAgICAgICBwcmV2aW91c0pvYklkOiBtZXNzYWdlLnByZXZpb3VzSm9iSWQsXG4gICAgICAgICAgICBwcmV2aW91c1N0YXR1czogbWVzc2FnZS5wcmV2aW91c1N0YXR1c1xuICAgICAgICAgIH0pXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJyZXBsYWNlLXNjaGVkdWxlZC1lcnJvclwiKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlLmVycm9yIHx8IFwiRmFpbGVkIHRvIHJlcGxhY2Ugc2NoZWR1bGVkIGpvYlwiKSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQ2FuY2VscyBvciBkZXRhY2hlcyB0aGUgY3VycmVudCBvd25lciBvZiBhIHN0YWJsZSBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc2NoZWR1bGVLZXkgLSBTdGFibGUgbG9naWNhbCBzY2hlZHVsZSBrZXkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYkNhbmNlbGxhdGlvblJlc3VsdD59IC0gQ2FuY2VsbGF0aW9uIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGNhbmNlbFNjaGVkdWxlZCh7c2NoZWR1bGVLZXl9KSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGF3YWl0IHRoaXMuX3JlcXVlc3QoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucnVuKHtcbiAgICAgIG9uQ29ubmVjdDogKGpzb25Tb2NrZXQpID0+IHtcbiAgICAgICAganNvblNvY2tldC5zZW5kKHt0eXBlOiBcImNhbmNlbC1zY2hlZHVsZWRcIiwgc2NoZWR1bGVLZXl9KVxuICAgICAgfSxcbiAgICAgIG9uTWVzc2FnZTogKHttZXNzYWdlLCByZXNvbHZlLCByZWplY3R9KSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcInNjaGVkdWxlLWNhbmNlbGxlZFwiKSB7XG4gICAgICAgICAgcmVzb2x2ZSh7am9iSWQ6IG1lc3NhZ2Uuam9iSWQsIG91dGNvbWU6IG1lc3NhZ2Uub3V0Y29tZX0pXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJjYW5jZWwtc2NoZWR1bGVkLWVycm9yXCIpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKG1lc3NhZ2UuZXJyb3IgfHwgXCJGYWlsZWQgdG8gY2FuY2VsIHNjaGVkdWxlZCBqb2JcIikpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuICB9XG59XG4iXX0=
@@ -65,6 +65,25 @@ export default class VelociousJob<TArgs extends Array<unknown> = []> {
65
65
  args: Array<unknown>;
66
66
  options?: import("./types.js").BackgroundJobOptions | undefined;
67
67
  }): Promise<string>;
68
+ /**
69
+ * Atomically replaces this job class's queued owner for a stable schedule key.
70
+ * @param {object} args - Options.
71
+ * @param {string} args.scheduleKey - Stable logical schedule key.
72
+ * @param {Array<?>} args.args - Job args.
73
+ * @param {import("./types.js").BackgroundJobOptions} [args.options] - Job options.
74
+ * @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
75
+ */
76
+ static replaceScheduled({ scheduleKey, args, options }: {
77
+ scheduleKey: string;
78
+ args: Array<unknown>;
79
+ options?: import("./types.js").BackgroundJobOptions | undefined;
80
+ }): Promise<import("./types.js").BackgroundJobReplacementResult>;
81
+ /**
82
+ * Cancels or detaches the current owner of a stable schedule key.
83
+ * @param {string} scheduleKey - Stable logical schedule key.
84
+ * @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
85
+ */
86
+ static cancelScheduled(scheduleKey: string): Promise<import("./types.js").BackgroundJobCancellationResult>;
68
87
  /**
69
88
  * Runs split args and options.
70
89
  * @param {Array<?>} args - Job args.
@@ -1 +1 @@
1
- {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,kCAFyB,KAAK,SAAhB,KAAK,CAAC,OAAC,CAAE;IAGrB;;;;;;OAMG;IACH,4BAFU,MAAM,EAAE,GAAG,SAAS,CAEQ;IAEtC;;;;;;OAMG;IACH,cAFU,MAAM,GAAG,SAAS,CAEJ;IAExB;;;;;;;;;OASG;IACH,qBAFU,MAAM,GAAG,SAAS,CAEG;IAE/B;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;;OAKG;IACH,2BAHW,OAAO,YAAY,EAAE,oBAAoB,GAAG,SAAS,GACnD,OAAO,YAAY,EAAE,oBAAoB,CAUrD;IAED;;;;OAIG;IACH,6BAHc,OAAC,EAAA,GACF,OAAO,CAAC,MAAM,CAAC,CAW3B;IAED;;;;;;OAMG;IACH,kDAJG;QAAuB,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CAU3B;IAED;;;;OAIG;IACH,kCAHW,KAAK,CAAC,OAAC,CAAC,GACN;QAAC,OAAO,EAAE,KAAK,CAAC,OAAC,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,YAAY,EAAE,oBAAoB,CAAA;KAAC,CAgBtF;IAED;;;;OAIG;IACH,kBAHW,KAAK,GACH,OAAO,CAAC,IAAI,CAAC,CAIzB;CACF"}
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,kCAFyB,KAAK,SAAhB,KAAK,CAAC,OAAC,CAAE;IAGrB;;;;;;OAMG;IACH,4BAFU,MAAM,EAAE,GAAG,SAAS,CAEQ;IAEtC;;;;;;OAMG;IACH,cAFU,MAAM,GAAG,SAAS,CAEJ;IAExB;;;;;;;;;OASG;IACH,qBAFU,MAAM,GAAG,SAAS,CAEG;IAE/B;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;;OAKG;IACH,2BAHW,OAAO,YAAY,EAAE,oBAAoB,GAAG,SAAS,GACnD,OAAO,YAAY,EAAE,oBAAoB,CAUrD;IAED;;;;OAIG;IACH,6BAHc,OAAC,EAAA,GACF,OAAO,CAAC,MAAM,CAAC,CAW3B;IAED;;;;;;OAMG;IACH,kDAJG;QAAuB,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CAU3B;IAED;;;;;;;OAOG;IACH,wDALG;QAAqB,WAAW,EAAxB,MAAM;QACS,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,OAAO,YAAY,EAAE,8BAA8B,CAAC,CAWxE;IAED;;;;OAIG;IACH,oCAHW,MAAM,GACJ,OAAO,CAAC,OAAO,YAAY,EAAE,+BAA+B,CAAC,CAMzE;IAED;;;;OAIG;IACH,kCAHW,KAAK,CAAC,OAAC,CAAC,GACN;QAAC,OAAO,EAAE,KAAK,CAAC,OAAC,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,YAAY,EAAE,oBAAoB,CAAA;KAAC,CAgBtF;IAED;;;;OAIG;IACH,kBAHW,KAAK,GACH,OAAO,CAAC,IAAI,CAAC,CAIzB;CACF"}