@zukhruf/mutex 0.3.38 → 0.3.40

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 (38) hide show
  1. package/README.md +17 -13
  2. package/dist/index.d.ts +0 -15
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -15
  5. package/dist/index.js.map +1 -1
  6. package/dist/lock-stores/file-system/index.d.ts +5 -0
  7. package/dist/lock-stores/file-system/index.d.ts.map +1 -0
  8. package/dist/lock-stores/file-system/index.js +5 -0
  9. package/dist/lock-stores/file-system/index.js.map +1 -0
  10. package/dist/lock-stores/ipc/index.d.ts +5 -0
  11. package/dist/lock-stores/ipc/index.d.ts.map +1 -0
  12. package/dist/lock-stores/ipc/index.js +5 -0
  13. package/dist/lock-stores/ipc/index.js.map +1 -0
  14. package/dist/lock-stores/memory/index.d.ts +2 -0
  15. package/dist/lock-stores/memory/index.d.ts.map +1 -0
  16. package/dist/lock-stores/memory/index.js +2 -0
  17. package/dist/lock-stores/memory/index.js.map +1 -0
  18. package/dist/lock-stores/postgres/index.d.ts +2 -0
  19. package/dist/lock-stores/postgres/index.d.ts.map +1 -0
  20. package/dist/lock-stores/postgres/index.js +2 -0
  21. package/dist/lock-stores/postgres/index.js.map +1 -0
  22. package/dist/lock-stores/postgres/postgres-store.d.ts +47 -0
  23. package/dist/lock-stores/postgres/postgres-store.d.ts.map +1 -0
  24. package/dist/lock-stores/postgres/postgres-store.js +254 -0
  25. package/dist/lock-stores/postgres/postgres-store.js.map +1 -0
  26. package/dist/lock-stores/socket/index.d.ts +7 -0
  27. package/dist/lock-stores/socket/index.d.ts.map +1 -0
  28. package/dist/lock-stores/socket/index.js +7 -0
  29. package/dist/lock-stores/socket/index.js.map +1 -0
  30. package/dist/lock-stores/sqlite/index.d.ts +4 -0
  31. package/dist/lock-stores/sqlite/index.d.ts.map +1 -0
  32. package/dist/lock-stores/sqlite/index.js +3 -0
  33. package/dist/lock-stores/sqlite/index.js.map +1 -0
  34. package/dist/lock-stores/thread/index.d.ts +5 -0
  35. package/dist/lock-stores/thread/index.d.ts.map +1 -0
  36. package/dist/lock-stores/thread/index.js +5 -0
  37. package/dist/lock-stores/thread/index.js.map +1 -0
  38. package/package.json +17 -8
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zukhruf/mutex
2
2
 
3
- A mutex for Node.js with interchangeable lock stores. You select who shares the locks: one object, the threads of one process, a parent process and its children, or all processes on one host. The code that uses the mutex stays the same. Each lease has a fencing token, so a resource can refuse the late writes of a holder that lost its key.
3
+ A mutex for Node.js with interchangeable lock stores. You select who shares the locks: one object, the threads of one process, a parent process and its children, all processes on one host, or all machines that reach one Postgres database. The code that uses the mutex stays the same. Each lease has a fencing token, so a resource can refuse the late writes of a holder that lost its key.
4
4
 
5
5
  The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
6
6
 
@@ -19,7 +19,8 @@ if (stock > 0) {
19
19
  A mutex lets one holder at a time run this code for a key:
20
20
 
21
21
  ```ts
22
- import { MemoryStore, Mutex } from '@zukhruf/mutex';
22
+ import { Mutex } from '@zukhruf/mutex';
23
+ import { MemoryStore } from '@zukhruf/mutex/memory';
23
24
 
24
25
  const mutex = new Mutex(new MemoryStore());
25
26
 
@@ -35,22 +36,24 @@ The full program is in the recipe [Stop two requests from selling the last item]
35
36
 
36
37
  ## Select a lock store
37
38
 
38
- First find who writes to the resource. Then select the lock store with that [reach](./docs/concepts/reach.md).
39
+ First find who writes to the resource. Then select the lock store with that [reach](./docs/concepts/reach.md). Each family of lock stores has its own import path. The root `@zukhruf/mutex` gives only `Mutex` and the acquire modes ([ADR 0020](./docs/adr/0020-each-store-family-has-its-own-import-path.md)).
39
40
 
40
- | Lock store | Reach | Order | A holder stops | Needs |
41
- | ---------------------------------------------------------------- | ----------------------- | --------------------------------------- | --------------------------------------------- | --------------------------- |
42
- | [MemoryStore](./docs/stores/memory-store.md) | One object | First come, first served | The locks stop with the process | Nothing |
43
- | [ThreadStore](./docs/stores/thread-store.md) | One process (threads) | First come, first served | Released when the worker exits | `adopt(worker)` |
44
- | [IpcStore](./docs/stores/ipc-store.md) | Parent and its children | First come, first served | Released in approximately 2 ms | `fork()` and `adopt(child)` |
45
- | [TicketQueueFileStore](./docs/stores/ticket-queue-file-store.md) | One host | First come, first served | Released after a waiter finds that it stopped | A shared directory |
46
- | [LockFileStore](./docs/stores/lock-file-store.md) | One host | No order | Released after a waiter finds that it stopped | A shared directory |
47
- | [SqliteStore](./docs/stores/sqlite-store.md) | One host | First come, first served in one process | Released by the kernel | A shared directory |
48
- | [SocketStore](./docs/stores/socket-store.md) | One host | First come, first served | Released in approximately 2 ms | A shared directory |
41
+ | Lock store | Import | Reach | Order | A holder stops | Needs |
42
+ | ---------------------------------------------------------------- | ---------------------------- | --------------------------------------- | --------------------------------------- | --------------------------------------------- | -------------------------------------------- |
43
+ | [MemoryStore](./docs/stores/memory-store.md) | `@zukhruf/mutex/memory` | One object | First come, first served | The locks stop with the process | Nothing |
44
+ | [ThreadStore](./docs/stores/thread-store.md) | `@zukhruf/mutex/thread` | One process (threads) | First come, first served | Released when the worker exits | `adopt(worker)` |
45
+ | [IpcStore](./docs/stores/ipc-store.md) | `@zukhruf/mutex/ipc` | Parent and its children | First come, first served | Released in approximately 2 ms | `fork()` and `adopt(child)` |
46
+ | [TicketQueueFileStore](./docs/stores/ticket-queue-file-store.md) | `@zukhruf/mutex/file-system` | One host | First come, first served | Released after a waiter finds that it stopped | A shared directory |
47
+ | [LockFileStore](./docs/stores/lock-file-store.md) | `@zukhruf/mutex/file-system` | One host | No order | Released after a waiter finds that it stopped | A shared directory |
48
+ | [SqliteStore](./docs/stores/sqlite-store.md) | `@zukhruf/mutex/sqlite` | One host | First come, first served in one process | Released by the kernel | A shared directory |
49
+ | [SocketStore](./docs/stores/socket-store.md) | `@zukhruf/mutex/socket` | One host | First come, first served | Released in approximately 2 ms | A shared directory |
50
+ | [PostgresStore](./docs/stores/postgres-store.md) | `@zukhruf/mutex/postgres` | Every machine that reaches the database | Postgres' lock queue | Released when its session ends | A Postgres database and a `connect` function |
49
51
 
50
52
  If you are not sure:
51
53
 
52
54
  - **One process:** use `MemoryStore`.
53
55
  - **Several processes on one host:** use `SqliteStore`.
56
+ - **Many machines that already use Postgres:** use `PostgresStore`.
54
57
 
55
58
  ## Acquire modes
56
59
 
@@ -151,7 +154,8 @@ npm install @zukhruf/mutex
151
154
  ```
152
155
 
153
156
  ```ts
154
- import { Mutex, SqliteStore } from '@zukhruf/mutex';
157
+ import { Mutex } from '@zukhruf/mutex';
158
+ import { SqliteStore } from '@zukhruf/mutex/sqlite';
155
159
  ```
156
160
 
157
161
  ## Development
package/dist/index.d.ts CHANGED
@@ -7,19 +7,4 @@ export type { Acquired, AcquireMode, ModeResult, NotAcquired, Outcome, OutcomeRe
7
7
  export { Modes } from './mutex/acquire-modes/modes.ts';
8
8
  export { WaitMode } from './mutex/acquire-modes/wait-mode.ts';
9
9
  export { SkipIfBusyMode, type SkipIfBusyOptions, } from './mutex/acquire-modes/skip-if-busy-mode.ts';
10
- export { MemoryStore, type MemoryStoreOptions, } from './lock-stores/memory/memory-store.ts';
11
- export { ThreadLockCoordinator, type ThreadLockCoordinatorOptions, } from './lock-stores/thread/thread-lock-coordinator.ts';
12
- export { ThreadStore } from './lock-stores/thread/thread-store.ts';
13
- export { IpcLockCoordinator, type IpcLockCoordinatorOptions, } from './lock-stores/ipc/ipc-lock-coordinator.ts';
14
- export { IpcStore } from './lock-stores/ipc/ipc-store.ts';
15
- export { CoordinatorUnavailableError } from './lock-stores/remote/coordinator-unavailable-error.ts';
16
- export { GrantFailedError } from './lock-stores/remote/grant-failed-error.ts';
17
- export { UnsupportedRequestError } from './lock-stores/remote/unsupported-request-error.ts';
18
- export { NetworkDirectoryError } from '@zukhruf/fs';
19
- export { FileLockStore, type FileLockStoreOptions, } from './lock-stores/file-system/file-lock-store.ts';
20
- export { TicketQueueFileStore } from './lock-stores/file-system/ticket-queue-file-store.ts';
21
- export { LockFileStore } from './lock-stores/file-system/lock-file-store.ts';
22
- export { SqliteStore } from './lock-stores/sqlite/sqlite-store.ts';
23
- export { ProtocolVersionError } from './lock-stores/socket/protocol-version-error.ts';
24
- export { SocketStore, type SocketRole, type SocketStoreOptions, } from './lock-stores/socket/socket-store.ts';
25
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,OAAO,EACP,cAAc,GACf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,EACX,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,OAAO,EACP,cAAc,GACf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,4CAA4C,CAAC"}
package/dist/index.js CHANGED
@@ -5,19 +5,4 @@ export { LeaseLostError } from '@zukhruf/lease';
5
5
  export { Modes } from "./mutex/acquire-modes/modes.js";
6
6
  export { WaitMode } from "./mutex/acquire-modes/wait-mode.js";
7
7
  export { SkipIfBusyMode, } from "./mutex/acquire-modes/skip-if-busy-mode.js";
8
- export { MemoryStore, } from "./lock-stores/memory/memory-store.js";
9
- export { ThreadLockCoordinator, } from "./lock-stores/thread/thread-lock-coordinator.js";
10
- export { ThreadStore } from "./lock-stores/thread/thread-store.js";
11
- export { IpcLockCoordinator, } from "./lock-stores/ipc/ipc-lock-coordinator.js";
12
- export { IpcStore } from "./lock-stores/ipc/ipc-store.js";
13
- export { CoordinatorUnavailableError } from "./lock-stores/remote/coordinator-unavailable-error.js";
14
- export { GrantFailedError } from "./lock-stores/remote/grant-failed-error.js";
15
- export { UnsupportedRequestError } from "./lock-stores/remote/unsupported-request-error.js";
16
- export { NetworkDirectoryError } from '@zukhruf/fs';
17
- export { FileLockStore, } from "./lock-stores/file-system/file-lock-store.js";
18
- export { TicketQueueFileStore } from "./lock-stores/file-system/ticket-queue-file-store.js";
19
- export { LockFileStore } from "./lock-stores/file-system/lock-file-store.js";
20
- export { SqliteStore } from "./lock-stores/sqlite/sqlite-store.js";
21
- export { ProtocolVersionError } from "./lock-stores/socket/protocol-version-error.js";
22
- export { SocketStore, } from "./lock-stores/socket/socket-store.js";
23
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAShD,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,GAEf,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EACL,WAAW,GAEZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,GAEtB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EACL,kBAAkB,GAEnB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uDAAuD,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,aAAa,GAEd,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,WAAW,GAGZ,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAShD,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,GAEf,MAAM,4CAA4C,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { FileLockStore, type FileLockStoreOptions } from './file-lock-store.ts';
2
+ export { LockFileStore } from './lock-file-store.ts';
3
+ export { TicketQueueFileStore } from './ticket-queue-file-store.ts';
4
+ export { NetworkDirectoryError } from '@zukhruf/fs';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/file-system/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { FileLockStore } from "./file-lock-store.js";
2
+ export { LockFileStore } from "./lock-file-store.js";
3
+ export { TicketQueueFileStore } from "./ticket-queue-file-store.js";
4
+ export { NetworkDirectoryError } from '@zukhruf/fs';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/file-system/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA6B,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { IpcLockCoordinator, type IpcLockCoordinatorOptions, } from './ipc-lock-coordinator.ts';
2
+ export { IpcStore } from './ipc-store.ts';
3
+ export { CoordinatorUnavailableError } from '../remote/coordinator-unavailable-error.ts';
4
+ export { GrantFailedError } from '../remote/grant-failed-error.ts';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/ipc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { IpcLockCoordinator, } from "./ipc-lock-coordinator.js";
2
+ export { IpcStore } from "./ipc-store.js";
3
+ export { CoordinatorUnavailableError } from "../remote/coordinator-unavailable-error.js";
4
+ export { GrantFailedError } from "../remote/grant-failed-error.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/ipc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MemoryStore, type MemoryStoreOptions } from './memory-store.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MemoryStore } from "./memory-store.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PostgresStore, type PostgresSession, type PostgresStoreOptions, } from './postgres-store.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/postgres/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PostgresStore, } from "./postgres-store.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/postgres/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAGd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { LockHandle } from '../../mutex/lease.ts';
2
+ import type { AcquireOptions, LockStore } from '../../mutex/lock-store.ts';
3
+ /**
4
+ * One connection to the Postgres server: only the methods that the store
5
+ * calls. A `PoolClient` of `pg` (node-postgres) fits it.
6
+ */
7
+ export interface PostgresSession {
8
+ query(text: string, values: unknown[]): Promise<{
9
+ rows: Record<string, unknown>[];
10
+ }>;
11
+ on(event: 'error', listener: (error: Error) => void): unknown;
12
+ on(event: 'end', listener: () => void): unknown;
13
+ off(event: 'error' | 'end', listener: (error: Error) => void): unknown;
14
+ /** `true` destroys the session; `false` gives it back to its pool. */
15
+ release(destroy: boolean): void;
16
+ }
17
+ export interface PostgresStoreOptions {
18
+ /** Gives a new session. The store owns each session that it gets. */
19
+ connect(): Promise<PostgresSession>;
20
+ /** The name of an existing sequence for the fencing tokens. The store runs no DDL. */
21
+ sequence: string;
22
+ /**
23
+ * Milliseconds between two heartbeats of a holder, and the time limit of
24
+ * each heartbeat: the longest time that a holder can work after its session
25
+ * ended, before its signal aborts.
26
+ */
27
+ heartbeatInterval: number;
28
+ }
29
+ /**
30
+ * Holds a session-level advisory lock of Postgres for each key, on a session
31
+ * of its own. The server releases the lock when the session ends, so a
32
+ * holder that stops never leaves a key locked. Every process on every machine
33
+ * that reaches one database shares the locks.
34
+ *
35
+ * Callers in this process first line up in a queue in memory, so only the
36
+ * first one gets a session: one session per key per process, however many
37
+ * callers wait, and first-come order within the process.
38
+ */
39
+ export declare class PostgresStore implements LockStore {
40
+ #private;
41
+ constructor(options: PostgresStoreOptions);
42
+ acquire(key: string, options?: AcquireOptions): Promise<LockHandle>;
43
+ tryAcquire(key: string): Promise<LockHandle | undefined>;
44
+ /** Reads `pg_locks` on a short session, and never runs an advisory lock function. */
45
+ isHeld(key: string): Promise<boolean>;
46
+ }
47
+ //# sourceMappingURL=postgres-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/postgres/postgres-store.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;IAChD,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IAC9D,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAChD,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;IACvE,sEAAsE;IACtE,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACpC,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAWD;;;;;;;;;GASG;AACH,qBAAa,aAAc,YAAW,SAAS;;gBAIjC,OAAO,EAAE,oBAAoB;IAInC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAUnE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAU9D,qFAAqF;IAC/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAkC5C"}
@@ -0,0 +1,254 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { setTimeout as delay } from 'node:timers/promises';
3
+ import { untilAborted } from '@zukhruf/async';
4
+ import { FencingToken } from '@zukhruf/fencing';
5
+ import { LeaseController } from '@zukhruf/lease';
6
+ import { MemoryStore } from "../memory/memory-store.js";
7
+ const heldQuery = `SELECT EXISTS (
8
+ SELECT 1 FROM pg_catalog.pg_locks
9
+ WHERE locktype = 'advisory'
10
+ AND database = (SELECT oid FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())
11
+ AND objsubid = 1
12
+ AND ((classid::bigint << 32) | objid::bigint) = $1::bigint
13
+ AND granted
14
+ ) AS held`;
15
+ /**
16
+ * Holds a session-level advisory lock of Postgres for each key, on a session
17
+ * of its own. The server releases the lock when the session ends, so a
18
+ * holder that stops never leaves a key locked. Every process on every machine
19
+ * that reaches one database shares the locks.
20
+ *
21
+ * Callers in this process first line up in a queue in memory, so only the
22
+ * first one gets a session: one session per key per process, however many
23
+ * callers wait, and first-come order within the process.
24
+ */
25
+ export class PostgresStore {
26
+ #inProcess = new MemoryStore();
27
+ #options;
28
+ constructor(options) {
29
+ this.#options = options;
30
+ }
31
+ async acquire(key, options) {
32
+ const signal = options?.signal;
33
+ await using turn = new AsyncDisposableStack();
34
+ // Joining the in-process queue is synchronous, so the order is the order of the calls.
35
+ turn.use(await this.#inProcess.acquire(key, { signal }));
36
+ const session = await this.#session(key, signal);
37
+ await session.wait(signal);
38
+ return withTurn(await session.hold(), turn);
39
+ }
40
+ async tryAcquire(key) {
41
+ await using turn = new AsyncDisposableStack();
42
+ const inProcess = await this.#inProcess.tryAcquire(key);
43
+ if (!inProcess)
44
+ return undefined;
45
+ turn.use(inProcess);
46
+ const session = await this.#session(key, undefined);
47
+ if (!(await session.try()))
48
+ return undefined;
49
+ return withTurn(await session.hold(), turn);
50
+ }
51
+ /** Reads `pg_locks` on a short session, and never runs an advisory lock function. */
52
+ async isHeld(key) {
53
+ const session = new OwnedSession(await this.#options.connect());
54
+ try {
55
+ const [row] = await session.query(heldQuery, [lockNumber(key)]);
56
+ session.giveBack();
57
+ return row?.held === true;
58
+ }
59
+ catch (error) {
60
+ session.destroy();
61
+ throw error;
62
+ }
63
+ }
64
+ /** Gets a session for `key`. A cancel never waits for the pool: a session that comes later goes back at once. */
65
+ async #session(key, signal) {
66
+ const connecting = this.#options.connect();
67
+ try {
68
+ return new KeySession(new OwnedSession(await untilAborted(connecting, signal)), key, this.#options);
69
+ }
70
+ catch (error) {
71
+ if (signal?.aborted && error === signal.reason) {
72
+ void connecting.then((late) => late.release(false), () => { });
73
+ }
74
+ throw error;
75
+ }
76
+ }
77
+ }
78
+ /**
79
+ * The number of the advisory lock of `key`: the first 8 bytes of the SHA-256
80
+ * digest of its UTF-16 code units, as a signed 64-bit integer. The code units,
81
+ * not UTF-8, so that keys that differ only in a lone surrogate get different
82
+ * numbers. Sent as text, because a JavaScript number cannot hold 64 bits.
83
+ */
84
+ function lockNumber(key) {
85
+ return createHash('sha256')
86
+ .update(Buffer.from(key, 'utf16le'))
87
+ .digest()
88
+ .readBigInt64BE(0)
89
+ .toString();
90
+ }
91
+ /**
92
+ * A session from `connect` that the store owns until it gives it back or
93
+ * destroys it, once. Its `ended` signal aborts when the session emits `error`
94
+ * or `end`. Its listeners stay on a destroyed session, because node-postgres
95
+ * can emit `error` again after the close.
96
+ */
97
+ class OwnedSession {
98
+ #session;
99
+ #ended = new AbortController();
100
+ #owned = new AbortController();
101
+ #onError = (error) => this.#ended.abort(error);
102
+ #onEnd = () => this.#ended.abort(new Error('The Postgres session ended.'));
103
+ constructor(session) {
104
+ this.#session = session;
105
+ session.on('error', this.#onError);
106
+ session.on('end', this.#onEnd);
107
+ }
108
+ get ended() {
109
+ return this.#ended.signal;
110
+ }
111
+ async query(text, values) {
112
+ return (await this.#session.query(text, values)).rows;
113
+ }
114
+ /** The session holds nothing: it goes back to the pool with its own settings. */
115
+ giveBack() {
116
+ if (this.#owned.signal.aborted)
117
+ return;
118
+ this.#owned.abort();
119
+ this.#session.off('error', this.#onError);
120
+ this.#session.off('end', this.#onEnd);
121
+ this.#session.release(false);
122
+ }
123
+ /** The lock state of the session is not known: the server releases each lock of a session that ends. */
124
+ destroy() {
125
+ if (this.#owned.signal.aborted)
126
+ return;
127
+ this.#owned.abort();
128
+ this.#session.release(true);
129
+ }
130
+ }
131
+ /** One session for one key: it waits for the lock or tries it, then holds it with a heartbeat. */
132
+ class KeySession {
133
+ #session;
134
+ #key;
135
+ #number;
136
+ #options;
137
+ #lease;
138
+ /** Aborts when the store stops holding: a release, or a lost session. */
139
+ #done = new AbortController();
140
+ constructor(session, key, options) {
141
+ this.#session = session;
142
+ this.#key = key;
143
+ this.#number = lockNumber(key);
144
+ this.#options = options;
145
+ this.#lease = new LeaseController(key);
146
+ }
147
+ /** Waits in Postgres' lock queue. A cancel closes the session, and the end of the session releases a late grant. */
148
+ async wait(signal) {
149
+ try {
150
+ // A timeout of the pool must not stop the wait.
151
+ await this.#session.query('SET statement_timeout = 0; SET lock_timeout = 0', []);
152
+ await untilAborted(this.#session.query('SELECT pg_advisory_lock($1::bigint)', [
153
+ this.#number,
154
+ ]), signal);
155
+ }
156
+ catch (error) {
157
+ this.#session.destroy();
158
+ throw error;
159
+ }
160
+ }
161
+ async try() {
162
+ try {
163
+ const [row] = await this.#session.query('SELECT pg_try_advisory_lock($1::bigint) AS locked', [this.#number]);
164
+ if (row?.locked === true)
165
+ return true;
166
+ }
167
+ catch (error) {
168
+ this.#session.destroy();
169
+ throw error;
170
+ }
171
+ this.#session.giveBack();
172
+ return false;
173
+ }
174
+ /** Mints the token of a granted lock and starts the heartbeat. A failed mint releases the key. */
175
+ async hold() {
176
+ let token;
177
+ try {
178
+ const [row] = await this.#session.query('SELECT nextval($1::regclass)::text AS token', [this.#options.sequence]);
179
+ if (typeof row?.token !== 'string') {
180
+ throw new Error(`nextval of sequence ${JSON.stringify(this.#options.sequence)} gave no number.`);
181
+ }
182
+ token = new FencingToken(BigInt(row.token));
183
+ }
184
+ catch (error) {
185
+ await this.#release();
186
+ throw error;
187
+ }
188
+ const ended = this.#session.ended;
189
+ ended.addEventListener('abort', () => this.#lose(ended.reason), {
190
+ once: true,
191
+ signal: this.#done.signal,
192
+ });
193
+ void this.#beat();
194
+ return {
195
+ token,
196
+ signal: this.#lease.signal,
197
+ [Symbol.asyncDispose]: () => this.#release(),
198
+ };
199
+ }
200
+ /** Sends `SELECT 1` each interval. A failed or late answer loses the lease. */
201
+ async #beat() {
202
+ const interval = this.#options.heartbeatInterval;
203
+ const done = this.#done.signal;
204
+ try {
205
+ for (;;) {
206
+ await delay(interval, undefined, { signal: done });
207
+ await untilAborted(this.#session.query('SELECT 1', []), AbortSignal.any([done, AbortSignal.timeout(interval)]));
208
+ }
209
+ }
210
+ catch (cause) {
211
+ if (!done.aborted)
212
+ this.#lose(cause);
213
+ }
214
+ }
215
+ /** Another holder can have the key now. */
216
+ #lose(cause) {
217
+ if (this.#done.signal.aborted)
218
+ return;
219
+ this.#done.abort();
220
+ this.#lease.lose(cause);
221
+ this.#session.destroy();
222
+ }
223
+ async #release() {
224
+ if (this.#done.signal.aborted)
225
+ return;
226
+ this.#done.abort();
227
+ try {
228
+ const [row] = await this.#session.query('SELECT pg_advisory_unlock($1::bigint) AS released', [this.#number]);
229
+ if (row?.released !== true) {
230
+ throw new Error(`The session did not hold the lock of ${JSON.stringify(this.#key)}.`);
231
+ }
232
+ await this.#session.query('RESET statement_timeout; RESET lock_timeout', []);
233
+ }
234
+ catch (cause) {
235
+ // A plain release would give the next borrower a lock that this session may still hold.
236
+ this.#lease.lose(cause);
237
+ this.#session.destroy();
238
+ return;
239
+ }
240
+ this.#lease.end();
241
+ this.#session.giveBack();
242
+ }
243
+ }
244
+ /** Releases the Postgres lock first, then lets the next caller in this process continue. */
245
+ function withTurn(handle, turn) {
246
+ turn.use(handle);
247
+ const release = turn.move();
248
+ return {
249
+ token: handle.token,
250
+ signal: handle.signal,
251
+ [Symbol.asyncDispose]: () => release.disposeAsync(),
252
+ };
253
+ }
254
+ //# sourceMappingURL=postgres-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-store.js","sourceRoot":"","sources":["../../../src/lock-stores/postgres/postgres-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { SocketStore, type SocketRole, type SocketStoreOptions, } from './socket-store.ts';
2
+ export { ProtocolVersionError } from './protocol-version-error.ts';
3
+ export { UnsupportedRequestError } from '../remote/unsupported-request-error.ts';
4
+ export { CoordinatorUnavailableError } from '../remote/coordinator-unavailable-error.ts';
5
+ export { GrantFailedError } from '../remote/grant-failed-error.ts';
6
+ export { NetworkDirectoryError } from '@zukhruf/fs';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/socket/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,UAAU,EACf,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { SocketStore, } from "./socket-store.js";
2
+ export { ProtocolVersionError } from "./protocol-version-error.js";
3
+ export { UnsupportedRequestError } from "../remote/unsupported-request-error.js";
4
+ export { CoordinatorUnavailableError } from "../remote/coordinator-unavailable-error.js";
5
+ export { GrantFailedError } from "../remote/grant-failed-error.js";
6
+ export { NetworkDirectoryError } from '@zukhruf/fs';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/socket/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAGZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { SqliteStore } from './sqlite-store.ts';
2
+ export type { FileLockStoreOptions } from '../file-system/file-lock-store.ts';
3
+ export { NetworkDirectoryError } from '@zukhruf/fs';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/sqlite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { SqliteStore } from "./sqlite-store.js";
2
+ export { NetworkDirectoryError } from '@zukhruf/fs';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/sqlite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { ThreadLockCoordinator, type ThreadLockCoordinatorOptions, } from './thread-lock-coordinator.ts';
2
+ export { ThreadStore } from './thread-store.ts';
3
+ export { CoordinatorUnavailableError } from '../remote/coordinator-unavailable-error.ts';
4
+ export { GrantFailedError } from '../remote/grant-failed-error.ts';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lock-stores/thread/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { ThreadLockCoordinator, } from "./thread-lock-coordinator.js";
2
+ export { ThreadStore } from "./thread-store.js";
3
+ export { CoordinatorUnavailableError } from "../remote/coordinator-unavailable-error.js";
4
+ export { GrantFailedError } from "../remote/grant-failed-error.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lock-stores/thread/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,GAEtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/mutex",
3
- "version": "0.3.38",
3
+ "version": "0.3.40",
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": {
@@ -26,6 +26,13 @@
26
26
  "types": "./dist/index.d.ts",
27
27
  "import": "./dist/index.js",
28
28
  "default": "./dist/index.js"
29
+ },
30
+ "./remote": null,
31
+ "./*": {
32
+ "@zukhruf/source": "./src/lock-stores/*/index.ts",
33
+ "types": "./dist/lock-stores/*/index.d.ts",
34
+ "import": "./dist/lock-stores/*/index.js",
35
+ "default": "./dist/lock-stores/*/index.js"
29
36
  }
30
37
  },
31
38
  "files": [
@@ -38,14 +45,16 @@
38
45
  "access": "public"
39
46
  },
40
47
  "dependencies": {
41
- "@zukhruf/async": "^0.3.38",
42
- "@zukhruf/election": "^0.3.38",
43
- "@zukhruf/fencing": "^0.3.38",
44
- "@zukhruf/fs": "^0.3.38",
45
- "@zukhruf/lease": "^0.3.38"
48
+ "@zukhruf/async": "^0.3.40",
49
+ "@zukhruf/election": "^0.3.40",
50
+ "@zukhruf/fencing": "^0.3.40",
51
+ "@zukhruf/fs": "^0.3.40",
52
+ "@zukhruf/lease": "^0.3.40"
46
53
  },
47
54
  "devDependencies": {
48
- "@zukhruf/testing": "^0.3.38",
49
- "hono": "^4.13.13"
55
+ "@types/pg": "^8.23.1",
56
+ "@zukhruf/testing": "^0.3.40",
57
+ "hono": "^4.13.13",
58
+ "pg": "^8.23.1"
50
59
  }
51
60
  }