@serfab/cadre-core 0.9.0 → 0.11.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 (193) hide show
  1. package/README.md +255 -253
  2. package/dist/bootstrap-peer-store-file.d.ts +13 -0
  3. package/dist/bootstrap-peer-store-file.js +42 -0
  4. package/dist/bootstrap-peer-store-file.js.map +1 -0
  5. package/dist/bootstrap-peer-store.d.ts +73 -0
  6. package/dist/bootstrap-peer-store.js +128 -0
  7. package/dist/bootstrap-peer-store.js.map +1 -0
  8. package/dist/cadre-node.d.ts +1121 -81
  9. package/dist/cadre-node.js +2276 -262
  10. package/dist/cadre-node.js.map +1 -1
  11. package/dist/control-authorization.d.ts +93 -0
  12. package/dist/control-authorization.js +57 -0
  13. package/dist/control-authorization.js.map +1 -0
  14. package/dist/control-cohort.d.ts +26 -0
  15. package/dist/control-cohort.js +26 -0
  16. package/dist/control-cohort.js.map +1 -1
  17. package/dist/control-database.d.ts +959 -54
  18. package/dist/control-database.js +1421 -148
  19. package/dist/control-database.js.map +1 -1
  20. package/dist/control-formation-recorder.d.ts +90 -10
  21. package/dist/control-formation-recorder.js +130 -14
  22. package/dist/control-formation-recorder.js.map +1 -1
  23. package/dist/control-schema.d.ts +1 -1
  24. package/dist/control-schema.js +651 -72
  25. package/dist/control-schema.js.map +1 -1
  26. package/dist/control-stream.d.ts +38 -4
  27. package/dist/control-stream.js +70 -4
  28. package/dist/control-stream.js.map +1 -1
  29. package/dist/control-write-retry.d.ts +161 -0
  30. package/dist/control-write-retry.js +412 -0
  31. package/dist/control-write-retry.js.map +1 -0
  32. package/dist/delegate-admission.d.ts +134 -0
  33. package/dist/delegate-admission.js +244 -0
  34. package/dist/delegate-admission.js.map +1 -0
  35. package/dist/device-token.d.ts +11 -11
  36. package/dist/device-token.js +14 -13
  37. package/dist/device-token.js.map +1 -1
  38. package/dist/ed25519-key.d.ts +26 -0
  39. package/dist/ed25519-key.js +56 -1
  40. package/dist/ed25519-key.js.map +1 -1
  41. package/dist/file-durable-slot.d.ts +20 -0
  42. package/dist/file-durable-slot.js +53 -0
  43. package/dist/file-durable-slot.js.map +1 -0
  44. package/dist/formation-approval.d.ts +157 -0
  45. package/dist/formation-approval.js +375 -0
  46. package/dist/formation-approval.js.map +1 -0
  47. package/dist/fs-atomic.d.ts +38 -0
  48. package/dist/fs-atomic.js +97 -0
  49. package/dist/fs-atomic.js.map +1 -0
  50. package/dist/identity-key.d.ts +49 -0
  51. package/dist/identity-key.js +81 -0
  52. package/dist/identity-key.js.map +1 -0
  53. package/dist/index.d.ts +17 -7
  54. package/dist/index.js +40 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/key-store-file.d.ts +2 -24
  57. package/dist/key-store-file.js +10 -77
  58. package/dist/key-store-file.js.map +1 -1
  59. package/dist/membership-connection-gater.d.ts +146 -0
  60. package/dist/membership-connection-gater.js +180 -0
  61. package/dist/membership-connection-gater.js.map +1 -0
  62. package/dist/node-local-snapshot.d.ts +109 -0
  63. package/dist/node-local-snapshot.js +182 -0
  64. package/dist/node-local-snapshot.js.map +1 -0
  65. package/dist/peer-addr-book.d.ts +92 -0
  66. package/dist/peer-addr-book.js +220 -0
  67. package/dist/peer-addr-book.js.map +1 -0
  68. package/dist/peer-authorization.d.ts +135 -18
  69. package/dist/peer-authorization.js +152 -21
  70. package/dist/peer-authorization.js.map +1 -1
  71. package/dist/peer-record.d.ts +21 -8
  72. package/dist/peer-record.js +26 -10
  73. package/dist/peer-record.js.map +1 -1
  74. package/dist/relay-addrs.d.ts +45 -0
  75. package/dist/relay-addrs.js +103 -0
  76. package/dist/relay-addrs.js.map +1 -0
  77. package/dist/relay-reservation.d.ts +266 -0
  78. package/dist/relay-reservation.js +613 -0
  79. package/dist/relay-reservation.js.map +1 -0
  80. package/dist/seed-bootstrap.d.ts +228 -56
  81. package/dist/seed-bootstrap.js +340 -198
  82. package/dist/seed-bootstrap.js.map +1 -1
  83. package/dist/seed-trust-policy.d.ts +47 -21
  84. package/dist/seed-trust-policy.js +24 -15
  85. package/dist/seed-trust-policy.js.map +1 -1
  86. package/dist/strand-addr-protocol.d.ts +42 -13
  87. package/dist/strand-addr-protocol.js +58 -52
  88. package/dist/strand-addr-protocol.js.map +1 -1
  89. package/dist/strand-backfill.d.ts +109 -0
  90. package/dist/strand-backfill.js +279 -0
  91. package/dist/strand-backfill.js.map +1 -0
  92. package/dist/strand-cohort.d.ts +4 -37
  93. package/dist/strand-cohort.js +4 -15
  94. package/dist/strand-cohort.js.map +1 -1
  95. package/dist/strand-database.d.ts +11 -16
  96. package/dist/strand-database.js +19 -7
  97. package/dist/strand-database.js.map +1 -1
  98. package/dist/strand-formation-manager.d.ts +36 -7
  99. package/dist/strand-formation-manager.js +115 -15
  100. package/dist/strand-formation-manager.js.map +1 -1
  101. package/dist/strand-formation-protocol.d.ts +103 -4
  102. package/dist/strand-formation-protocol.js +232 -4
  103. package/dist/strand-formation-protocol.js.map +1 -1
  104. package/dist/strand-instance-manager.d.ts +88 -19
  105. package/dist/strand-instance-manager.js +178 -34
  106. package/dist/strand-instance-manager.js.map +1 -1
  107. package/dist/strand-member-registry.d.ts +5 -5
  108. package/dist/strand-member-registry.js +18 -10
  109. package/dist/strand-member-registry.js.map +1 -1
  110. package/dist/strand-membership-writer.d.ts +484 -88
  111. package/dist/strand-membership-writer.js +751 -128
  112. package/dist/strand-membership-writer.js.map +1 -1
  113. package/dist/strand-solicitation.d.ts +99 -33
  114. package/dist/strand-solicitation.js +100 -52
  115. package/dist/strand-solicitation.js.map +1 -1
  116. package/dist/strand-transport-key.d.ts +40 -0
  117. package/dist/strand-transport-key.js +56 -0
  118. package/dist/strand-transport-key.js.map +1 -0
  119. package/dist/strand-wake-protocol.d.ts +9 -7
  120. package/dist/strand-wake-protocol.js +22 -46
  121. package/dist/strand-wake-protocol.js.map +1 -1
  122. package/dist/strand-watcher.d.ts +17 -2
  123. package/dist/strand-watcher.js +47 -3
  124. package/dist/strand-watcher.js.map +1 -1
  125. package/dist/trusted-owner-store-file.d.ts +12 -0
  126. package/dist/trusted-owner-store-file.js +39 -0
  127. package/dist/trusted-owner-store-file.js.map +1 -0
  128. package/dist/trusted-owner-store.d.ts +64 -0
  129. package/dist/trusted-owner-store.js +126 -0
  130. package/dist/trusted-owner-store.js.map +1 -0
  131. package/dist/types.d.ts +307 -44
  132. package/dist/types.js +13 -0
  133. package/dist/types.js.map +1 -1
  134. package/package.json +20 -8
  135. package/src/arachnode-stub.ts +159 -159
  136. package/src/bootstrap-peer-store-file.ts +44 -0
  137. package/src/bootstrap-peer-store.ts +172 -0
  138. package/src/cadre-node.ts +5158 -2981
  139. package/src/canonical-json.ts +30 -30
  140. package/src/control-authorization.ts +114 -0
  141. package/src/control-cohort.ts +130 -103
  142. package/src/control-database.ts +2406 -948
  143. package/src/control-formation-recorder.ts +305 -151
  144. package/src/control-schema.ts +651 -72
  145. package/src/control-stream.ts +205 -128
  146. package/src/control-write-retry.ts +483 -0
  147. package/src/delegate-admission.ts +302 -0
  148. package/src/device-token.ts +94 -89
  149. package/src/diagnostics/connection-path.ts +277 -277
  150. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  151. package/src/ed25519-key.ts +66 -1
  152. package/src/enrollment.ts +199 -199
  153. package/src/file-durable-slot.ts +61 -0
  154. package/src/formation-approval.ts +604 -0
  155. package/src/fs-atomic.ts +107 -0
  156. package/src/hibernation-manager.ts +437 -437
  157. package/src/identity-key.ts +109 -0
  158. package/src/index.ts +137 -5
  159. package/src/key-store-file.ts +132 -203
  160. package/src/key-store.ts +99 -99
  161. package/src/membership-connection-gater.ts +204 -0
  162. package/src/node-local-snapshot.ts +260 -0
  163. package/src/peer-addr-book.ts +250 -0
  164. package/src/peer-authorization.ts +259 -81
  165. package/src/peer-record.ts +164 -146
  166. package/src/push-credentials.ts +84 -84
  167. package/src/push-node.ts +64 -64
  168. package/src/push-notifier-apns.ts +247 -247
  169. package/src/push-notifier-fcm.ts +220 -220
  170. package/src/push-notifier-shared.ts +28 -28
  171. package/src/push-notifier.ts +52 -52
  172. package/src/relay-addrs.ts +111 -0
  173. package/src/relay-reservation.ts +823 -0
  174. package/src/seed-bootstrap.ts +409 -209
  175. package/src/seed-trust-policy.ts +140 -107
  176. package/src/strand-addr-protocol.ts +441 -410
  177. package/src/strand-backfill.ts +366 -0
  178. package/src/strand-cohort.ts +38 -77
  179. package/src/strand-database.ts +202 -204
  180. package/src/strand-formation-manager.ts +491 -368
  181. package/src/strand-formation-protocol.ts +692 -391
  182. package/src/strand-instance-manager.ts +201 -46
  183. package/src/strand-member-key.ts +39 -39
  184. package/src/strand-member-registry.ts +182 -177
  185. package/src/strand-membership-writer.ts +938 -146
  186. package/src/strand-solicitation.ts +472 -407
  187. package/src/strand-transport-key.ts +58 -0
  188. package/src/strand-wake-payload.ts +32 -32
  189. package/src/strand-wake-protocol.ts +314 -331
  190. package/src/strand-watcher.ts +314 -251
  191. package/src/trusted-owner-store-file.ts +41 -0
  192. package/src/trusted-owner-store.ts +171 -0
  193. package/src/types.ts +1309 -1032
package/dist/types.d.ts CHANGED
@@ -1,16 +1,28 @@
1
1
  import type { ConnectionGater, Libp2p, PeerId, PrivateKey } from '@libp2p/interface';
2
2
  import type { IRawStorage, Libp2pTransports } from '@optimystic/db-p2p';
3
- import type { IRepo } from '@optimystic/db-core';
3
+ import type { IPeerNetwork, IRepo } from '@optimystic/db-core';
4
+ import type { StrandBackfillConfig } from './strand-backfill.js';
4
5
  import type { StrandDatabase } from './strand-database.js';
5
6
  import type { SeedTrustPolicy } from './seed-trust-policy.js';
6
7
  import type { KeyStore, KeyId } from './key-store.js';
8
+ import type { TrustedOwnerStore, TrustSource } from './trusted-owner-store.js';
9
+ import type { BootstrapPeerStore } from './bootstrap-peer-store.js';
7
10
  import type { PushNotifier } from './push-notifier.js';
11
+ import type { RevocableTable } from './control-authorization.js';
8
12
  /**
9
13
  * Extended Libp2p node with the coordinatedRepo attached by db-p2p's
10
14
  * createLibp2pNode after node creation (not surfaced on the base Libp2p type).
11
15
  */
12
16
  export interface Libp2pNodeWithRepo extends Libp2p {
13
17
  coordinatedRepo: IRepo;
18
+ /**
19
+ * The node's key-addressed peer network, attached by db-p2p's factory alongside
20
+ * `coordinatedRepo` (`libp2p-node-base.ts`). Optional deliberately: the base
21
+ * factory always assigns it, but it is not part of the upstream node type, so
22
+ * declaring it required would be a claim this repo cannot enforce. The strand
23
+ * backfill (`strand-backfill.ts`) logs once and stays inert when it is absent.
24
+ */
25
+ keyNetwork?: IPeerNetwork;
14
26
  }
15
27
  /**
16
28
  * Node profile determines storage participation
@@ -70,8 +82,28 @@ export interface HibernationTimeouts {
70
82
  */
71
83
  export declare const HIBERNATION_TIMEOUTS: Record<LatencyHint, HibernationTimeouts>;
72
84
  /**
73
- * Storage provider type - either an IRawStorage instance or a factory function.
85
+ * Storage provider - either an `IRawStorage` instance or a factory function.
74
86
  * Factory functions are useful for creating strand-specific storage instances.
87
+ *
88
+ * **Called once per scope per runtime lifetime.** The scopes are the literal string
89
+ * `'control'` (once per `CadreNode.start()`) and each strand id (once per
90
+ * `startStrand`). Hibernation — `quiesceStrand` then `resumeStrand` — reuses the
91
+ * store already resolved for that strand and does NOT re-enter this callback.
92
+ *
93
+ * It IS re-entered for a scope after that scope's runtime has stopped
94
+ * (`stopStrand`, or a `stop()` then `start()` cycle on one `CadreNode`), so it must
95
+ * be able to hand back a store over the same durable backend a second time. A
96
+ * factory may mint a fresh object per call; it must not *need* to.
97
+ *
98
+ * cadre-core disposes only its own cache wrapper — it never closes the store you
99
+ * returned. Closing the underlying handle stays the embedder's job.
100
+ *
101
+ * **Prefer the factory form for any persistent backend.** One instance handed to
102
+ * every scope also shares ONE cache wrapper (`wrapStorageWithCache` memoizes per
103
+ * inner instance), and no scope solely owns it — so the first scope to stop retires
104
+ * the wrapper the still-running scopes are reading through. See
105
+ * `tickets/backlog/debt-storage-cache-wrap-unrefcounted.md`; an in-memory store is
106
+ * unaffected, since it is never wrapped.
75
107
  */
76
108
  export type RawStorageProvider = IRawStorage | ((strandId: string) => IRawStorage);
77
109
  /**
@@ -80,6 +112,7 @@ export type RawStorageProvider = IRawStorage | ((strandId: string) => IRawStorag
80
112
  export interface StorageConfig {
81
113
  /**
82
114
  * Storage provider - either an IRawStorage instance or a factory function.
115
+ * See {@link RawStorageProvider} for how often cadre-core calls it.
83
116
  *
84
117
  * For Node.js environments, use FileRawStorage from @optimystic/db-p2p-storage-fs:
85
118
  * ```typescript
@@ -89,8 +122,9 @@ export interface StorageConfig {
89
122
  *
90
123
  * For React Native, use the appropriate storage from @optimystic/db-p2p-storage-rn:
91
124
  * ```typescript
92
- * import { RNRawStorage } from '@optimystic/db-p2p-storage-rn';
93
- * storage: { provider: (strandId) => new RNRawStorage(strandId) }
125
+ * import { LevelDBRawStorage } from '@optimystic/db-p2p-storage-rn';
126
+ * // `db` is an open LevelDB handle (see `openOptimysticRNDb` over `rn-leveldb`)
127
+ * storage: { provider: (strandId) => new LevelDBRawStorage(openDb(`sereus-${strandId}`)) }
94
128
  * ```
95
129
  *
96
130
  * For in-memory storage (testing):
@@ -107,7 +141,47 @@ export interface StorageConfig {
107
141
  */
108
142
  export interface NetworkConfig {
109
143
  listenAddrs?: string[];
144
+ /**
145
+ * Addresses to advertise to peers instead of `listenAddrs` — for a node behind
146
+ * NAT or a reverse proxy that is reachable at a different address than it binds
147
+ * (e.g. `mynode.example.com:4001` in front of a `0.0.0.0:4001` listener).
148
+ *
149
+ * Accepted (settable in `cadre.yaml`, via `CADRE_ANNOUNCE_ADDRS`, and through the
150
+ * Docker entrypoint) but **not yet applied**: libp2p only takes announce addresses
151
+ * at construction (`addresses.announce` / `addresses.appendAnnounce`), and
152
+ * `@optimystic/db-p2p`'s `NodeOptions` has no field for either — there is nothing
153
+ * in this repo to wire this into. `CadreNode.start()` warns when this is set,
154
+ * rather than pretending it works. Unblocked by the `announce-addrs-option`
155
+ * request filed against `@optimystic/db-p2p`; wiring lands here once this repo's
156
+ * dependency range moves to a version carrying it.
157
+ *
158
+ * Use {@link relayAddrs} for reachability behind NAT today (a reserved relay slot
159
+ * gives the node a real dialable circuit address), or `inviteAddressResolver` to
160
+ * substitute a reachable address into invite payloads specifically — neither
161
+ * changes what this node advertises on the wire, but both cover the operator need
162
+ * this field cannot yet.
163
+ */
110
164
  announceAddrs?: string[];
165
+ /**
166
+ * Circuit-relay servers this node reserves a slot on, so peers can reach it
167
+ * from behind NAT. Each entry is the relay's DIRECT dial multiaddr ending in
168
+ * its peerId — `/dns4/relay.example.com/tcp/4001/p2p/12D3KooW…` — with no
169
+ * `/p2p-circuit` suffix (one is appended for you; an entry that already has
170
+ * one is passed through unchanged).
171
+ *
172
+ * This is sugar for a circuit entry in {@link listenAddrs}: `relay-addrs.ts`
173
+ * resolves the two into one listen list, and listening on a relay's circuit
174
+ * addr is what makes libp2p dial it and hold the reservation. A relay named
175
+ * here therefore also becomes a delegate-announce target, so this node's
176
+ * strand nodes may reserve on it too (see `delegate-admission.ts`).
177
+ *
178
+ * Setting this gives the node a listener even when `listenAddrs` is `[]` —
179
+ * that is the point of naming a relay, but note that React Native hosts
180
+ * (`reference-app-rn`'s `cadre-phone.ts`) deliberately do NOT listen, and
181
+ * must not acquire a listener by accident.
182
+ *
183
+ * A malformed entry throws at node start rather than being silently dropped.
184
+ */
111
185
  relayAddrs?: string[];
112
186
  /**
113
187
  * Enable circuit relay server - allows this node to relay connections for other peers.
@@ -147,15 +221,22 @@ export interface NetworkConfig {
147
221
  * Playwright e2e, RN simulators) supply a permissive gater here — e.g.
148
222
  * `{ denyDialMultiaddr: () => false }`. See `@optimystic/db-p2p`'s
149
223
  * `libp2p-node-base` for the underlying option.
224
+ *
225
+ * On the CONTROL node this gater is composed with the built-in membership
226
+ * admission gate (`membership-connection-gater.ts`): every hook supplied here
227
+ * is honored unchanged, and on inbound encrypted connections a deny from
228
+ * either this gater or the membership policy denies. Strand cohort nodes
229
+ * receive this gater as-is (their peers are legitimately cross-party).
150
230
  */
151
231
  connectionGater?: ConnectionGater;
152
232
  /**
153
233
  * Tuning for the proactive control-cohort dial routine
154
234
  * ({@link CadreNode.reconcileControlCohort}), which keeps a party's control
155
235
  * nodes connected so the `CadreControl` collections form a replicating cohort.
156
- * Both fields are optional; omit for the defaults
236
+ * Every field is optional; omit for the defaults
157
237
  * ({@link DEFAULT_CONTROL_COHORT_TARGET_DEGREE} /
158
- * {@link DEFAULT_CONTROL_COHORT_RECONCILE_MS}).
238
+ * {@link DEFAULT_CONTROL_COHORT_RECONCILE_MS} /
239
+ * {@link DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS} / `STRAND_PEER_ADDR_REFRESH_MS`).
159
240
  */
160
241
  controlCohort?: {
161
242
  /**
@@ -169,6 +250,20 @@ export interface NetworkConfig {
169
250
  * {@link DEFAULT_CONTROL_COHORT_RECONCILE_MS}.
170
251
  */
171
252
  reconcileMs?: number;
253
+ /**
254
+ * Budget for ONE sibling's proactive dial, in ms. Bounds a pass at
255
+ * (dialed siblings) × this, instead of leaving it to each address's own
256
+ * libp2p attempt timeout multiplied by address fan-out and relay hops.
257
+ * Defaults to {@link DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS}.
258
+ */
259
+ dialTimeoutMs?: number;
260
+ /**
261
+ * How often each running strand re-resolves its siblings' strand-network
262
+ * addresses into its own libp2p address book — a step of the reconcile pass,
263
+ * on its own much longer throttle. Defaults to `STRAND_PEER_ADDR_REFRESH_MS`
264
+ * (10 min); must stay well under the peerStore's one-hour address expiry.
265
+ */
266
+ strandAddrRefreshMs?: number;
172
267
  };
173
268
  }
174
269
  /**
@@ -201,6 +296,19 @@ export interface ControlNetworkConfig {
201
296
  /** Optional path to the control schema file (defaults to bundled schema) */
202
297
  schemaPath?: string;
203
298
  }
299
+ /**
300
+ * Replication-breadth constants, both networks' cluster policies, and the strand
301
+ * resolver, re-exported so cadre embedders, the SQL plugin and the integration
302
+ * harness share one definition. Defined in `@serfab/quereus-plugin-sereus`
303
+ * because that package also creates libp2p nodes and cannot depend on this one.
304
+ * The control network's breadth is fixed ({@link CONTROL_REPLICATION_BREADTH},
305
+ * not configurable) and so is its consensus policy ({@link CONTROL_CLUSTER_POLICY}
306
+ * — notably the super-majority threshold, which it leaves at Optimystic's default
307
+ * by omission); the strand breadth defaults to
308
+ * {@link CadreNodeConfig.strandClusterSize} while its policy is the fixed
309
+ * {@link STRAND_CLUSTER_POLICY}.
310
+ */
311
+ export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize } from '@serfab/quereus-plugin-sereus';
204
312
  /**
205
313
  * Main configuration for a CadreNode
206
314
  */
@@ -237,6 +345,41 @@ export interface CadreNodeConfig {
237
345
  storage?: StorageConfig;
238
346
  /** Network configuration */
239
347
  network?: NetworkConfig;
348
+ /**
349
+ * Number of nodes Optimystic is told a **strand** network's replication cluster
350
+ * should have, for every strand this node starts. The control network is not
351
+ * configurable — it always replicates to {@link CONTROL_REPLICATION_BREADTH}
352
+ * nodes, which is above any party's node count, because every member reads the
353
+ * whole control database and a member that misses a write may never learn the
354
+ * fact (see that constant for the full reasoning).
355
+ *
356
+ * Every node on the same strand should use the same value: the number bounds the
357
+ * cohort a member independently derives, and Optimystic's cluster-membership gate
358
+ * can reject a coordinator's smaller declared set as a downsize against a larger
359
+ * derived view.
360
+ *
361
+ * Frozen when the strand's libp2p node is created; a change takes effect on
362
+ * restart, not when cadre membership grows. Defaults to
363
+ * {@link DEFAULT_STRAND_CLUSTER_SIZE} (4 — the smallest breadth whose 0.75
364
+ * super-majority still commits with one holder offline); anything below
365
+ * {@link MIN_CLUSTER_SIZE} is rejected before a node is created. The cost of a
366
+ * small value is replication breadth and reliance on read repair, not commit
367
+ * correctness — but at 2 that read repair cannot converge, because a lone
368
+ * corroborator's stale answer is accepted as the cluster's truth.
369
+ */
370
+ strandClusterSize?: number;
371
+ /**
372
+ * Tuning for the strand peer-join block catch-up (see `strand-backfill.ts`):
373
+ * when a strand's libp2p node connects to a peer this runtime has not yet
374
+ * caught up, every block in the strand's own raw store is pushed to that peer,
375
+ * so a machine that joined the strand after blocks were committed still ends
376
+ * up physically holding them. Applies to every strand this node starts;
377
+ * strand-only — the control network has its own row-level re-issue queue
378
+ * (`drainPendingControlReplication`). Omit for the defaults
379
+ * (`DEFAULT_STRAND_BACKFILL`); `{ enabled: false }` restores the
380
+ * no-backfill behaviour.
381
+ */
382
+ strandBackfill?: StrandBackfillConfig;
240
383
  /** Hibernation configuration */
241
384
  hibernation?: HibernationConfig;
242
385
  /** Polling interval for strand watcher in ms (default: 5000) */
@@ -253,13 +396,73 @@ export interface CadreNodeConfig {
253
396
  * into every SeedBootstrapService this node constructs (owner, receive-only
254
397
  * listener, and the temp service used by applySeed when no service exists), and
255
398
  * used as the service-level default the libp2p seed-protocol handler relies on
256
- * (that path has no per-call override seam). Defaults to dbAnchoredTrustPolicy()
257
- * inside SeedBootstrapService when unset — a cold-start node then rejects every
258
- * seed. A per-call `applySeed(seed, { trustPolicy })` override still wins over
259
- * this default for callers that hold out-of-band material (e.g. a pinned key
260
- * from a CadreInvite).
399
+ * (that path has no per-call override seam). Defaults to anchoredTrustPolicy()
400
+ * inside SeedBootstrapService when unset — a node whose node-local trusted-owner
401
+ * anchor was never seeded then rejects every seed. A per-call
402
+ * `applySeed(seed, { trustPolicy })` override still wins over this default for
403
+ * callers that hold out-of-band material (e.g. a pinned key from a CadreInvite).
261
404
  */
262
405
  seedTrustPolicy?: SeedTrustPolicy;
406
+ /**
407
+ * Node-local trusted-owner anchor (see `trusted-owner-store.ts`): the
408
+ * NON-replicated, per-party record of owner keys established out of band —
409
+ * the anchor membership/seed trust can rest on, since the replicated
410
+ * `OwnerKey` table can be polluted by a stranger's self-genesis. Absent ⇒ an
411
+ * in-memory store is created at start() (ephemeral: anchored trust does not
412
+ * survive the process).
413
+ */
414
+ trustedOwners?: {
415
+ /**
416
+ * Injected store instance — e.g. a `FileTrustedOwnerStore` from the
417
+ * Node-only subpath `@serfab/cadre-core/trusted-owner-store-file`,
418
+ * persisted in the node's state directory (same injection/isolation pattern
419
+ * as {@link keyStore}). Its `partyId` must match `controlNetwork.partyId`;
420
+ * start() fails closed on a mismatch.
421
+ */
422
+ store?: TrustedOwnerStore;
423
+ /**
424
+ * Owner keys (base64url ed25519) established out of band and seeded into
425
+ * the store during start(): operator pins (e.g. cadre-cli
426
+ * `--pin-owner-key` / `CADRE_OWNER_KEYS`) or a `CadreInvite.ownerKeys`
427
+ * already known at config time. Seeding is idempotent across restarts.
428
+ */
429
+ pinnedKeys?: string[];
430
+ /**
431
+ * Provenance recorded for {@link pinnedKeys}. Default: 'operator'.
432
+ * ('genesis' is reserved for the node's own founding key, seeded
433
+ * internally by `initializeSeedBootstrap`.)
434
+ */
435
+ pinnedSource?: Exclude<TrustSource, 'genesis'>;
436
+ };
437
+ /**
438
+ * Node-local cold-start bootstrap-peer store (see `bootstrap-peer-store.ts`):
439
+ * the owner addresses an applied seed nominated, kept so
440
+ * `reconcileControlCohort`'s cold-start branch can keep retrying a node that
441
+ * was seeded but never managed to connect. Sibling of {@link trustedOwners} —
442
+ * same NON-replicated, per-party, injected-backend shape — but nothing here is
443
+ * trust-bearing: these are dial hints only, and every address is re-bound to
444
+ * its peer id before the dial. Absent ⇒ an in-memory store is created at
445
+ * start() (ephemeral: the retry set does not survive the process, and such a
446
+ * node is stranded permanently if it restarts before connecting).
447
+ *
448
+ * The Node CLI, the browser, and React Native all inject a durable backend
449
+ * today; only NativeScript stays ephemeral, tracked by the
450
+ * `ns-durable-node-local-stores` ticket (which covers the same gap for
451
+ * {@link trustedOwners}). A new platform needs no new store class: supply a
452
+ * `DurableSlot` for the platform's storage and inject
453
+ * `PersistentBootstrapPeerStore.open(slot, partyId)` /
454
+ * `PersistentTrustedOwnerStore.open(slot, partyId)`.
455
+ */
456
+ bootstrapPeers?: {
457
+ /**
458
+ * Injected store instance — e.g. a `FileBootstrapPeerStore` from the
459
+ * Node-only subpath `@serfab/cadre-core/bootstrap-peer-store-file`, persisted
460
+ * in the node's state directory (same injection/isolation pattern as
461
+ * {@link keyStore} / {@link trustedOwners}). Its `partyId` must match
462
+ * `controlNetwork.partyId`; start() fails closed on a mismatch.
463
+ */
464
+ store?: BootstrapPeerStore;
465
+ };
263
466
  /**
264
467
  * Platform push-delivery for suspended mobile peers. When present, the node's
265
468
  * server fan-out can deliver strand-wake data messages over the platform push
@@ -375,20 +578,6 @@ export interface SAppConfig {
375
578
  /** Latency hint for hibernation behavior (optional, defaults to config) */
376
579
  latencyHint?: LatencyHint;
377
580
  }
378
- /**
379
- * Lifecycle mode for a strand.
380
- *
381
- * - `bootstrap`: newly created locally; no remote peers exist for this strand yet.
382
- * Schema apply and data operations route through a local (non-network) transactor
383
- * so a solo node can fully initialize without any peer round trips.
384
- * - `networked`: strand has (or is expected to have) remote peers. Operations route
385
- * through the network transactor.
386
- *
387
- * Transition `bootstrap -> networked` happens at first remote-peer enrollment for
388
- * the strand; because the transactor is fixed at plugin registration time, the
389
- * transition requires stopping and restarting the strand.
390
- */
391
- export type StrandMode = 'bootstrap' | 'networked';
392
581
  /**
393
582
  * Full strand configuration when adding a strand via the API
394
583
  */
@@ -397,13 +586,6 @@ export interface StrandConfig {
397
586
  strandRow: StrandRow;
398
587
  /** sApp configuration provided by the hosting application */
399
588
  sAppConfig: SAppConfig;
400
- /**
401
- * Lifecycle mode for this strand instance. When omitted, CadreNode infers the
402
- * mode from cohort membership (`bootstrap` for a solo/first node with no other
403
- * `CadrePeer` rows, `networked` once the cohort has other members). An explicit
404
- * value always wins.
405
- */
406
- mode?: StrandMode;
407
589
  /**
408
590
  * Whether THIS node is the strand's founder — the party that provisioned and
409
591
  * published the strand (the responder in formation, the creator in host/solo
@@ -473,15 +655,6 @@ export interface FormStrandResult {
473
655
  */
474
656
  memberPrivateKey?: string;
475
657
  }
476
- /**
477
- * Result of validating a strand formation request
478
- */
479
- export interface ValidateFormationResult {
480
- /** Public key for validating this formation */
481
- validationKey: string;
482
- /** Signature over the formation approval */
483
- validationSignature: string;
484
- }
485
658
  /**
486
659
  * Disclosure object provided during strand formation.
487
660
  * Contains identity and context information from the initiator.
@@ -589,13 +762,57 @@ export interface PeerAddressRecord {
589
762
  /** ed25519 self-signature over the signed payload, base64url. */
590
763
  sig: string;
591
764
  }
765
+ /**
766
+ * One `CadreControl.CadrePeer` row as read by `ControlDatabase.queryCadrePeers`:
767
+ * the addressing columns plus the persisted membership voucher.
768
+ *
769
+ * The voucher triple (`stampId`, `vouchOwner`, `vouchSig`) is what
770
+ * {@link CadreNode.listAuthorizedMembers} re-checks against the node-local
771
+ * trusted-owner anchor — it is null on a row written before the voucher columns
772
+ * existed, and all three must be present for the row to be authorizable. Named
773
+ * (rather than restated inline at each read site) so a future column addition
774
+ * cannot reach the query without the predicate seeing it.
775
+ */
776
+ export interface CadrePeerRow {
777
+ /** libp2p peer ID (base58btc) — the row key. */
778
+ peerId: string;
779
+ /** Comma-joined dialable multiaddrs as stored, or null when unpublished. */
780
+ multiaddr: string | null;
781
+ /** Single-use anti-replay nonce the voucher signature is bound to. */
782
+ stampId: string | null;
783
+ /** ed25519 public key (base64url) of the owner that vouched this row. */
784
+ vouchOwner: string | null;
785
+ /** That owner's signature over `digest('CadreControl.CadrePeer', 'vouch', peerId, stampId)`, base64url. */
786
+ vouchSig: string | null;
787
+ }
788
+ /** The voucher-bearing subset of a {@link CadrePeerRow} — what the authorized-membership predicate reads. */
789
+ export type CadrePeerVoucherFields = Pick<CadrePeerRow, 'peerId' | 'stampId' | 'vouchOwner' | 'vouchSig'>;
790
+ /**
791
+ * One `CadreControl.Revocation` tombstone as read by
792
+ * `ControlDatabase.queryRevocations`: the identity triple plus the `ReissuedAt`
793
+ * counter an owner bumps (`ControlDatabase.reissueRevocations`) to re-write — and
794
+ * therefore re-broadcast — a tombstone that committed while the node was alone.
795
+ */
796
+ export interface RevocationRow {
797
+ /** Which guarded table's stamp was retired. */
798
+ tableName: RevocableTable;
799
+ /** Primary key of the removed row (peer id / key / strand id). */
800
+ rowKey: string;
801
+ /** The retired single-use nonce — the tombstone's identity. */
802
+ stampId: string;
803
+ /** Monotonic re-issue counter; carries no semantics (see the schema comment). */
804
+ reissuedAt: number;
805
+ }
592
806
  /**
593
807
  * Outcome of {@link CadreNode.registerSelf}, surfaced so callers (e.g. the CLI
594
808
  * `--owner` branch) can log what happened:
595
809
  * - `inserted` — the first owner-signed INSERT of this node's `CadrePeer` row.
596
810
  * - `refreshed` — a self-signed UPDATE of an existing row (heartbeat / addr change).
597
- * - `skipped` — nothing written (no self-signing key, or not yet a member with no
598
- * owner service to self-insert).
811
+ * Also reported when a first publish found its row seated by a concurrent
812
+ * `authorizePeer` of this node's own id and fell through to the UPDATE — the write
813
+ * really was an UPDATE, even though the caller's intent was a first publish.
814
+ * - `skipped` — nothing written (no self-signing key, not yet a member with no
815
+ * owner service to self-insert, or the row was removed mid-publish).
599
816
  */
600
817
  export type SelfRegistrationOutcome = 'inserted' | 'refreshed' | 'skipped';
601
818
  /**
@@ -668,6 +885,20 @@ export interface DeviceTokenRecord {
668
885
  /** ed25519 self-signature over the signed payload, base64url. */
669
886
  sig: string;
670
887
  }
888
+ /**
889
+ * A stored `CadreControl.DeviceToken` row: the self-signed
890
+ * {@link DeviceTokenRecord} plus the row's single-use `StampId` nonce.
891
+ *
892
+ * The stamp is deliberately OUTSIDE `DeviceTokenRecord`: the peer's own `Sig`
893
+ * covers only (peerId, platform, token, updatedAt), while the stamp is bound by
894
+ * the OWNER's insert/delete approvals. Readers need it to drop a row whose stamp
895
+ * has been retired into `CadreControl.Revocation` (a token resurrected by an
896
+ * approval replay on a node that had not yet converged on the tombstone).
897
+ */
898
+ export interface DeviceTokenRow extends DeviceTokenRecord {
899
+ /** Single-use authorization nonce; rotates on every (re)insert. */
900
+ stampId: string;
901
+ }
671
902
  /**
672
903
  * Options for {@link CadreNode.resolveDeviceToken}.
673
904
  */
@@ -815,6 +1046,14 @@ export interface WakeAck {
815
1046
  export interface StrandAddrRequest {
816
1047
  /** The strand whose strand-network address the requester wants to seed from. */
817
1048
  strandId: string;
1049
+ /**
1050
+ * The derived transport peerId the requester's own strand-`strandId` node
1051
+ * runs as (see `strand-transport-key.ts`). Present → the responder records a
1052
+ * delegate admission grant for it, so its own connection gate (and thus its
1053
+ * circuit-relay server, when it runs one) admits that peerId; absent →
1054
+ * today's behavior exactly. See `delegate-admission.ts` for the trust model.
1055
+ */
1056
+ delegatePeerId?: string;
818
1057
  }
819
1058
  /**
820
1059
  * Response to a {@link StrandAddrRequest}, carrying the responder's strand-node
@@ -849,6 +1088,27 @@ export interface ApplySeedResult {
849
1088
  peersAdded: number;
850
1089
  /** Error message if not successful */
851
1090
  error?: string;
1091
+ /**
1092
+ * Owner-flagged seed peers this apply attempted to dial. Zero when the seed
1093
+ * carried no owner peer with an address, or when the seed was rejected before
1094
+ * the dial loop ran.
1095
+ */
1096
+ ownerDialsAttempted: number;
1097
+ /**
1098
+ * How many of those dials threw. `ownerDialsAttempted > 0 && ownerDialsFailed
1099
+ * === ownerDialsAttempted` means "seeded but stranded": the seed itself was
1100
+ * accepted (`success: true`) but no owner could be reached, so this node has
1101
+ * no connection to bootstrap its control database from. The node retries those
1102
+ * addresses on every control-cohort reconcile pass (see
1103
+ * `CadreNode.dialColdStartBootstrap`), so this is a signal, not a fatal error.
1104
+ *
1105
+ * Zero failures is NOT proof of a live connection: the receiving node's
1106
+ * membership gate denies AFTER the dialer's upgrade completes (see
1107
+ * `createMembershipConnectionGater`), so a dial can resolve and then be torn
1108
+ * down. Treat a non-zero value as certain failure and zero as "no failure
1109
+ * observed".
1110
+ */
1111
+ ownerDialsFailed: number;
852
1112
  }
853
1113
  /**
854
1114
  * Node network topology type for seed helper scenarios.
@@ -867,7 +1127,10 @@ export interface CadreInvite {
867
1127
  * Owner ed25519 public keys (base64url) of the cadre, carried out-of-band
868
1128
  * so a cold-start invitee can pin the trusted owner set before applying
869
1129
  * any seed (the seed itself cannot vouch for its own signer). Populated by
870
- * `createInvite` from the issuer's `OwnerKey` table.
1130
+ * `createInvite` from the issuer's OWN node-local trusted-owner anchor —
1131
+ * not its replicated `OwnerKey` table, because the invitee anchors whatever
1132
+ * arrives here and a stranger's genesis-inserted key must not ride an
1133
+ * otherwise-legitimate invite into a fresh node's anchor.
871
1134
  */
872
1135
  ownerKeys?: string[];
873
1136
  /** Optional invite token for validation */
package/dist/types.js CHANGED
@@ -40,4 +40,17 @@ export const HIBERNATION_TIMEOUTS = {
40
40
  * See {@link HibernationConfig.checkInWindowMs}.
41
41
  */
42
42
  export const DEFAULT_CHECKIN_WINDOW_MS = 15 * 1000;
43
+ /**
44
+ * Replication-breadth constants, both networks' cluster policies, and the strand
45
+ * resolver, re-exported so cadre embedders, the SQL plugin and the integration
46
+ * harness share one definition. Defined in `@serfab/quereus-plugin-sereus`
47
+ * because that package also creates libp2p nodes and cannot depend on this one.
48
+ * The control network's breadth is fixed ({@link CONTROL_REPLICATION_BREADTH},
49
+ * not configurable) and so is its consensus policy ({@link CONTROL_CLUSTER_POLICY}
50
+ * — notably the super-majority threshold, which it leaves at Optimystic's default
51
+ * by omission); the strand breadth defaults to
52
+ * {@link CadreNodeConfig.strandClusterSize} while its policy is the fixed
53
+ * {@link STRAND_CLUSTER_POLICY}.
54
+ */
55
+ export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize } from '@serfab/quereus-plugin-sereus';
43
56
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA+DA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,QAAQ,EAAE;QACR,WAAW,EAAE,QAAQ,EAAS,aAAa;QAC3C,gBAAgB,EAAE,QAAQ,EAAI,kBAAkB;QAChD,eAAe,EAAE,QAAQ,EAAK,MAAM;QACpC,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,QAAQ,CAAE,MAAM;KACrC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,YAAY;QAC1C,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,wBAAwB;QAC1D,eAAe,EAAE,EAAE,GAAG,IAAI,EAAI,mBAAmB;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KACnD;IACD,UAAU,EAAE;QACV,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,WAAW;QACzC,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAG,uBAAuB;QACzD,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,kBAAkB;QACpD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;KACxD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,EAAQ,aAAa;QAC3C,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAG,wBAAwB;QACtD,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAG,eAAe;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KAC5D;CACF,CAAC;AA4HF;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA2EA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,QAAQ,EAAE;QACR,WAAW,EAAE,QAAQ,EAAS,aAAa;QAC3C,gBAAgB,EAAE,QAAQ,EAAI,kBAAkB;QAChD,eAAe,EAAE,QAAQ,EAAK,MAAM;QACpC,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,QAAQ,CAAE,MAAM;KACrC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,YAAY;QAC1C,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,wBAAwB;QAC1D,eAAe,EAAE,EAAE,GAAG,IAAI,EAAI,mBAAmB;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KACnD;IACD,UAAU,EAAE;QACV,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,WAAW;QACzC,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAG,uBAAuB;QACzD,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,kBAAkB;QACpD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;KACxD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,EAAQ,aAAa;QAC3C,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAG,wBAAwB;QACtD,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAG,eAAe;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KAC5D;CACF,CAAC;AA+MF;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AAYnD;;;;;;;;;;;GAWG;AACH,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACzB,MAAM,+BAA+B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serfab/cadre-core",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "description": "Core library for Sereus cadre nodes - manages control networks and strand participation",
6
6
  "main": "dist/index.js",
@@ -24,6 +24,14 @@
24
24
  "types": "./dist/key-store-file.d.ts",
25
25
  "import": "./dist/key-store-file.js"
26
26
  },
27
+ "./trusted-owner-store-file": {
28
+ "types": "./dist/trusted-owner-store-file.d.ts",
29
+ "import": "./dist/trusted-owner-store-file.js"
30
+ },
31
+ "./bootstrap-peer-store-file": {
32
+ "types": "./dist/bootstrap-peer-store-file.d.ts",
33
+ "import": "./dist/bootstrap-peer-store-file.js"
34
+ },
27
35
  "./push-node": {
28
36
  "types": "./dist/push-node.d.ts",
29
37
  "import": "./dist/push-node.js"
@@ -54,8 +62,12 @@
54
62
  "devDependencies": {
55
63
  "@chainsafe/libp2p-noise": "^17.0.0",
56
64
  "@chainsafe/libp2p-yamux": "^8.0.1",
57
- "@libp2p/peer-id-factory": "^4.2.4",
65
+ "@libp2p/circuit-relay-v2": "^4.1.3",
66
+ "@libp2p/identify": "4.0.10",
58
67
  "@libp2p/tcp": "^11.0.10",
68
+ "@libp2p/webrtc": "6.0.14",
69
+ "@libp2p/websockets": "^10.1.3",
70
+ "@optimystic/db-p2p-storage-fs": "^0.24.0",
59
71
  "@types/debug": "^4.1.12",
60
72
  "@types/node": "^25.0.10",
61
73
  "@vitest/coverage-v8": "^4.0.17",
@@ -68,12 +80,12 @@
68
80
  "@libp2p/interface": "^3.1.0",
69
81
  "@libp2p/peer-id": "^6.0.4",
70
82
  "@multiformats/multiaddr": "^12.5.1",
71
- "@optimystic/db-core": "^0.14.1",
72
- "@optimystic/db-p2p": "^0.14.1",
73
- "@optimystic/quereus-plugin-crypto": "^0.14.1",
74
- "@optimystic/quereus-plugin-optimystic": "^0.14.1",
75
- "@quereus/quereus": "^4.4.0",
76
- "@serfab/quereus-plugin-sereus": "^0.9.0",
83
+ "@optimystic/db-core": "^0.24.0",
84
+ "@optimystic/db-p2p": "^0.24.0",
85
+ "@optimystic/quereus-plugin-crypto": "^0.24.0",
86
+ "@optimystic/quereus-plugin-optimystic": "^0.24.0",
87
+ "@quereus/quereus": "^4.14.0",
88
+ "@serfab/quereus-plugin-sereus": "^0.11.0",
77
89
  "debug": "^4.4.3",
78
90
  "libp2p": "^3.1.3",
79
91
  "uint8arrays": "^5.1.0"