@zukhruf/mutex 0.2.0 → 0.3.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 (146) hide show
  1. package/README.md +5 -3
  2. package/dist/fencing/file-token-source.js +2 -2
  3. package/dist/fencing/file-token-source.js.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/leader-election/index.d.ts +1 -0
  9. package/dist/leader-election/index.d.ts.map +1 -1
  10. package/dist/leader-election/index.js +1 -0
  11. package/dist/leader-election/index.js.map +1 -1
  12. package/dist/leader-election/leader-election.d.ts.map +1 -1
  13. package/dist/leader-election/leader-election.js +4 -2
  14. package/dist/leader-election/leader-election.js.map +1 -1
  15. package/dist/local-directory/local-directory.d.ts +7 -0
  16. package/dist/local-directory/local-directory.d.ts.map +1 -0
  17. package/dist/local-directory/local-directory.js +75 -0
  18. package/dist/local-directory/local-directory.js.map +1 -0
  19. package/dist/local-directory/network-directory-error.d.ts +8 -0
  20. package/dist/local-directory/network-directory-error.d.ts.map +1 -0
  21. package/dist/local-directory/network-directory-error.js +13 -0
  22. package/dist/local-directory/network-directory-error.js.map +1 -0
  23. package/dist/lock-stores/file-system/file-lock-store.d.ts +6 -3
  24. package/dist/lock-stores/file-system/file-lock-store.d.ts.map +1 -1
  25. package/dist/lock-stores/file-system/file-lock-store.js +40 -11
  26. package/dist/lock-stores/file-system/file-lock-store.js.map +1 -1
  27. package/dist/lock-stores/file-system/lock-file-store.d.ts.map +1 -1
  28. package/dist/lock-stores/file-system/lock-file-store.js +9 -4
  29. package/dist/lock-stores/file-system/lock-file-store.js.map +1 -1
  30. package/dist/lock-stores/file-system/ticket-queue-file-store.d.ts.map +1 -1
  31. package/dist/lock-stores/file-system/ticket-queue-file-store.js +3 -2
  32. package/dist/lock-stores/file-system/ticket-queue-file-store.js.map +1 -1
  33. package/dist/lock-stores/ipc/child-process-connection.d.ts +3 -3
  34. package/dist/lock-stores/ipc/child-process-connection.d.ts.map +1 -1
  35. package/dist/lock-stores/ipc/child-process-connection.js +16 -20
  36. package/dist/lock-stores/ipc/child-process-connection.js.map +1 -1
  37. package/dist/lock-stores/ipc/ipc-store.d.ts.map +1 -1
  38. package/dist/lock-stores/ipc/ipc-store.js +7 -5
  39. package/dist/lock-stores/ipc/ipc-store.js.map +1 -1
  40. package/dist/lock-stores/ipc/process-channel-connection.d.ts +4 -3
  41. package/dist/lock-stores/ipc/process-channel-connection.d.ts.map +1 -1
  42. package/dist/lock-stores/ipc/process-channel-connection.js +6 -14
  43. package/dist/lock-stores/ipc/process-channel-connection.js.map +1 -1
  44. package/dist/lock-stores/memory/memory-store.d.ts +1 -1
  45. package/dist/lock-stores/memory/memory-store.d.ts.map +1 -1
  46. package/dist/lock-stores/memory/memory-store.js +13 -14
  47. package/dist/lock-stores/memory/memory-store.js.map +1 -1
  48. package/dist/lock-stores/remote/connection-supervisor.d.ts +39 -0
  49. package/dist/lock-stores/remote/connection-supervisor.d.ts.map +1 -0
  50. package/dist/lock-stores/remote/connection-supervisor.js +195 -0
  51. package/dist/lock-stores/remote/connection-supervisor.js.map +1 -0
  52. package/dist/lock-stores/remote/connection.d.ts +11 -7
  53. package/dist/lock-stores/remote/connection.d.ts.map +1 -1
  54. package/dist/lock-stores/remote/connector.d.ts +5 -2
  55. package/dist/lock-stores/remote/connector.d.ts.map +1 -1
  56. package/dist/lock-stores/remote/lock-coordinator.d.ts +2 -2
  57. package/dist/lock-stores/remote/lock-coordinator.d.ts.map +1 -1
  58. package/dist/lock-stores/remote/lock-coordinator.js +140 -69
  59. package/dist/lock-stores/remote/lock-coordinator.js.map +1 -1
  60. package/dist/lock-stores/remote/remote-lock-client.d.ts +8 -7
  61. package/dist/lock-stores/remote/remote-lock-client.d.ts.map +1 -1
  62. package/dist/lock-stores/remote/remote-lock-client.js +99 -99
  63. package/dist/lock-stores/remote/remote-lock-client.js.map +1 -1
  64. package/dist/lock-stores/socket/electing-connector.d.ts +7 -4
  65. package/dist/lock-stores/socket/electing-connector.d.ts.map +1 -1
  66. package/dist/lock-stores/socket/electing-connector.js +94 -11
  67. package/dist/lock-stores/socket/electing-connector.js.map +1 -1
  68. package/dist/lock-stores/socket/handshake.d.ts +27 -0
  69. package/dist/lock-stores/socket/handshake.d.ts.map +1 -0
  70. package/dist/lock-stores/socket/handshake.js +80 -0
  71. package/dist/lock-stores/socket/handshake.js.map +1 -0
  72. package/dist/lock-stores/socket/local-directory-connector.d.ts +14 -0
  73. package/dist/lock-stores/socket/local-directory-connector.d.ts.map +1 -0
  74. package/dist/lock-stores/socket/local-directory-connector.js +23 -0
  75. package/dist/lock-stores/socket/local-directory-connector.js.map +1 -0
  76. package/dist/lock-stores/socket/lock-server.d.ts.map +1 -1
  77. package/dist/lock-stores/socket/lock-server.js +7 -1
  78. package/dist/lock-stores/socket/lock-server.js.map +1 -1
  79. package/dist/lock-stores/socket/protocol-version-error.d.ts +12 -0
  80. package/dist/lock-stores/socket/protocol-version-error.d.ts.map +1 -0
  81. package/dist/lock-stores/socket/protocol-version-error.js +19 -0
  82. package/dist/lock-stores/socket/protocol-version-error.js.map +1 -0
  83. package/dist/lock-stores/socket/socket-connection.d.ts +3 -3
  84. package/dist/lock-stores/socket/socket-connection.d.ts.map +1 -1
  85. package/dist/lock-stores/socket/socket-connection.js +16 -18
  86. package/dist/lock-stores/socket/socket-connection.js.map +1 -1
  87. package/dist/lock-stores/socket/socket-store.d.ts +1 -2
  88. package/dist/lock-stores/socket/socket-store.d.ts.map +1 -1
  89. package/dist/lock-stores/socket/socket-store.js +16 -23
  90. package/dist/lock-stores/socket/socket-store.js.map +1 -1
  91. package/dist/lock-stores/thread/parent-port-connection.d.ts +4 -3
  92. package/dist/lock-stores/thread/parent-port-connection.d.ts.map +1 -1
  93. package/dist/lock-stores/thread/parent-port-connection.js +6 -13
  94. package/dist/lock-stores/thread/parent-port-connection.js.map +1 -1
  95. package/dist/lock-stores/thread/thread-store.d.ts.map +1 -1
  96. package/dist/lock-stores/thread/thread-store.js +5 -8
  97. package/dist/lock-stores/thread/thread-store.js.map +1 -1
  98. package/dist/lock-stores/thread/worker-connection.d.ts +3 -3
  99. package/dist/lock-stores/thread/worker-connection.d.ts.map +1 -1
  100. package/dist/lock-stores/thread/worker-connection.js +19 -23
  101. package/dist/lock-stores/thread/worker-connection.js.map +1 -1
  102. package/dist/mutex/acquire-mode.d.ts +6 -3
  103. package/dist/mutex/acquire-mode.d.ts.map +1 -1
  104. package/dist/mutex/acquire-modes/skip-if-busy-mode.d.ts +7 -3
  105. package/dist/mutex/acquire-modes/skip-if-busy-mode.d.ts.map +1 -1
  106. package/dist/mutex/acquire-modes/skip-if-busy-mode.js +7 -4
  107. package/dist/mutex/acquire-modes/skip-if-busy-mode.js.map +1 -1
  108. package/dist/mutex/acquire-modes/wait-mode.d.ts +2 -2
  109. package/dist/mutex/acquire-modes/wait-mode.d.ts.map +1 -1
  110. package/dist/mutex/acquire-modes/wait-mode.js +2 -2
  111. package/dist/mutex/acquire-modes/wait-mode.js.map +1 -1
  112. package/dist/mutex/key.d.ts +3 -2
  113. package/dist/mutex/key.d.ts.map +1 -1
  114. package/dist/mutex/key.js +3 -3
  115. package/dist/mutex/key.js.map +1 -1
  116. package/dist/mutex/mutex.d.ts +3 -3
  117. package/dist/mutex/mutex.d.ts.map +1 -1
  118. package/dist/mutex/mutex.js +28 -5
  119. package/dist/mutex/mutex.js.map +1 -1
  120. package/dist/shared/fs/atomic-write.d.ts.map +1 -1
  121. package/dist/shared/fs/atomic-write.js +3 -27
  122. package/dist/shared/fs/atomic-write.js.map +1 -1
  123. package/dist/shared/fs/create-exclusive.d.ts.map +1 -1
  124. package/dist/shared/fs/create-exclusive.js +7 -2
  125. package/dist/shared/fs/create-exclusive.js.map +1 -1
  126. package/dist/shared/fs/durable-write.d.ts +7 -0
  127. package/dist/shared/fs/durable-write.d.ts.map +1 -0
  128. package/dist/shared/fs/durable-write.js +46 -0
  129. package/dist/shared/fs/durable-write.js.map +1 -0
  130. package/dist/shared/fs/patiently.d.ts +3 -0
  131. package/dist/shared/fs/patiently.d.ts.map +1 -0
  132. package/dist/shared/fs/patiently.js +30 -0
  133. package/dist/shared/fs/patiently.js.map +1 -0
  134. package/dist/shared/fs/replace-file.d.ts +8 -0
  135. package/dist/shared/fs/replace-file.d.ts.map +1 -0
  136. package/dist/shared/fs/replace-file.js +12 -0
  137. package/dist/shared/fs/replace-file.js.map +1 -0
  138. package/dist/shared/latch.d.ts +10 -0
  139. package/dist/shared/latch.d.ts.map +1 -0
  140. package/dist/shared/latch.js +14 -0
  141. package/dist/shared/latch.js.map +1 -0
  142. package/dist/shared/sqlite/is-not-a-database.d.ts +3 -0
  143. package/dist/shared/sqlite/is-not-a-database.d.ts.map +1 -0
  144. package/dist/shared/sqlite/is-not-a-database.js +9 -0
  145. package/dist/shared/sqlite/is-not-a-database.js.map +1 -0
  146. package/package.json +1 -1
@@ -1,34 +1,10 @@
1
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;
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { replaceFile } from "./replace-file.js";
7
4
  /** Replaces `path` in one step, so readers see the old or the new content, never a partial write. */
8
5
  export async function atomicWrite(path, content) {
9
6
  const draft = `${path}.${randomUUID()}.tmp`;
10
7
  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
- }
8
+ await replaceFile(draft, path);
33
9
  }
34
10
  //# sourceMappingURL=atomic-write.js.map
@@ -1 +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"}
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,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,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"}
@@ -1 +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"}
1
+ {"version":3,"file":"create-exclusive.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/create-exclusive.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAYlE"}
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { link, unlink, writeFile } from 'node:fs/promises';
3
3
  import { isErrno } from "./errno.js";
4
+ import { patiently } from "./patiently.js";
4
5
  /**
5
6
  * Creates `path` holding `content` unless it already exists. Linking a fully
6
7
  * written file makes creation atomic, so the file is never seen empty.
@@ -9,7 +10,7 @@ export async function createExclusive(path, content) {
9
10
  const draft = `${path}.${randomUUID()}.tmp`;
10
11
  await writeFile(draft, content);
11
12
  try {
12
- await link(draft, path);
13
+ await patiently(() => link(draft, path));
13
14
  return true;
14
15
  }
15
16
  catch (error) {
@@ -18,7 +19,11 @@ export async function createExclusive(path, content) {
18
19
  throw error;
19
20
  }
20
21
  finally {
21
- await unlink(draft);
22
+ await removeDraft(draft);
22
23
  }
23
24
  }
25
+ /** A draft left behind has a unique name, so it never blocks a key; failing to remove it must not change whether `path` was created. */
26
+ async function removeDraft(draft) {
27
+ await patiently(() => unlink(draft)).catch(() => { });
28
+ }
24
29
  //# sourceMappingURL=create-exclusive.js.map
@@ -1 +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"}
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;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;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,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QACzC,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,WAAW,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,wIAAwI;AACxI,KAAK,UAAU,WAAW,CAAC,KAAa;IACtC,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Replaces `path` in one step like `atomicWrite`, and returns only once both
3
+ * the new content and the replacement survive a power loss: a counter that
4
+ * goes back after a crash would hand out a token twice.
5
+ */
6
+ export declare function durableWrite(path: string, content: string): Promise<void>;
7
+ //# sourceMappingURL=durable-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-write.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/durable-write.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAW/D"}
@@ -0,0 +1,46 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { open, rm } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
4
+ import { isErrno } from "./errno.js";
5
+ import { replaceFile } from "./replace-file.js";
6
+ /**
7
+ * Replaces `path` in one step like `atomicWrite`, and returns only once both
8
+ * the new content and the replacement survive a power loss: a counter that
9
+ * goes back after a crash would hand out a token twice.
10
+ */
11
+ export async function durableWrite(path, content) {
12
+ const draft = `${path}.${randomUUID()}.tmp`;
13
+ try {
14
+ await writeSynced(draft, content);
15
+ await replaceFile(draft, path);
16
+ }
17
+ catch (error) {
18
+ // A draft that never replaced `path` would only pile up, one per failed write.
19
+ await rm(draft, { force: true });
20
+ throw error;
21
+ }
22
+ await syncDirectory(dirname(path));
23
+ }
24
+ async function writeSynced(path, content) {
25
+ await using handle = await open(path, 'wx');
26
+ await handle.writeFile(content);
27
+ await handle.sync();
28
+ }
29
+ /**
30
+ * A rename lives in its directory, so the directory must reach the disk too.
31
+ * Windows cannot open a directory to sync it, and some file systems refuse to
32
+ * sync one; there the rename is as durable as that system makes it.
33
+ */
34
+ async function syncDirectory(directory) {
35
+ if (process.platform === 'win32')
36
+ return;
37
+ await using handle = await open(directory, 'r');
38
+ try {
39
+ await handle.sync();
40
+ }
41
+ catch (error) {
42
+ if (!isErrno(error, 'EINVAL') && !isErrno(error, 'ENOTSUP'))
43
+ throw error;
44
+ }
45
+ }
46
+ //# sourceMappingURL=durable-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-write.js","sourceRoot":"","sources":["../../../src/shared/fs/durable-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,OAAe;IAC9D,MAAM,KAAK,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClC,MAAM,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+EAA+E;QAC/E,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAe;IACtD,YAAY,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAAC,SAAiB;IAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO;IACzC,YAAY,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC;YAAE,MAAM,KAAK,CAAC;IAC3E,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Runs `operation`, and runs it again while Windows refuses the file for a moment; after that, the error reaches the caller. */
2
+ export declare function patiently<T>(operation: () => Promise<T>): Promise<T>;
3
+ //# sourceMappingURL=patiently.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patiently.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/patiently.ts"],"names":[],"mappings":"AAoBA,iIAAiI;AACjI,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAc1E"}
@@ -0,0 +1,30 @@
1
+ import { setTimeout as delay } from 'node:timers/promises';
2
+ import { isErrno } from "./errno.js";
3
+ /** How long to retry a file operation that Windows refuses for a moment. */
4
+ const WINDOWS_PATIENCE = 1000;
5
+ /**
6
+ * Windows refuses a file for a moment while another program holds it open
7
+ * with no sharing, as a virus scanner can, or while a delete of it is in
8
+ * progress. The error code is the same as for a real permission denial, so a
9
+ * refusal is retried only for a limited time.
10
+ */
11
+ function isRefusedForNow(error) {
12
+ return (process.platform === 'win32' &&
13
+ ['EPERM', 'EACCES', 'EBUSY'].some((code) => isErrno(error, code)));
14
+ }
15
+ /** Runs `operation`, and runs it again while Windows refuses the file for a moment; after that, the error reaches the caller. */
16
+ export async function patiently(operation) {
17
+ const started = performance.now();
18
+ for (let attempt = 0;; attempt++) {
19
+ try {
20
+ return await operation();
21
+ }
22
+ catch (error) {
23
+ if (!isRefusedForNow(error) ||
24
+ performance.now() - started > WINDOWS_PATIENCE)
25
+ throw error;
26
+ await delay(Math.min(5 * 2 ** attempt, 100));
27
+ }
28
+ }
29
+ }
30
+ //# sourceMappingURL=patiently.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patiently.js","sourceRoot":"","sources":["../../../src/shared/fs/patiently.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,4EAA4E;AAC5E,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B;;;;;GAKG;AACH,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,CACL,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC5B,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAClE,CAAC;AACJ,CAAC;AAED,iIAAiI;AACjI,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,SAA2B;IAC5D,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,SAAS,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,CAAC,eAAe,CAAC,KAAK,CAAC;gBACvB,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,gBAAgB;gBAE9C,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,8 @@
1
+ /**
2
+ * Moves `draft` over `path` in one step. On Windows, a rename over a file
3
+ * fails while another process has that file open, for example a waiter that
4
+ * reads it at that moment. The refusal is brief, so the rename is tried again;
5
+ * it stays the single commit point.
6
+ */
7
+ export declare function replaceFile(draft: string, path: string): Promise<void>;
8
+ //# sourceMappingURL=replace-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replace-file.d.ts","sourceRoot":"","sources":["../../../src/shared/fs/replace-file.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAEtD"}
@@ -0,0 +1,12 @@
1
+ import { rename } from 'node:fs/promises';
2
+ import { patiently } from "./patiently.js";
3
+ /**
4
+ * Moves `draft` over `path` in one step. On Windows, a rename over a file
5
+ * fails while another process has that file open, for example a waiter that
6
+ * reads it at that moment. The refusal is brief, so the rename is tried again;
7
+ * it stays the single commit point.
8
+ */
9
+ export function replaceFile(draft, path) {
10
+ return patiently(() => rename(draft, path));
11
+ }
12
+ //# sourceMappingURL=replace-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replace-file.js","sourceRoot":"","sources":["../../../src/shared/fs/replace-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,IAAY;IACrD,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A gate that starts closed and opens once. It never closes again, so a wait
3
+ * that starts after it opened ends at once.
4
+ */
5
+ export declare class Latch {
6
+ #private;
7
+ open(): void;
8
+ wait(): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=latch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latch.d.ts","sourceRoot":"","sources":["../../src/shared/latch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,KAAK;;IAGhB,IAAI,IAAI,IAAI;IAIZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtB"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A gate that starts closed and opens once. It never closes again, so a wait
3
+ * that starts after it opened ends at once.
4
+ */
5
+ export class Latch {
6
+ #opened = Promise.withResolvers();
7
+ open() {
8
+ this.#opened.resolve();
9
+ }
10
+ wait() {
11
+ return this.#opened.promise;
12
+ }
13
+ }
14
+ //# sourceMappingURL=latch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latch.js","sourceRoot":"","sources":["../../src/shared/latch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,KAAK;IACP,OAAO,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;IAEjD,IAAI;QACF,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ /** Whether `error` means the file is not a SQLite database, for example a file that an older version wrote. */
2
+ export declare function isNotADatabase(error: unknown): boolean;
3
+ //# sourceMappingURL=is-not-a-database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-not-a-database.d.ts","sourceRoot":"","sources":["../../../src/shared/sqlite/is-not-a-database.ts"],"names":[],"mappings":"AAEA,+GAA+G;AAC/G,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOtD"}
@@ -0,0 +1,9 @@
1
+ const SQLITE_NOTADB = 26;
2
+ /** Whether `error` means the file is not a SQLite database, for example a file that an older version wrote. */
3
+ export function isNotADatabase(error) {
4
+ return (error instanceof Error &&
5
+ 'errcode' in error &&
6
+ typeof error.errcode === 'number' &&
7
+ (error.errcode & 0xff) === SQLITE_NOTADB);
8
+ }
9
+ //# sourceMappingURL=is-not-a-database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-not-a-database.js","sourceRoot":"","sources":["../../../src/shared/sqlite/is-not-a-database.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,+GAA+G;AAC/G,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,SAAS,IAAI,KAAK;QAClB,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QACjC,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,aAAa,CACzC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/mutex",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "A mutex with interchangeable lock stores, from one object to every process on a host, with fencing tokens on every lease.",
5
5
  "license": "MIT",
6
6
  "repository": {