@optimystic/db-core 1.0.0-beta.3 → 1.0.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 (171) hide show
  1. package/dist/src/cluster/structs.d.ts +30 -6
  2. package/dist/src/cluster/structs.d.ts.map +1 -1
  3. package/dist/src/cluster/structs.js +5 -3
  4. package/dist/src/cluster/structs.js.map +1 -1
  5. package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts +2 -1
  6. package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts.map +1 -1
  7. package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js +10 -3
  8. package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js.map +1 -1
  9. package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -1
  10. package/dist/src/cohort-topic/wire/codec.js +8 -2
  11. package/dist/src/cohort-topic/wire/codec.js.map +1 -1
  12. package/dist/src/collection/collection.d.ts +439 -34
  13. package/dist/src/collection/collection.d.ts.map +1 -1
  14. package/dist/src/collection/collection.js +843 -148
  15. package/dist/src/collection/collection.js.map +1 -1
  16. package/dist/src/collection/struct.d.ts +109 -4
  17. package/dist/src/collection/struct.d.ts.map +1 -1
  18. package/dist/src/collection/struct.js +88 -1
  19. package/dist/src/collection/struct.js.map +1 -1
  20. package/dist/src/collections/diary/diary.d.ts +6 -2
  21. package/dist/src/collections/diary/diary.d.ts.map +1 -1
  22. package/dist/src/collections/diary/diary.js +5 -2
  23. package/dist/src/collections/diary/diary.js.map +1 -1
  24. package/dist/src/collections/tree/struct.d.ts +124 -16
  25. package/dist/src/collections/tree/struct.d.ts.map +1 -1
  26. package/dist/src/collections/tree/struct.js +86 -11
  27. package/dist/src/collections/tree/struct.js.map +1 -1
  28. package/dist/src/collections/tree/tree.d.ts +13 -3
  29. package/dist/src/collections/tree/tree.d.ts.map +1 -1
  30. package/dist/src/collections/tree/tree.js +106 -40
  31. package/dist/src/collections/tree/tree.js.map +1 -1
  32. package/dist/src/index.d.ts +1 -1
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +1 -1
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/matchmaking/wire.d.ts.map +1 -1
  37. package/dist/src/matchmaking/wire.js +8 -2
  38. package/dist/src/matchmaking/wire.js.map +1 -1
  39. package/dist/src/network/durability.d.ts +45 -0
  40. package/dist/src/network/durability.d.ts.map +1 -0
  41. package/dist/src/network/durability.js +114 -0
  42. package/dist/src/network/durability.js.map +1 -0
  43. package/dist/src/network/i-key-network.d.ts +14 -6
  44. package/dist/src/network/i-key-network.d.ts.map +1 -1
  45. package/dist/src/network/index.d.ts +3 -0
  46. package/dist/src/network/index.d.ts.map +1 -1
  47. package/dist/src/network/index.js +3 -0
  48. package/dist/src/network/index.js.map +1 -1
  49. package/dist/src/network/lineage.d.ts +39 -0
  50. package/dist/src/network/lineage.d.ts.map +1 -0
  51. package/dist/src/network/lineage.js +61 -0
  52. package/dist/src/network/lineage.js.map +1 -0
  53. package/dist/src/network/routing-key.d.ts +24 -0
  54. package/dist/src/network/routing-key.d.ts.map +1 -0
  55. package/dist/src/network/routing-key.js +9 -0
  56. package/dist/src/network/routing-key.js.map +1 -0
  57. package/dist/src/network/stale-failure.d.ts +5 -1
  58. package/dist/src/network/stale-failure.d.ts.map +1 -1
  59. package/dist/src/network/stale-failure.js +5 -1
  60. package/dist/src/network/stale-failure.js.map +1 -1
  61. package/dist/src/network/struct.d.ts +151 -8
  62. package/dist/src/network/struct.d.ts.map +1 -1
  63. package/dist/src/network/struct.js.map +1 -1
  64. package/dist/src/reactivity/wire.d.ts.map +1 -1
  65. package/dist/src/reactivity/wire.js +8 -2
  66. package/dist/src/reactivity/wire.js.map +1 -1
  67. package/dist/src/testing/test-transactor.d.ts +64 -7
  68. package/dist/src/testing/test-transactor.d.ts.map +1 -1
  69. package/dist/src/testing/test-transactor.js +150 -23
  70. package/dist/src/testing/test-transactor.js.map +1 -1
  71. package/dist/src/transaction/coordinator.d.ts +141 -21
  72. package/dist/src/transaction/coordinator.d.ts.map +1 -1
  73. package/dist/src/transaction/coordinator.js +408 -122
  74. package/dist/src/transaction/coordinator.js.map +1 -1
  75. package/dist/src/transaction/errors.d.ts +39 -10
  76. package/dist/src/transaction/errors.d.ts.map +1 -1
  77. package/dist/src/transaction/errors.js +34 -9
  78. package/dist/src/transaction/errors.js.map +1 -1
  79. package/dist/src/transaction/index.d.ts +1 -0
  80. package/dist/src/transaction/index.d.ts.map +1 -1
  81. package/dist/src/transaction/index.js.map +1 -1
  82. package/dist/src/transactor/block-floors.d.ts +78 -0
  83. package/dist/src/transactor/block-floors.d.ts.map +1 -0
  84. package/dist/src/transactor/block-floors.js +62 -0
  85. package/dist/src/transactor/block-floors.js.map +1 -0
  86. package/dist/src/transactor/change-notifier.d.ts +43 -0
  87. package/dist/src/transactor/change-notifier.d.ts.map +1 -1
  88. package/dist/src/transactor/change-notifier.js +3 -0
  89. package/dist/src/transactor/change-notifier.js.map +1 -1
  90. package/dist/src/transactor/index.d.ts +1 -0
  91. package/dist/src/transactor/index.d.ts.map +1 -1
  92. package/dist/src/transactor/index.js +1 -0
  93. package/dist/src/transactor/index.js.map +1 -1
  94. package/dist/src/transactor/network-transactor.d.ts +43 -6
  95. package/dist/src/transactor/network-transactor.d.ts.map +1 -1
  96. package/dist/src/transactor/network-transactor.js +279 -86
  97. package/dist/src/transactor/network-transactor.js.map +1 -1
  98. package/dist/src/transactor/transactor-source.d.ts +94 -4
  99. package/dist/src/transactor/transactor-source.d.ts.map +1 -1
  100. package/dist/src/transactor/transactor-source.js +120 -42
  101. package/dist/src/transactor/transactor-source.js.map +1 -1
  102. package/dist/src/transactor/transactor.d.ts +14 -1
  103. package/dist/src/transactor/transactor.d.ts.map +1 -1
  104. package/dist/src/transform/atomic.d.ts.map +1 -1
  105. package/dist/src/transform/atomic.js +12 -9
  106. package/dist/src/transform/atomic.js.map +1 -1
  107. package/dist/src/transform/base-pins.d.ts +50 -17
  108. package/dist/src/transform/base-pins.d.ts.map +1 -1
  109. package/dist/src/transform/base-pins.js +58 -11
  110. package/dist/src/transform/base-pins.js.map +1 -1
  111. package/dist/src/transform/cache-source.d.ts +75 -11
  112. package/dist/src/transform/cache-source.d.ts.map +1 -1
  113. package/dist/src/transform/cache-source.js +162 -36
  114. package/dist/src/transform/cache-source.js.map +1 -1
  115. package/dist/src/transform/digest.d.ts +8 -1
  116. package/dist/src/transform/digest.d.ts.map +1 -1
  117. package/dist/src/transform/digest.js +19 -9
  118. package/dist/src/transform/digest.js.map +1 -1
  119. package/dist/src/transform/helpers.d.ts +6 -2
  120. package/dist/src/transform/helpers.d.ts.map +1 -1
  121. package/dist/src/transform/helpers.js +8 -3
  122. package/dist/src/transform/helpers.js.map +1 -1
  123. package/dist/src/transform/tracker.d.ts +94 -14
  124. package/dist/src/transform/tracker.d.ts.map +1 -1
  125. package/dist/src/transform/tracker.js +222 -68
  126. package/dist/src/transform/tracker.js.map +1 -1
  127. package/dist/src/utility/structural-equals.d.ts +38 -0
  128. package/dist/src/utility/structural-equals.d.ts.map +1 -0
  129. package/dist/src/utility/structural-equals.js +77 -0
  130. package/dist/src/utility/structural-equals.js.map +1 -0
  131. package/package.json +2 -2
  132. package/src/cluster/structs.ts +28 -7
  133. package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +260 -253
  134. package/src/cohort-topic/wire/codec.ts +222 -216
  135. package/src/collection/collection.ts +960 -157
  136. package/src/collection/struct.ts +99 -4
  137. package/src/collections/diary/diary.ts +71 -68
  138. package/src/collections/tree/struct.ts +155 -23
  139. package/src/collections/tree/tree.ts +127 -40
  140. package/src/index.ts +1 -1
  141. package/src/matchmaking/wire.ts +8 -2
  142. package/src/network/durability.ts +123 -0
  143. package/src/network/i-key-network.ts +60 -52
  144. package/src/network/index.ts +10 -7
  145. package/src/network/lineage.ts +80 -0
  146. package/src/network/routing-key.ts +27 -0
  147. package/src/network/stale-failure.ts +5 -1
  148. package/src/network/struct.ts +156 -8
  149. package/src/reactivity/wire.ts +230 -224
  150. package/src/testing/test-transactor.ts +152 -24
  151. package/src/transaction/coordinator.ts +470 -131
  152. package/src/transaction/errors.ts +34 -9
  153. package/src/transaction/index.ts +1 -0
  154. package/src/transactor/block-floors.ts +105 -0
  155. package/src/transactor/change-notifier.ts +129 -80
  156. package/src/transactor/index.ts +1 -0
  157. package/src/transactor/network-transactor.ts +297 -89
  158. package/src/transactor/transactor-source.ts +131 -42
  159. package/src/transactor/transactor.ts +13 -1
  160. package/src/transform/atomic.ts +25 -22
  161. package/src/transform/base-pins.ts +76 -18
  162. package/src/transform/cache-source.ts +327 -194
  163. package/src/transform/digest.ts +21 -10
  164. package/src/transform/helpers.ts +8 -3
  165. package/src/transform/tracker.ts +423 -270
  166. package/src/utility/structural-equals.ts +72 -0
  167. package/dist/src/utility/block-id-to-bytes.d.ts +0 -3
  168. package/dist/src/utility/block-id-to-bytes.d.ts.map +0 -1
  169. package/dist/src/utility/block-id-to-bytes.js +0 -7
  170. package/dist/src/utility/block-id-to-bytes.js.map +0 -1
  171. package/src/utility/block-id-to-bytes.ts +0 -8
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Deep structural equality over the JSON-shaped values this codebase stores and transports:
3
+ * primitives, plain objects, arrays, and `Uint8Array` (compared by bytes — a byte array survives
4
+ * `structuredClone`, which is the in-process transport the test transactors use).
5
+ *
6
+ * Written for the tree's `unchanged` entry guard (`TreeEntryGuard` in
7
+ * `packages/db-core/src/collections/tree/struct.ts`), which must decide whether the entry
8
+ * currently committed at a key is still the one a staged write read — where one side has
9
+ * usually round-tripped through the log's encoding and the other has not. The three rules
10
+ * that follow from that:
11
+ *
12
+ * - **Object key ORDER is irrelevant.** An encoder may sort keys (see `canonicalJson`); the
13
+ * value did not change because the bytes were reordered.
14
+ * - **A key whose value is `undefined` counts as ABSENT**, matching what JSON does to it, so
15
+ * `{ a: 1, b: undefined }` and `{ a: 1 }` compare equal. Without this, an entry carrying an
16
+ * explicit `undefined` property would refuse itself the moment it crossed a JSON boundary.
17
+ * - **`NaN` equals `NaN`.** A guard that can never accept its own value is a trap, not a check.
18
+ *
19
+ * NOTE: values outside that shape — `Date`, `Map`, `Set`, class instances — fall through to the
20
+ * plain-object arm and are compared by their own enumerable properties, which for two distinct
21
+ * `Date`s (no own properties) reports EQUAL. Entries are JSON-shaped by contract (they are
22
+ * serialized into the log), so nothing reaches that path today; if a richer entry type is ever
23
+ * introduced, this function needs a type tag before it can judge it.
24
+ *
25
+ * NOTE: the `Uint8Array` arm is correct but currently unreachable across the REAL transport. The
26
+ * peer-to-peer repo protocol is JSON both directions (`JSON.stringify` in
27
+ * `packages/db-p2p/src/protocol-client.ts`, `JSON.parse` in `packages/db-p2p/src/repo/service.ts`),
28
+ * and JSON turns a `Uint8Array` into an index-keyed object — which the arm below deliberately
29
+ * reports as NOT equal to the bytes it came from. So an entry type that is genuinely byte-shaped
30
+ * would make an `unchanged` guard refuse an honest write forever, not just once. No such entry
31
+ * type exists: the one candidate is the plugin's `EncodedRow` under `msgpack`, and that encoder
32
+ * throws `not yet implemented` (`packages/quereus-plugin-optimystic/src/schema/row-codec.ts`);
33
+ * under the `json` encoding BLOB columns are base64 strings before they ever reach a tree entry.
34
+ * If a byte-shaped entry type is ever introduced, the guard's `expected` needs a transport-stable
35
+ * encoding (base64, or a tagged wrapper) BEFORE this comparison can be trusted over the wire.
36
+ */
37
+ export declare function structuralEquals(a: unknown, b: unknown): boolean;
38
+ //# sourceMappingURL=structural-equals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-equals.d.ts","sourceRoot":"","sources":["../../../src/utility/structural-equals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAOhE"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Deep structural equality over the JSON-shaped values this codebase stores and transports:
3
+ * primitives, plain objects, arrays, and `Uint8Array` (compared by bytes — a byte array survives
4
+ * `structuredClone`, which is the in-process transport the test transactors use).
5
+ *
6
+ * Written for the tree's `unchanged` entry guard (`TreeEntryGuard` in
7
+ * `packages/db-core/src/collections/tree/struct.ts`), which must decide whether the entry
8
+ * currently committed at a key is still the one a staged write read — where one side has
9
+ * usually round-tripped through the log's encoding and the other has not. The three rules
10
+ * that follow from that:
11
+ *
12
+ * - **Object key ORDER is irrelevant.** An encoder may sort keys (see `canonicalJson`); the
13
+ * value did not change because the bytes were reordered.
14
+ * - **A key whose value is `undefined` counts as ABSENT**, matching what JSON does to it, so
15
+ * `{ a: 1, b: undefined }` and `{ a: 1 }` compare equal. Without this, an entry carrying an
16
+ * explicit `undefined` property would refuse itself the moment it crossed a JSON boundary.
17
+ * - **`NaN` equals `NaN`.** A guard that can never accept its own value is a trap, not a check.
18
+ *
19
+ * NOTE: values outside that shape — `Date`, `Map`, `Set`, class instances — fall through to the
20
+ * plain-object arm and are compared by their own enumerable properties, which for two distinct
21
+ * `Date`s (no own properties) reports EQUAL. Entries are JSON-shaped by contract (they are
22
+ * serialized into the log), so nothing reaches that path today; if a richer entry type is ever
23
+ * introduced, this function needs a type tag before it can judge it.
24
+ *
25
+ * NOTE: the `Uint8Array` arm is correct but currently unreachable across the REAL transport. The
26
+ * peer-to-peer repo protocol is JSON both directions (`JSON.stringify` in
27
+ * `packages/db-p2p/src/protocol-client.ts`, `JSON.parse` in `packages/db-p2p/src/repo/service.ts`),
28
+ * and JSON turns a `Uint8Array` into an index-keyed object — which the arm below deliberately
29
+ * reports as NOT equal to the bytes it came from. So an entry type that is genuinely byte-shaped
30
+ * would make an `unchanged` guard refuse an honest write forever, not just once. No such entry
31
+ * type exists: the one candidate is the plugin's `EncodedRow` under `msgpack`, and that encoder
32
+ * throws `not yet implemented` (`packages/quereus-plugin-optimystic/src/schema/row-codec.ts`);
33
+ * under the `json` encoding BLOB columns are base64 strings before they ever reach a tree entry.
34
+ * If a byte-shaped entry type is ever introduced, the guard's `expected` needs a transport-stable
35
+ * encoding (base64, or a tagged wrapper) BEFORE this comparison can be trusted over the wire.
36
+ */
37
+ export function structuralEquals(a, b) {
38
+ if (a === b)
39
+ return true; // identical reference, or identical primitive
40
+ if (typeof a === 'number' && typeof b === 'number')
41
+ return Number.isNaN(a) && Number.isNaN(b);
42
+ if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object')
43
+ return false;
44
+ if (a instanceof Uint8Array || b instanceof Uint8Array)
45
+ return bytesEqual(a, b);
46
+ if (Array.isArray(a) || Array.isArray(b))
47
+ return arraysEqual(a, b);
48
+ return objectsEqual(a, b);
49
+ }
50
+ /** Byte-wise comparison. A `Uint8Array` is only equal to another `Uint8Array` — a plain array or
51
+ * object with the same numeric indices is a DIFFERENT encoding of the value, and treating it as
52
+ * equal would let an encoding change slip past a guard unnoticed. */
53
+ function bytesEqual(a, b) {
54
+ if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array) || a.length !== b.length)
55
+ return false;
56
+ return a.every((byte, i) => byte === b[i]);
57
+ }
58
+ /** Element-wise comparison; position is meaning, so order matters here (unlike object keys). */
59
+ function arraysEqual(a, b) {
60
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
61
+ return false;
62
+ return a.every((value, i) => structuralEquals(value, b[i]));
63
+ }
64
+ /** Compares the DEFINED own properties of two plain objects, order-independently. Equal counts of
65
+ * defined keys plus a recursive match on each of `a`'s is sufficient: a key present in `b` but
66
+ * not `a` would push `b`'s count higher, and a key `a` defines that `b` leaves undefined fails
67
+ * the recursive compare. */
68
+ function objectsEqual(a, b) {
69
+ const keys = definedKeys(a);
70
+ if (keys.length !== definedKeys(b).length)
71
+ return false;
72
+ return keys.every(key => structuralEquals(a[key], b[key]));
73
+ }
74
+ function definedKeys(value) {
75
+ return Object.keys(value).filter(key => value[key] !== undefined);
76
+ }
77
+ //# sourceMappingURL=structural-equals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-equals.js","sourceRoot":"","sources":["../../../src/utility/structural-equals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAU,EAAE,CAAU;IACtD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,8CAA8C;IACxE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9F,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC7F,IAAI,CAAC,YAAY,UAAU,IAAI,CAAC,YAAY,UAAU;QAAE,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,OAAO,YAAY,CAAC,CAA4B,EAAE,CAA4B,CAAC,CAAC;AACjF,CAAC;AAED;;sEAEsE;AACtE,SAAS,UAAU,CAAC,CAAS,EAAE,CAAS;IACvC,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpG,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,gGAAgG;AAChG,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAClF,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;6BAG6B;AAC7B,SAAS,YAAY,CAAC,CAA0B,EAAE,CAA0B;IAC3E,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,WAAW,CAAC,KAA8B;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC;AACnE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimystic/db-core",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "description": "Core database functionality for Optimystic",
6
6
  "main": "dist/src/index.js",
@@ -50,8 +50,8 @@
50
50
  "@libp2p/crypto": "^5.1.13",
51
51
  "@libp2p/interface": "^3.2.4",
52
52
  "@libp2p/peer-id": "^6.0.4",
53
- "@libp2p/peer-id-factory": "^4.2.4",
54
53
  "@multiformats/multiaddr": "^13.0.1",
54
+ "@noble/curves": "^2.0.1",
55
55
  "@types/chai": "^5.2.3",
56
56
  "@types/chai-as-promised": "^8.0.2",
57
57
  "@types/debug": "^4.1.12",
@@ -18,13 +18,33 @@ export type Signature =
18
18
  * counted toward the permanent-rejection threshold. `conflictWith` is the winning
19
19
  * transaction's messageHash: structured, signed, and readable without parsing prose.
20
20
  */
21
- | { type: 'conflict'; signature: string; conflictWith: string };
21
+ | { type: 'conflict'; signature: string; conflictWith: string }
22
+ /**
23
+ * This member refuses the transaction *for now* for the OTHER transient reason: the pend's blocks
24
+ * are reserved by a different unresolved action in this member's durable storage. Retryable and
25
+ * never counted toward the permanent-rejection threshold, exactly like `conflict`.
26
+ *
27
+ * Distinct from `conflict` because the two know different things, from different places:
28
+ * - `conflict` comes from the member's in-memory reservation table, where it holds the rival's
29
+ * whole {@link ClusterRecord} and can name its `messageHash`.
30
+ * - `held` comes from storage's pending list, which carries only an **action id** — and it fires
31
+ * precisely in the window where the rival has left the in-memory table (cleared at its
32
+ * pend-consensus) but not yet storage (cleared at its commit or cancel), so no `messageHash`
33
+ * exists to name.
34
+ *
35
+ * `heldBy` is therefore an action id, a different id space from `conflictWith`. Packing one into
36
+ * the other would put two id spaces in a single unlabelled signed field, which is why this is its
37
+ * own variant rather than a reused one. Where several rivals hold the blocks, `heldBy` names the
38
+ * one the refusal returned on.
39
+ */
40
+ | { type: 'held'; signature: string; heldBy: string };
22
41
 
23
42
  /**
24
43
  * The exact bytes a vote signature covers: `<hash>:<type>[:<extra>]`, where `extra` is the variant's
25
- * own payload — a reject's `rejectReason`, a conflict's `conflictWith`, nothing for an approve.
26
- * Folding the extra in is what makes it integrity-protected in transit rather than free-floating
27
- * prose.
44
+ * own payload — a reject's `rejectReason`, a conflict's `conflictWith`, a held's `heldBy`, nothing
45
+ * for an approve. Folding the extra in is what makes it integrity-protected in transit rather than
46
+ * free-floating prose. Each variant's extra is a single string, so the preimage needs no encoding
47
+ * scheme; a variant that ever needs two fields must define one rather than concatenating here.
28
48
  *
29
49
  * Producers and verifiers must both build the preimage here. It lives beside {@link Signature}
30
50
  * rather than in either consumer because a second copy that forgets a variant does not fail loudly:
@@ -42,6 +62,7 @@ export function clusterVoteVerificationPayload(hash: string, signature: Signatur
42
62
  switch (signature.type) {
43
63
  case 'reject': return clusterVoteSigningPayload(hash, 'reject', signature.rejectReason);
44
64
  case 'conflict': return clusterVoteSigningPayload(hash, 'conflict', signature.conflictWith);
65
+ case 'held': return clusterVoteSigningPayload(hash, 'held', signature.heldBy);
45
66
  default: return clusterVoteSigningPayload(hash, signature.type);
46
67
  }
47
68
  }
@@ -241,11 +262,11 @@ export interface ClusterConsensusConfig {
241
262
  * single reset here would otherwise drop the peer and sink super-majority.
242
263
  */
243
264
  promiseImmediateRetries?: number;
244
- /** Read-repair behavior: 'off' (only fetch on missing — legacy), 'lazy' (fetch when local age > window), 'paranoid' (always verify against cluster on read, missing blocks included). Default 'lazy'. In 'off' and 'lazy', a missing block whose cohort is this node alone is re-consulted at most once per `readRepairWindowMs`. */
265
+ /** Read-repair behavior: 'off' (only fetch on missing — legacy), 'lazy' (fetch when local age > window), 'paranoid' (always verify against cluster on read). Default 'lazy'. In every mode a block missing locally consults its cohort on every read. */
245
266
  readRepairMode?: 'off' | 'lazy' | 'paranoid';
246
- /** For 'lazy' mode: read-repair triggers when (now - localEntry.lastSeenCommitMs) > this. In 'lazy' and 'off' it is also how long a settled absence is remembered. Default 10000. */
267
+ /** For 'lazy' mode: read-repair triggers when (now - localEntry.lastSeenCommitMs) > this. Default 10000. */
247
268
  readRepairWindowMs?: number;
248
- /** Per-read probability of a cohort check in 'lazy' mode even within the window — of a held block or a settled absence (0..1). Default 0 (no random check). */
269
+ /** Per-read probability of triggering read-repair in 'lazy' mode even within the window (0..1). Default 0 (no random check). */
249
270
  readRepairSampleRate?: number;
250
271
  /**
251
272
  * When FRET has no confident network-size estimate, allow an undersized cluster