@zukhruf/mutex 0.0.0-stage → 0.2.0

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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -2
  3. package/dist/fencing/counter-token-source.d.ts +11 -0
  4. package/dist/fencing/counter-token-source.d.ts.map +1 -0
  5. package/dist/fencing/counter-token-source.js +13 -0
  6. package/dist/fencing/counter-token-source.js.map +1 -0
  7. package/dist/fencing/epoch-token-source.d.ts +13 -0
  8. package/dist/fencing/epoch-token-source.d.ts.map +1 -0
  9. package/dist/fencing/epoch-token-source.js +27 -0
  10. package/dist/fencing/epoch-token-source.js.map +1 -0
  11. package/dist/fencing/fencing-token.d.ts +12 -0
  12. package/dist/fencing/fencing-token.d.ts.map +1 -0
  13. package/dist/fencing/fencing-token.js +18 -0
  14. package/dist/fencing/fencing-token.js.map +1 -0
  15. package/dist/fencing/file-token-source.d.ts +13 -0
  16. package/dist/fencing/file-token-source.d.ts.map +1 -0
  17. package/dist/fencing/file-token-source.js +35 -0
  18. package/dist/fencing/file-token-source.js.map +1 -0
  19. package/dist/fencing/monotonic-clock-token-source.d.ts +12 -0
  20. package/dist/fencing/monotonic-clock-token-source.d.ts.map +1 -0
  21. package/dist/fencing/monotonic-clock-token-source.js +15 -0
  22. package/dist/fencing/monotonic-clock-token-source.js.map +1 -0
  23. package/dist/fencing/token-source.d.ts +9 -0
  24. package/dist/fencing/token-source.d.ts.map +1 -0
  25. package/dist/fencing/token-source.js +2 -0
  26. package/dist/fencing/token-source.js.map +1 -0
  27. package/dist/index.d.ts +27 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +24 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/leader-election/index.d.ts +3 -0
  32. package/dist/leader-election/index.d.ts.map +1 -0
  33. package/dist/leader-election/index.js +3 -0
  34. package/dist/leader-election/index.js.map +1 -0
  35. package/dist/leader-election/leader-election.d.ts +23 -0
  36. package/dist/leader-election/leader-election.d.ts.map +1 -0
  37. package/dist/leader-election/leader-election.js +77 -0
  38. package/dist/leader-election/leader-election.js.map +1 -0
  39. package/dist/leader-election/leadership.d.ts +14 -0
  40. package/dist/leader-election/leadership.d.ts.map +1 -0
  41. package/dist/leader-election/leadership.js +23 -0
  42. package/dist/leader-election/leadership.js.map +1 -0
  43. package/dist/lock-stores/file-system/file-lock-store.d.ts +35 -0
  44. package/dist/lock-stores/file-system/file-lock-store.d.ts.map +1 -0
  45. package/dist/lock-stores/file-system/file-lock-store.js +64 -0
  46. package/dist/lock-stores/file-system/file-lock-store.js.map +1 -0
  47. package/dist/lock-stores/file-system/lock-file-store.d.ts +11 -0
  48. package/dist/lock-stores/file-system/lock-file-store.d.ts.map +1 -0
  49. package/dist/lock-stores/file-system/lock-file-store.js +44 -0
  50. package/dist/lock-stores/file-system/lock-file-store.js.map +1 -0
  51. package/dist/lock-stores/file-system/owner.d.ts +16 -0
  52. package/dist/lock-stores/file-system/owner.d.ts.map +1 -0
  53. package/dist/lock-stores/file-system/owner.js +47 -0
  54. package/dist/lock-stores/file-system/owner.js.map +1 -0
  55. package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts +16 -0
  56. package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts.map +1 -0
  57. package/dist/lock-stores/file-system/ticket-queue-file-store.js +111 -0
  58. package/dist/lock-stores/file-system/ticket-queue-file-store.js.map +1 -0
  59. package/dist/lock-stores/ipc/child-process-connection.d.ts +18 -0
  60. package/dist/lock-stores/ipc/child-process-connection.d.ts.map +1 -0
  61. package/dist/lock-stores/ipc/child-process-connection.js +46 -0
  62. package/dist/lock-stores/ipc/child-process-connection.js.map +1 -0
  63. package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts +24 -0
  64. package/dist/lock-stores/ipc/ipc-lock-coordinator.d.ts.map +1 -0
  65. package/dist/lock-stores/ipc/ipc-lock-coordinator.js +27 -0
  66. package/dist/lock-stores/ipc/ipc-lock-coordinator.js.map +1 -0
  67. package/dist/lock-stores/ipc/ipc-store.d.ts +15 -0
  68. package/dist/lock-stores/ipc/ipc-store.d.ts.map +1 -0
  69. package/dist/lock-stores/ipc/ipc-store.js +34 -0
  70. package/dist/lock-stores/ipc/ipc-store.js.map +1 -0
  71. package/dist/lock-stores/ipc/process-channel-connection.d.ts +18 -0
  72. package/dist/lock-stores/ipc/process-channel-connection.d.ts.map +1 -0
  73. package/dist/lock-stores/ipc/process-channel-connection.js +52 -0
  74. package/dist/lock-stores/ipc/process-channel-connection.js.map +1 -0
  75. package/dist/lock-stores/memory/memory-store.d.ts +14 -0
  76. package/dist/lock-stores/memory/memory-store.d.ts.map +1 -0
  77. package/dist/lock-stores/memory/memory-store.js +41 -0
  78. package/dist/lock-stores/memory/memory-store.js.map +1 -0
  79. package/dist/lock-stores/remote/connection.d.ts +17 -0
  80. package/dist/lock-stores/remote/connection.d.ts.map +1 -0
  81. package/dist/lock-stores/remote/connection.js +2 -0
  82. package/dist/lock-stores/remote/connection.js.map +1 -0
  83. package/dist/lock-stores/remote/connector.d.ts +12 -0
  84. package/dist/lock-stores/remote/connector.d.ts.map +1 -0
  85. package/dist/lock-stores/remote/connector.js +2 -0
  86. package/dist/lock-stores/remote/connector.js.map +1 -0
  87. package/dist/lock-stores/remote/coordinator-unavailable-error.d.ts +6 -0
  88. package/dist/lock-stores/remote/coordinator-unavailable-error.d.ts.map +1 -0
  89. package/dist/lock-stores/remote/coordinator-unavailable-error.js +10 -0
  90. package/dist/lock-stores/remote/coordinator-unavailable-error.js.map +1 -0
  91. package/dist/lock-stores/remote/envelope.d.ts +7 -0
  92. package/dist/lock-stores/remote/envelope.d.ts.map +1 -0
  93. package/dist/lock-stores/remote/envelope.js +11 -0
  94. package/dist/lock-stores/remote/envelope.js.map +1 -0
  95. package/dist/lock-stores/remote/lock-coordinator.d.ts +34 -0
  96. package/dist/lock-stores/remote/lock-coordinator.d.ts.map +1 -0
  97. package/dist/lock-stores/remote/lock-coordinator.js +150 -0
  98. package/dist/lock-stores/remote/lock-coordinator.js.map +1 -0
  99. package/dist/lock-stores/remote/protocol.d.ts +36 -0
  100. package/dist/lock-stores/remote/protocol.d.ts.map +1 -0
  101. package/dist/lock-stores/remote/protocol.js +33 -0
  102. package/dist/lock-stores/remote/protocol.js.map +1 -0
  103. package/dist/lock-stores/remote/remote-lock-client.d.ts +17 -0
  104. package/dist/lock-stores/remote/remote-lock-client.d.ts.map +1 -0
  105. package/dist/lock-stores/remote/remote-lock-client.js +172 -0
  106. package/dist/lock-stores/remote/remote-lock-client.js.map +1 -0
  107. package/dist/lock-stores/socket/electing-connector.d.ts +21 -0
  108. package/dist/lock-stores/socket/electing-connector.d.ts.map +1 -0
  109. package/dist/lock-stores/socket/electing-connector.js +45 -0
  110. package/dist/lock-stores/socket/electing-connector.js.map +1 -0
  111. package/dist/lock-stores/socket/lock-server.d.ts +23 -0
  112. package/dist/lock-stores/socket/lock-server.d.ts.map +1 -0
  113. package/dist/lock-stores/socket/lock-server.js +67 -0
  114. package/dist/lock-stores/socket/lock-server.js.map +1 -0
  115. package/dist/lock-stores/socket/socket-connection.d.ts +18 -0
  116. package/dist/lock-stores/socket/socket-connection.d.ts.map +1 -0
  117. package/dist/lock-stores/socket/socket-connection.js +54 -0
  118. package/dist/lock-stores/socket/socket-connection.js.map +1 -0
  119. package/dist/lock-stores/socket/socket-store.d.ts +35 -0
  120. package/dist/lock-stores/socket/socket-store.d.ts.map +1 -0
  121. package/dist/lock-stores/socket/socket-store.js +84 -0
  122. package/dist/lock-stores/socket/socket-store.js.map +1 -0
  123. package/dist/lock-stores/sqlite/sqlite-store.d.ts +21 -0
  124. package/dist/lock-stores/sqlite/sqlite-store.d.ts.map +1 -0
  125. package/dist/lock-stores/sqlite/sqlite-store.js +105 -0
  126. package/dist/lock-stores/sqlite/sqlite-store.js.map +1 -0
  127. package/dist/lock-stores/thread/parent-port-connection.d.ts +20 -0
  128. package/dist/lock-stores/thread/parent-port-connection.d.ts.map +1 -0
  129. package/dist/lock-stores/thread/parent-port-connection.js +44 -0
  130. package/dist/lock-stores/thread/parent-port-connection.js.map +1 -0
  131. package/dist/lock-stores/thread/thread-lock-coordinator.d.ts +22 -0
  132. package/dist/lock-stores/thread/thread-lock-coordinator.d.ts.map +1 -0
  133. package/dist/lock-stores/thread/thread-lock-coordinator.js +25 -0
  134. package/dist/lock-stores/thread/thread-lock-coordinator.js.map +1 -0
  135. package/dist/lock-stores/thread/thread-store.d.ts +13 -0
  136. package/dist/lock-stores/thread/thread-store.d.ts.map +1 -0
  137. package/dist/lock-stores/thread/thread-store.js +37 -0
  138. package/dist/lock-stores/thread/thread-store.js.map +1 -0
  139. package/dist/lock-stores/thread/worker-connection.d.ts +19 -0
  140. package/dist/lock-stores/thread/worker-connection.d.ts.map +1 -0
  141. package/dist/lock-stores/thread/worker-connection.js +45 -0
  142. package/dist/lock-stores/thread/worker-connection.js.map +1 -0
  143. package/dist/mutex/acquire-mode.d.ts +30 -0
  144. package/dist/mutex/acquire-mode.d.ts.map +1 -0
  145. package/dist/mutex/acquire-mode.js +2 -0
  146. package/dist/mutex/acquire-mode.js.map +1 -0
  147. package/dist/mutex/acquire-modes/modes.d.ts +9 -0
  148. package/dist/mutex/acquire-modes/modes.d.ts.map +1 -0
  149. package/dist/mutex/acquire-modes/modes.js +9 -0
  150. package/dist/mutex/acquire-modes/modes.js.map +1 -0
  151. package/dist/mutex/acquire-modes/skip-if-busy-mode.d.ts +15 -0
  152. package/dist/mutex/acquire-modes/skip-if-busy-mode.d.ts.map +1 -0
  153. package/dist/mutex/acquire-modes/skip-if-busy-mode.js +27 -0
  154. package/dist/mutex/acquire-modes/skip-if-busy-mode.js.map +1 -0
  155. package/dist/mutex/acquire-modes/wait-mode.d.ts +9 -0
  156. package/dist/mutex/acquire-modes/wait-mode.d.ts.map +1 -0
  157. package/dist/mutex/acquire-modes/wait-mode.js +8 -0
  158. package/dist/mutex/acquire-modes/wait-mode.js.map +1 -0
  159. package/dist/mutex/key.d.ts +22 -0
  160. package/dist/mutex/key.d.ts.map +1 -0
  161. package/dist/mutex/key.js +21 -0
  162. package/dist/mutex/key.js.map +1 -0
  163. package/dist/mutex/lease.d.ts +9 -0
  164. package/dist/mutex/lease.d.ts.map +1 -0
  165. package/dist/mutex/lease.js +12 -0
  166. package/dist/mutex/lease.js.map +1 -0
  167. package/dist/mutex/lock-lost-error.d.ts +6 -0
  168. package/dist/mutex/lock-lost-error.d.ts.map +1 -0
  169. package/dist/mutex/lock-lost-error.js +10 -0
  170. package/dist/mutex/lock-lost-error.js.map +1 -0
  171. package/dist/mutex/lock-store.d.ts +13 -0
  172. package/dist/mutex/lock-store.d.ts.map +1 -0
  173. package/dist/mutex/lock-store.js +2 -0
  174. package/dist/mutex/lock-store.js.map +1 -0
  175. package/dist/mutex/mutex.d.ts +25 -0
  176. package/dist/mutex/mutex.d.ts.map +1 -0
  177. package/dist/mutex/mutex.js +41 -0
  178. package/dist/mutex/mutex.js.map +1 -0
  179. package/dist/shared/fs/atomic-write.d.ts +3 -0
  180. package/dist/shared/fs/atomic-write.d.ts.map +1 -0
  181. package/dist/shared/fs/atomic-write.js +34 -0
  182. package/dist/shared/fs/atomic-write.js.map +1 -0
  183. package/dist/shared/fs/create-exclusive.d.ts +6 -0
  184. package/dist/shared/fs/create-exclusive.d.ts.map +1 -0
  185. package/dist/shared/fs/create-exclusive.js +24 -0
  186. package/dist/shared/fs/create-exclusive.js.map +1 -0
  187. package/dist/shared/fs/errno.d.ts +2 -0
  188. package/dist/shared/fs/errno.d.ts.map +1 -0
  189. package/dist/shared/fs/errno.js +4 -0
  190. package/dist/shared/fs/errno.js.map +1 -0
  191. package/dist/shared/fs/safe-file-name.d.ts +8 -0
  192. package/dist/shared/fs/safe-file-name.d.ts.map +1 -0
  193. package/dist/shared/fs/safe-file-name.js +10 -0
  194. package/dist/shared/fs/safe-file-name.js.map +1 -0
  195. package/dist/shared/is-record.d.ts +3 -0
  196. package/dist/shared/is-record.d.ts.map +1 -0
  197. package/dist/shared/is-record.js +3 -0
  198. package/dist/shared/is-record.js.map +1 -0
  199. package/dist/shared/sqlite/is-busy.d.ts +3 -0
  200. package/dist/shared/sqlite/is-busy.d.ts.map +1 -0
  201. package/dist/shared/sqlite/is-busy.js +10 -0
  202. package/dist/shared/sqlite/is-busy.js.map +1 -0
  203. package/dist/shared/until-aborted.d.ts +3 -0
  204. package/dist/shared/until-aborted.d.ts.map +1 -0
  205. package/dist/shared/until-aborted.js +19 -0
  206. package/dist/shared/until-aborted.js.map +1 -0
  207. package/package.json +50 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-lost-error.d.ts","sourceRoot":"","sources":["../../src/mutex/lock-lost-error.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,GAAG,EAAE,MAAM;CAOxB"}
@@ -0,0 +1,10 @@
1
+ /** The key may have been granted to another holder while this lease was still in use. */
2
+ export class LockLostError extends Error {
3
+ key;
4
+ constructor(key) {
5
+ super(`Lost the lock on ${JSON.stringify(key)}: another holder may have been granted it.`);
6
+ this.name = 'LockLostError';
7
+ this.key = key;
8
+ }
9
+ }
10
+ //# sourceMappingURL=lock-lost-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-lost-error.js","sourceRoot":"","sources":["../../src/mutex/lock-lost-error.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,GAAG,CAAS;IAErB,YAAY,GAAW;QACrB,KAAK,CACH,oBAAoB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,4CAA4C,CACpF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { Lease } from './lease.ts';
2
+ export interface AcquireOptions {
3
+ /** Stops waiting when it aborts; the call then rejects with `signal.reason`. */
4
+ signal?: AbortSignal | undefined;
5
+ }
6
+ /** Where a mutex keeps its locks; each implementation decides who can share them. */
7
+ export interface LockStore {
8
+ /** Resolves once `key` is exclusively held. */
9
+ acquire(key: string, options?: AcquireOptions): Promise<Lease>;
10
+ /** Holds `key` only if that is possible without waiting for another holder. */
11
+ tryAcquire(key: string): Promise<Lease | undefined>;
12
+ }
13
+ //# sourceMappingURL=lock-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-store.d.ts","sourceRoot":"","sources":["../../src/mutex/lock-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/D,+EAA+E;IAC/E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CACrD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lock-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-store.js","sourceRoot":"","sources":["../../src/mutex/lock-store.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import type { AcquireMode, Outcome, OutcomeResults } from './acquire-mode.ts';
2
+ import { Key } from './key.ts';
3
+ import type { Lease } from './lease.ts';
4
+ import type { LockStore } from './lock-store.ts';
5
+ export declare class Mutex {
6
+ #private;
7
+ constructor(store: LockStore);
8
+ /** Runs `task` while holding `key`, and waits while the key is busy. */
9
+ acquire<T>(key: string, task: (lease: Lease) => Promise<T>, options?: {
10
+ mode?: undefined;
11
+ }): Promise<T>;
12
+ /** Runs `task` while holding `key`. The acquire mode decides what happens while the key is busy. */
13
+ acquire<T, O extends Outcome>(key: string, task: (lease: Lease) => Promise<T>, options: {
14
+ mode: AcquireMode<O>;
15
+ }): Promise<OutcomeResults<T>[O]>;
16
+ /** A key whose callers wait, unless one call says otherwise. */
17
+ key(name: string, options?: {
18
+ mode?: undefined;
19
+ }): Key<'always'>;
20
+ /** A key whose callers use `mode`, unless one call says otherwise. */
21
+ key<O extends Outcome>(name: string, options: {
22
+ mode: AcquireMode<O>;
23
+ }): Key<O>;
24
+ }
25
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../src/mutex/mutex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAoBjD,qBAAa,KAAK;;gBAGJ,KAAK,EAAE,SAAS;IAI5B,wEAAwE;IACxE,OAAO,CAAC,CAAC,EACP,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,EAClC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,GAC7B,OAAO,CAAC,CAAC,CAAC;IACb,oGAAoG;IACpG,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,EAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,EAClC,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;KAAE,GAChC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAWhC,gEAAgE;IAChE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,GAAG,GAAG,CAAC,QAAQ,CAAC;IAChE,sEAAsE;IACtE,GAAG,CAAC,CAAC,SAAS,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;KAAE,GAChC,GAAG,CAAC,CAAC,CAAC;CAuBV"}
@@ -0,0 +1,41 @@
1
+ import { WaitMode } from "./acquire-modes/wait-mode.js";
2
+ import { Key } from "./key.js";
3
+ const wait = new WaitMode();
4
+ const ran = (value) => ({
5
+ always: value,
6
+ maybe: { acquired: true, value },
7
+ });
8
+ // Only a mode that may give up can end without a lease. A mode whose outcome
9
+ // is 'always' and gives up breaks its contract, so reading its result throws.
10
+ const gaveUp = (key) => ({
11
+ get always() {
12
+ throw new Error(`An acquire mode whose outcome is 'always' gave up on key "${key}".`);
13
+ },
14
+ maybe: { acquired: false },
15
+ });
16
+ export class Mutex {
17
+ #store;
18
+ constructor(store) {
19
+ this.#store = store;
20
+ }
21
+ acquire(key, task, { mode } = {}) {
22
+ return mode === undefined
23
+ ? this.#run(key, task, wait)
24
+ : this.#run(key, task, mode);
25
+ }
26
+ key(name, { mode } = {}) {
27
+ return mode === undefined
28
+ ? new Key(this, name, wait)
29
+ : new Key(this, name, mode);
30
+ }
31
+ // `mode.outcome` has the type O, so TypeScript checks each result below
32
+ // against OutcomeResults<T>[O] and needs no type assertion.
33
+ async #run(key, task, mode) {
34
+ const lease = await mode.acquire(this.#store, key);
35
+ if (!lease)
36
+ return gaveUp(key)[mode.outcome];
37
+ await using held = lease;
38
+ return ran(await task(held))[mode.outcome];
39
+ }
40
+ }
41
+ //# sourceMappingURL=mutex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/mutex/mutex.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAI/B,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;AAE5B,MAAM,GAAG,GAAG,CAAI,KAAQ,EAAqB,EAAE,CAAC,CAAC;IAC/C,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE;CACjC,CAAC,CAAC;AAEH,6EAA6E;AAC7E,8EAA8E;AAC9E,MAAM,MAAM,GAAG,CAAI,GAAW,EAAqB,EAAE,CAAC,CAAC;IACrD,IAAI,MAAM;QACR,MAAM,IAAI,KAAK,CACb,6DAA6D,GAAG,IAAI,CACrE,CAAC;IACJ,CAAC;IACD,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;CAC3B,CAAC,CAAC;AAEH,MAAM,OAAO,KAAK;IACP,MAAM,CAAY;IAE3B,YAAY,KAAgB;QAC1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAcD,OAAO,CACL,GAAW,EACX,IAAkC,EAClC,EAAE,IAAI,KAA4C,EAAE;QAEpD,OAAO,IAAI,KAAK,SAAS;YACvB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;YAC5B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IASD,GAAG,CACD,IAAY,EACZ,EAAE,IAAI,KAA4C,EAAE;QAEpD,OAAO,IAAI,KAAK,SAAS;YACvB,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;YAC3B,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,wEAAwE;IACxE,4DAA4D;IAC5D,KAAK,CAAC,IAAI,CACR,GAAW,EACX,IAAkC,EAClC,IAAoB;QAEpB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK;YAAE,OAAO,MAAM,CAAI,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEhD,YAAY,IAAI,GAAG,KAAK,CAAC;QACzB,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ /** Replaces `path` in one step, so readers see the old or the new content, never a partial write. */
2
+ export declare function atomicWrite(path: string, content: string): Promise<void>;
3
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/atomic-write.ts"],"names":[],"mappings":"AASA,qGAAqG;AACrG,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAI9D"}
@@ -0,0 +1,34 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { rename, writeFile } from 'node:fs/promises';
3
+ import { setTimeout as delay } from 'node:timers/promises';
4
+ import { isErrno } from "./errno.js";
5
+ /** How long to retry a rename that Windows refuses while another handle has the target open. */
6
+ const WINDOWS_RENAME_PATIENCE = 1000;
7
+ /** Replaces `path` in one step, so readers see the old or the new content, never a partial write. */
8
+ export async function atomicWrite(path, content) {
9
+ const draft = `${path}.${randomUUID()}.tmp`;
10
+ await writeFile(draft, content);
11
+ await replaceWith(draft, path);
12
+ }
13
+ /**
14
+ * On Windows, a rename over a file fails while another process has that file
15
+ * open, for example a waiter that reads it at that moment. The refusal is
16
+ * brief, so the rename is tried again; it stays the single commit point.
17
+ */
18
+ async function replaceWith(draft, path) {
19
+ const started = performance.now();
20
+ for (let attempt = 0;; attempt++) {
21
+ try {
22
+ return await rename(draft, path);
23
+ }
24
+ catch (error) {
25
+ const refusedForNow = process.platform === 'win32' &&
26
+ ['EPERM', 'EACCES', 'EBUSY'].some((code) => isErrno(error, code));
27
+ if (!refusedForNow ||
28
+ performance.now() - started > WINDOWS_RENAME_PATIENCE)
29
+ throw error;
30
+ await delay(Math.min(5 * 2 ** attempt, 100));
31
+ }
32
+ }
33
+ }
34
+ //# sourceMappingURL=atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../../src/shared/fs/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,gGAAgG;AAChG,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAe;IAC7D,MAAM,KAAK,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAC5C,MAAM,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,KAAa,EAAE,IAAY;IACpD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAClC,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,aAAa,GACjB,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC5B,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,IACE,CAAC,aAAa;gBACd,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,uBAAuB;gBAErD,MAAM,KAAK,CAAC;YACd,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Creates `path` holding `content` unless it already exists. Linking a fully
3
+ * written file makes creation atomic, so the file is never seen empty.
4
+ */
5
+ export declare function createExclusive(path: string, content: string): Promise<boolean>;
6
+ //# sourceMappingURL=create-exclusive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-exclusive.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/create-exclusive.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAYlE"}
@@ -0,0 +1,24 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { link, unlink, writeFile } from 'node:fs/promises';
3
+ import { isErrno } from "./errno.js";
4
+ /**
5
+ * Creates `path` holding `content` unless it already exists. Linking a fully
6
+ * written file makes creation atomic, so the file is never seen empty.
7
+ */
8
+ export async function createExclusive(path, content) {
9
+ const draft = `${path}.${randomUUID()}.tmp`;
10
+ await writeFile(draft, content);
11
+ try {
12
+ await link(draft, path);
13
+ return true;
14
+ }
15
+ catch (error) {
16
+ if (isErrno(error, 'EEXIST'))
17
+ return false;
18
+ throw error;
19
+ }
20
+ finally {
21
+ await unlink(draft);
22
+ }
23
+ }
24
+ //# sourceMappingURL=create-exclusive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-exclusive.js","sourceRoot":"","sources":["../../../src/shared/fs/create-exclusive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,OAAe;IACjE,MAAM,KAAK,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAC5C,MAAM,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function isErrno(error: unknown, code: string): boolean;
2
+ //# sourceMappingURL=errno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errno.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/errno.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,4 @@
1
+ export function isErrno(error, code) {
2
+ return error instanceof Error && 'code' in error && error.code === code;
3
+ }
4
+ //# sourceMappingURL=errno.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errno.js","sourceRoot":"","sources":["../../../src/shared/fs/errno.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,OAAO,CAAC,KAAc,EAAE,IAAY;IAClD,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Maps any key to a single path segment. Encoding every dot means a key can
3
+ * never be `.` or `..`, and suffixes such as `.lock` can never collide with a key.
4
+ * On a case-insensitive file system, keys that differ only by case share a
5
+ * name, which over-locks but never under-locks.
6
+ */
7
+ export declare function safeFileName(key: string): string;
8
+ //# sourceMappingURL=safe-file-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-file-name.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/safe-file-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Maps any key to a single path segment. Encoding every dot means a key can
3
+ * never be `.` or `..`, and suffixes such as `.lock` can never collide with a key.
4
+ * On a case-insensitive file system, keys that differ only by case share a
5
+ * name, which over-locks but never under-locks.
6
+ */
7
+ export function safeFileName(key) {
8
+ return encodeURIComponent(key).replaceAll('.', '%2E');
9
+ }
10
+ //# sourceMappingURL=safe-file-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-file-name.js","sourceRoot":"","sources":["../../../src/shared/fs/safe-file-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Narrows a parsed or received value to an object whose fields can be checked one by one. */
2
+ export declare const isRecord: (value: unknown) => value is Readonly<Record<string, unknown>>;
3
+ //# sourceMappingURL=is-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-record.d.ts","sourceRoot":"","sources":["../../src/shared/is-record.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,GACnB,OAAO,OAAO,KACb,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACC,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Narrows a parsed or received value to an object whose fields can be checked one by one. */
2
+ export const isRecord = (value) => typeof value === 'object' && value !== null;
3
+ //# sourceMappingURL=is-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-record.js","sourceRoot":"","sources":["../../src/shared/is-record.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,KAAc,EAC8B,EAAE,CAC9C,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Whether `error` means another connection holds a conflicting lock right now. */
2
+ export declare function isBusy(error: unknown): boolean;
3
+ //# sourceMappingURL=is-busy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-busy.d.ts","sourceRoot":"","sources":["../../../src/shared/sqlite/is-busy.ts"],"names":[],"mappings":"AAEA,mFAAmF;AACnF,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQ9C"}
@@ -0,0 +1,10 @@
1
+ const SQLITE_BUSY = 5;
2
+ /** Whether `error` means another connection holds a conflicting lock right now. */
3
+ export function isBusy(error) {
4
+ return (error instanceof Error &&
5
+ 'errcode' in error &&
6
+ typeof error.errcode === 'number' &&
7
+ // The low byte is the primary result code, covering SQLITE_BUSY_* variants.
8
+ (error.errcode & 0xff) === SQLITE_BUSY);
9
+ }
10
+ //# sourceMappingURL=is-busy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-busy.js","sourceRoot":"","sources":["../../../src/shared/sqlite/is-busy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,mFAAmF;AACnF,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,SAAS,IAAI,KAAK;QAClB,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QACjC,4EAA4E;QAC5E,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,WAAW,CACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Settles like `promise`, or rejects with `signal.reason` first if `signal` aborts. */
2
+ export declare function untilAborted<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
3
+ //# sourceMappingURL=until-aborted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until-aborted.d.ts","sourceRoot":"","sources":["../../src/shared/until-aborted.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
@@ -0,0 +1,19 @@
1
+ /** Settles like `promise`, or rejects with `signal.reason` first if `signal` aborts. */
2
+ export function untilAborted(promise, signal) {
3
+ if (!signal)
4
+ return promise;
5
+ return new Promise((resolve, reject) => {
6
+ const abort = () => reject(signal.reason);
7
+ if (signal.aborted)
8
+ return abort();
9
+ signal.addEventListener('abort', abort, { once: true });
10
+ promise.then((value) => {
11
+ signal.removeEventListener('abort', abort);
12
+ resolve(value);
13
+ }, (error) => {
14
+ signal.removeEventListener('abort', abort);
15
+ reject(error);
16
+ });
17
+ });
18
+ }
19
+ //# sourceMappingURL=until-aborted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until-aborted.js","sourceRoot":"","sources":["../../src/shared/until-aborted.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAC1B,OAAmB,EACnB,MAA+B;IAE/B,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAC5B,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,KAAK,EAAE,CAAC;QACnC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;YACR,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@zukhruf/mutex",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "A mutex with interchangeable lock stores, from one object to every process on a host, with fencing tokens on every lease.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/JanuaryLabs/zukhruf",
9
+ "directory": "packages/mutex"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/JanuaryLabs/zukhruf/issues"
13
+ },
14
+ "homepage": "https://github.com/JanuaryLabs/zukhruf/tree/main/packages/mutex#readme",
15
+ "keywords": [
16
+ "mutex",
17
+ "lock",
18
+ "fencing-token",
19
+ "leader-election",
20
+ "inter-process"
21
+ ],
22
+ "type": "module",
23
+ "engines": {
24
+ "node": ">=26.9.0"
25
+ },
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ "./package.json": "./package.json",
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./leader-election": {
35
+ "types": "./dist/leader-election/index.d.ts",
36
+ "import": "./dist/leader-election/index.js",
37
+ "default": "./dist/leader-election/index.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "!dist/spec/**",
43
+ "!**/*.tsbuildinfo",
44
+ "!**/*.test.*"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "devDependencies": {
50
+ "hono": "^4.13.13"
51
+ }
52
+ }