@kubun/plugin-p2p 0.11.0 → 0.12.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.
- package/lib/context/group.js +1073 -746
- package/lib/context/hub.js +2 -1
- package/lib/context/join.js +50 -15
- package/lib/context/peer.d.ts +92 -0
- package/lib/context/peer.js +1216 -0
- package/lib/context/require-admin.d.ts +57 -0
- package/lib/context/require-admin.js +57 -0
- package/lib/context/sync.d.ts +12 -0
- package/lib/context/sync.js +234 -1
- package/lib/context/types.d.ts +56 -20
- package/lib/context/types.js +23 -3
- package/lib/groups/access-default-token.d.ts +44 -0
- package/lib/groups/access-default-token.js +103 -0
- package/lib/groups/admin-roster.d.ts +42 -117
- package/lib/groups/admin-roster.js +53 -168
- package/lib/groups/anchor-store.d.ts +15 -0
- package/lib/groups/anchor-store.js +37 -0
- package/lib/groups/app-cursor-store.d.ts +17 -0
- package/lib/groups/app-cursor-store.js +34 -0
- package/lib/groups/broadcast.d.ts +199 -81
- package/lib/groups/broadcast.js +443 -368
- package/lib/groups/catalog-token.d.ts +50 -0
- package/lib/groups/catalog-token.js +96 -0
- package/lib/groups/circle-projection.d.ts +32 -64
- package/lib/groups/circle-projection.js +95 -181
- package/lib/groups/circle-reducers.d.ts +71 -110
- package/lib/groups/circle-reducers.js +57 -127
- package/lib/groups/commit-adoption.d.ts +77 -0
- package/lib/groups/commit-adoption.js +108 -0
- package/lib/groups/commit-journal.d.ts +14 -0
- package/lib/groups/commit-journal.js +65 -0
- package/lib/groups/control-request.d.ts +66 -0
- package/lib/groups/control-request.js +101 -0
- package/lib/groups/events.d.ts +14 -1
- package/lib/groups/group-anchor.d.ts +18 -57
- package/lib/groups/group-anchor.js +15 -100
- package/lib/groups/group-crypto.d.ts +36 -13
- package/lib/groups/group-crypto.js +124 -50
- package/lib/groups/group-handle-registry.d.ts +106 -36
- package/lib/groups/group-handle-registry.js +351 -61
- package/lib/groups/group-handlers.d.ts +5 -4
- package/lib/groups/group-handlers.js +155 -29
- package/lib/groups/group-health-monitor.d.ts +1 -1
- package/lib/groups/group-health-monitor.js +1 -1
- package/lib/groups/group-mls.d.ts +35 -4
- package/lib/groups/group-mls.js +594 -62
- package/lib/groups/group-peer-manager.d.ts +212 -19
- package/lib/groups/group-peer-manager.js +1061 -69
- package/lib/groups/group-protocols.d.ts +485 -28
- package/lib/groups/group-protocols.js +289 -15
- package/lib/groups/invite-payload.d.ts +48 -0
- package/lib/groups/join-request-identity.d.ts +21 -0
- package/lib/groups/join-request-identity.js +43 -0
- package/lib/groups/join-utils.d.ts +60 -0
- package/lib/groups/join-utils.js +262 -0
- package/lib/groups/ledger-affected-events.d.ts +11 -6
- package/lib/groups/ledger-affected-events.js +15 -26
- package/lib/groups/ledger-commit-fold.d.ts +107 -0
- package/lib/groups/ledger-commit-fold.js +167 -0
- package/lib/groups/ledger-ingest.d.ts +124 -0
- package/lib/groups/ledger-ingest.js +212 -0
- package/lib/groups/ledger.d.ts +44 -0
- package/lib/groups/ledger.js +30 -0
- package/lib/groups/manager.d.ts +202 -19
- package/lib/groups/manager.js +623 -106
- package/lib/groups/mls-codec.d.ts +27 -6
- package/lib/groups/mls-codec.js +30 -15
- package/lib/groups/mls-encryptor.js +9 -6
- package/lib/groups/mls-group-handle.d.ts +37 -2
- package/lib/groups/mls-group-handle.js +12 -4
- package/lib/groups/mls-receive-errors.d.ts +0 -2
- package/lib/groups/mls-receive-errors.js +3 -6
- package/lib/groups/mls-state.d.ts +5 -3
- package/lib/groups/mls-state.js +27 -4
- package/lib/groups/peer-presence.d.ts +90 -0
- package/lib/groups/peer-presence.js +295 -0
- package/lib/groups/peer-selection.d.ts +37 -0
- package/lib/groups/peer-selection.js +72 -0
- package/lib/groups/roster-projection.d.ts +53 -0
- package/lib/groups/roster-projection.js +65 -0
- package/lib/groups/store-received-grant.d.ts +4 -3
- package/lib/groups/store-received-grant.js +80 -35
- package/lib/groups/store-received-revocation.d.ts +16 -13
- package/lib/groups/store-received-revocation.js +23 -22
- package/lib/hub/http-client.d.ts +10 -27
- package/lib/hub/http-client.js +2 -19
- package/lib/hub/hub-like.d.ts +57 -6
- package/lib/hub/hub-like.js +539 -52
- package/lib/hub/loopback-log-hub.d.ts +20 -0
- package/lib/hub/loopback-log-hub.js +178 -0
- package/lib/hub/manager.d.ts +25 -40
- package/lib/hub/manager.js +51 -94
- package/lib/hub/peer-scoped-hub-view.d.ts +35 -0
- package/lib/hub/peer-scoped-hub-view.js +92 -0
- package/lib/hub/sender-scoped-hub-view.d.ts +41 -0
- package/lib/hub/sender-scoped-hub-view.js +59 -0
- package/lib/hub/server-did.d.ts +67 -0
- package/lib/hub/server-did.js +131 -0
- package/lib/hub/wiring.d.ts +71 -14
- package/lib/hub/wiring.js +80 -23
- package/lib/index.d.ts +48 -13
- package/lib/index.js +257 -86
- package/lib/peer/connection-registry.d.ts +45 -0
- package/lib/peer/connection-registry.js +52 -0
- package/lib/peer/handlers.d.ts +69 -0
- package/lib/peer/handlers.js +110 -0
- package/lib/protocol.d.ts +213 -0
- package/lib/protocol.js +268 -0
- package/lib/schema.d.ts +2 -1
- package/lib/schema.js +805 -131
- package/lib/sync/access-default-sender.d.ts +23 -0
- package/lib/sync/access-default-sender.js +80 -0
- package/lib/sync/authorize.d.ts +57 -3
- package/lib/sync/authorize.js +45 -4
- package/lib/sync/broadcast-queue.d.ts +3 -4
- package/lib/sync/broadcast-queue.js +2 -3
- package/lib/sync/catalog-scope.d.ts +8 -7
- package/lib/sync/catalog-scope.js +55 -39
- package/lib/sync/errors.d.ts +9 -0
- package/lib/sync/errors.js +10 -0
- package/lib/sync/forwarder.d.ts +13 -19
- package/lib/sync/forwarder.js +13 -19
- package/lib/sync/handlers.js +54 -14
- package/lib/sync/hub-tunnel-sync-listener.d.ts +16 -6
- package/lib/sync/hub-tunnel-sync-listener.js +126 -37
- package/lib/sync/hub-tunnel-sync-provider.d.ts +31 -11
- package/lib/sync/hub-tunnel-sync-provider.js +68 -19
- package/lib/sync/merkle-channel.d.ts +9 -1
- package/lib/sync/merkle-channel.js +0 -0
- package/lib/sync/peer-registry.d.ts +14 -10
- package/lib/sync/peer-registry.js +0 -25
- package/lib/sync/sync-client.d.ts +11 -1
- package/lib/sync/sync-client.js +72 -10
- package/lib/sync/sync-manager.d.ts +22 -4
- package/lib/sync/sync-manager.js +39 -10
- package/lib/sync/tunnel-listeners.d.ts +52 -0
- package/lib/sync/tunnel-listeners.js +175 -0
- package/lib/sync/tunnel-observability.d.ts +25 -0
- package/lib/sync/tunnel-observability.js +63 -0
- package/lib/sync/tunnel-topics.d.ts +20 -0
- package/lib/sync/tunnel-topics.js +28 -0
- package/lib/types.d.ts +699 -28
- package/lib/types.js +0 -1
- package/lib/util/handler-error.d.ts +16 -0
- package/lib/util/handler-error.js +64 -0
- package/lib/util/mutex.d.ts +14 -1
- package/lib/util/mutex.js +37 -3
- package/package.json +56 -52
- package/lib/groups/ledger-entry.d.ts +0 -37
- package/lib/groups/ledger-entry.js +0 -56
- package/lib/groups/ledger-fold.d.ts +0 -56
- package/lib/groups/ledger-fold.js +0 -53
- package/lib/hub/did-observing-transport.d.ts +0 -75
- package/lib/hub/did-observing-transport.js +0 -126
- package/lib/hub/errors.d.ts +0 -24
- package/lib/hub/errors.js +0 -33
|
@@ -1,17 +1,35 @@
|
|
|
1
|
+
import type { ProcedureHandlers } from '@enkaku/server';
|
|
2
|
+
import type { OwnIdentity } from '@kokuin/token';
|
|
1
3
|
import type { StoreProvider } from '@kubun/db';
|
|
2
4
|
import type { DefaultAccessLevel, GraphInternals } from '@kubun/engine';
|
|
3
5
|
import type { HLC } from '@kubun/hlc';
|
|
4
6
|
import type { Logger } from '@kubun/logger';
|
|
5
7
|
import type { GraphStoreAPI } from '@kubun/store-graph';
|
|
6
|
-
import type
|
|
7
|
-
import {
|
|
8
|
-
import type { OnServerDIDObserved } from '../hub/did-observing-transport.js';
|
|
8
|
+
import { type GroupPeer, type LaneResult, type PendingCommit } from '@kumiai/rpc';
|
|
9
|
+
import type { Runtime } from '@sozai/runtime';
|
|
9
10
|
import type { CreateHubClient } from '../hub/http-client.js';
|
|
10
|
-
import type
|
|
11
|
+
import { type DeviceHub, type ReconnectingDeviceHub } from '../hub/hub-like.js';
|
|
12
|
+
import type { SyncProtocol } from '../protocol.js';
|
|
13
|
+
import type { ForwardingConfig } from '../sync/forwarder.js';
|
|
14
|
+
import type { LedgerCatchupOptions, LedgerCatchupSummary, RejoinResult, StoreUnreadableMode } from '../types.js';
|
|
11
15
|
import type { GroupBroadcastMessage } from './broadcast.js';
|
|
16
|
+
import { type SettleLostControlRequestDeps } from './commit-adoption.js';
|
|
12
17
|
import type { P2PEventEmitter } from './events.js';
|
|
13
18
|
import type { GroupHandleRegistry } from './group-handle-registry.js';
|
|
14
19
|
import { type GroupProtocols } from './group-protocols.js';
|
|
20
|
+
import { type PeerPresence } from './peer-presence.js';
|
|
21
|
+
/**
|
|
22
|
+
* Rebuild a fresh `ledger` commit carrying the given signed tokens, to re-drive
|
|
23
|
+
* a lost one under its original request id.
|
|
24
|
+
*
|
|
25
|
+
* A narrow capability, NOT the whole group manager: the lane may only ask for
|
|
26
|
+
* exactly this — a build closure over surviving ledger tokens — so it stays a
|
|
27
|
+
* consumer of the ledger write path, never its owner. Wired from
|
|
28
|
+
* `GroupManager.buildEnactLedgerCommit`. `requestID` is absent when the lost
|
|
29
|
+
* commit journalled none: the tokens are still the work and are re-driven, but
|
|
30
|
+
* the rebuilt commit settles nothing rather than settling a fabricated id.
|
|
31
|
+
*/
|
|
32
|
+
export type BuildLedgerRedrive = (groupID: string, tokens: Array<string>, requestID?: string) => () => Promise<PendingCommit>;
|
|
15
33
|
export type GroupPeerManagerParams = {
|
|
16
34
|
/**
|
|
17
35
|
* Spawns a fresh `Client<HubProtocol>` for a hub URL. The manager wraps each
|
|
@@ -19,11 +37,17 @@ export type GroupPeerManagerParams = {
|
|
|
19
37
|
* receive drain), lazily on first peer creation for that hub.
|
|
20
38
|
*/
|
|
21
39
|
createHubClient: CreateHubClient;
|
|
40
|
+
/**
|
|
41
|
+
* Rebuilds a lost `ledger` commit's surviving tokens into a fresh commit under
|
|
42
|
+
* the original request id, for the seam to re-drive once. Narrow by design —
|
|
43
|
+
* see {@link BuildLedgerRedrive}.
|
|
44
|
+
*/
|
|
45
|
+
buildLedgerRedrive: BuildLedgerRedrive;
|
|
22
46
|
/** Single canonical access point for the device's MLS `GroupHandle` instances. */
|
|
23
47
|
registry: GroupHandleRegistry;
|
|
24
48
|
/**
|
|
25
49
|
* Store coordinator. Resolves the device's p2p store for the apply path,
|
|
26
|
-
* group↔hub binding reads, and
|
|
50
|
+
* group↔hub binding reads, and the hub-DID cache; also passed to
|
|
27
51
|
* `createGroupMLS` for the receive-side commit transaction.
|
|
28
52
|
*/
|
|
29
53
|
stores: StoreProvider;
|
|
@@ -38,20 +62,54 @@ export type GroupPeerManagerParams = {
|
|
|
38
62
|
hlc: HLC;
|
|
39
63
|
/** Authenticated DID of this device (normalized). */
|
|
40
64
|
localDID: string;
|
|
65
|
+
/**
|
|
66
|
+
* The device's own signing identity, forwarded to each peer's `GroupMLS` for
|
|
67
|
+
* the recovery members alone — the only lane work that must sign without a
|
|
68
|
+
* request behind it to take a key from.
|
|
69
|
+
*/
|
|
70
|
+
identity: OwnIdentity;
|
|
41
71
|
emitter: P2PEventEmitter;
|
|
42
|
-
/**
|
|
43
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Host runtime; forwarded to each peer when set, which sources its fresh
|
|
74
|
+
* group-rpc correlation ids from it.
|
|
75
|
+
*/
|
|
76
|
+
runtime?: Runtime;
|
|
44
77
|
logger?: Logger;
|
|
45
78
|
/** Receive-side storage mode. Forwarded to the apply path. Defaults to `'persist'`. */
|
|
46
79
|
storeUnreadable?: StoreUnreadableMode;
|
|
47
80
|
/** Server default access level — required when `storeUnreadable === 'drop'`. */
|
|
48
81
|
defaultAccessLevel?: DefaultAccessLevel;
|
|
49
82
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
83
|
+
* Per-peer N+1 re-broadcast config for the apply path. Omitted or `false`
|
|
84
|
+
* skips the pipeline.
|
|
85
|
+
*/
|
|
86
|
+
forwarding?: ForwardingConfig;
|
|
87
|
+
/**
|
|
88
|
+
* Hub hook a forward re-broadcasts through. The apply path gates on this AND
|
|
89
|
+
* `forwarding`, so supplying one alone leaves forwarding off.
|
|
90
|
+
*/
|
|
91
|
+
scheduleBroadcast?: (groupID: string, message: GroupBroadcastMessage) => void | Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Reconnect-backoff overrides for every hub adapter this manager spawns. Only
|
|
94
|
+
* a test harness sets this — production runs on the adapter's defaults. Each
|
|
95
|
+
* field is forwarded verbatim to {@link createHubLike}.
|
|
53
96
|
*/
|
|
54
|
-
|
|
97
|
+
hubReconnectBackoff?: {
|
|
98
|
+
baseMs?: number;
|
|
99
|
+
maxMs?: number;
|
|
100
|
+
jitter?: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Sync procedures served to a co-member that dials in over a hub tunnel. The
|
|
104
|
+
* same handlers the direct and HTTP transports serve — a tunnel is a route,
|
|
105
|
+
* so it must not reach a different implementation.
|
|
106
|
+
*
|
|
107
|
+
* Omitted, the device answers no tunnel session: a caller that has not built
|
|
108
|
+
* handlers has no sync surface to expose.
|
|
109
|
+
*/
|
|
110
|
+
syncHandlers?: ProcedureHandlers<SyncProtocol>;
|
|
111
|
+
/** @see TunnelListenersParams.idleTimeoutMs */
|
|
112
|
+
tunnelIdleTimeoutMs?: number;
|
|
55
113
|
};
|
|
56
114
|
/**
|
|
57
115
|
* Coordinates the per-(group, hub) `GroupPeer`s for one device — full multi-hub.
|
|
@@ -75,12 +133,64 @@ export type GroupPeerManager = {
|
|
|
75
133
|
addBinding: (groupID: string, hubURL: string) => Promise<void>;
|
|
76
134
|
/** Dispose the (group, hub) peer if present, GC-ing the hub if now idle. */
|
|
77
135
|
removeBinding: (groupID: string, hubURL: string) => Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Re-derive the group's tunnel listeners from its current roster.
|
|
138
|
+
*
|
|
139
|
+
* Driven by the membership projection rather than only by the epoch, because
|
|
140
|
+
* the epoch advances INSIDE the transaction that writes the new member: a
|
|
141
|
+
* reconcile scheduled there can read the roster as it was and stand up no
|
|
142
|
+
* listener for the device just admitted.
|
|
143
|
+
*/
|
|
144
|
+
reconcileTunnelListeners: (groupID: string) => Promise<void>;
|
|
78
145
|
/** Fan a broadcast message out across every hub-peer of a group. */
|
|
79
146
|
broadcast: (groupID: string, message: GroupBroadcastMessage) => Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
|
|
147
|
+
/**
|
|
148
|
+
* This device's presence on the peer lane: what it advertises, and who it asks.
|
|
149
|
+
* The manager owns it because every internal trigger fires from here — a hub
|
|
150
|
+
* connect, an epoch rotation, a pruned app window — and because a gather needs
|
|
151
|
+
* the group's live peers.
|
|
152
|
+
*/
|
|
153
|
+
presence: PeerPresence;
|
|
154
|
+
/**
|
|
155
|
+
* The peer for the group's canonical commit hub — the single hub a group
|
|
156
|
+
* commits through. Resolves the designated commit hub; falls back to the live
|
|
157
|
+
* peer whose hub URL sorts first for a legacy group with no designation (and
|
|
158
|
+
* warns), then to the group's loopback peer when it has no hub-backed peer at
|
|
159
|
+
* all. `undefined` only when the group has no lane whatsoever.
|
|
160
|
+
*/
|
|
161
|
+
selectCommitPeer: (groupID: string) => Promise<GroupPeer<GroupProtocols> | undefined>;
|
|
162
|
+
/**
|
|
163
|
+
* Drive a commit through the group's canonical commit hub: build against the
|
|
164
|
+
* live handle, publish to that hub's commit log, adopt only on acceptance.
|
|
165
|
+
* Throws when the group has no live commit peer.
|
|
166
|
+
*/
|
|
167
|
+
commit: (groupID: string, build: () => Promise<PendingCommit>) => Promise<LaneResult>;
|
|
168
|
+
/**
|
|
169
|
+
* Deep recovery: rejoin a peer the group left behind, via `GroupPeer.recover()`
|
|
170
|
+
* on the group's canonical commit hub. The peer requests a member's sealed
|
|
171
|
+
* GroupInfo over the non-rotating rendezvous topic, publishes the external
|
|
172
|
+
* commit under a head compare-and-set, and bootstraps the ledger — reissuing
|
|
173
|
+
* any tokens the authenticated ledger lacked. Reports `recovered` once the
|
|
174
|
+
* rejoin landed, or `recovery-failed` (without throwing) when no live responder
|
|
175
|
+
* answers or the group has no lane.
|
|
176
|
+
*/
|
|
83
177
|
rejoinGroup: (groupID: string) => Promise<RejoinResult>;
|
|
178
|
+
/**
|
|
179
|
+
* Gather the group's control ledger from its current members and adopt it
|
|
180
|
+
* locally. Sends a `control/ledgerCatchup` request on every live hub-peer of
|
|
181
|
+
* the group; each responder returns its WHOLE ledger in enactment order, and
|
|
182
|
+
* the first list that reproduces this device's authenticated head is installed
|
|
183
|
+
* — a responder that withholds or reorders entries is dropped, not merged. A
|
|
184
|
+
* drifted joiner thus backfills what its invite snapshot missed, or gets
|
|
185
|
+
* nothing. Returns what landed; a no-op summary when the group has no live
|
|
186
|
+
* peer or every responder was refused.
|
|
187
|
+
*/
|
|
188
|
+
requestLedgerCatchup: (groupID: string, options?: LedgerCatchupOptions) => Promise<LedgerCatchupSummary>;
|
|
189
|
+
/**
|
|
190
|
+
* Ask co-members to restate their own model access-defaults, and apply what is
|
|
191
|
+
* newer than what this device holds. Returns how many rules landed.
|
|
192
|
+
*/
|
|
193
|
+
requestPolicyCatchup: (groupID: string) => Promise<number>;
|
|
84
194
|
/** The peer for one (group, hub), or `undefined` (used by tests). */
|
|
85
195
|
peer: (groupID: string, hubURL: string) => GroupPeer<GroupProtocols> | undefined;
|
|
86
196
|
/**
|
|
@@ -88,9 +198,22 @@ export type GroupPeerManager = {
|
|
|
88
198
|
* Lets a caller obtain the device-wide drain to pass into a directed sync
|
|
89
199
|
* transport (provider/listener) sharing the same hub connection.
|
|
90
200
|
*/
|
|
91
|
-
getHubLike: (hubURL: string) =>
|
|
92
|
-
|
|
93
|
-
|
|
201
|
+
getHubLike: (hubURL: string) => ReconnectingDeviceHub;
|
|
202
|
+
/**
|
|
203
|
+
* The device-wide drain a directed session to this group should ride, or
|
|
204
|
+
* `undefined` when the group has no live hub binding — which is what a caller
|
|
205
|
+
* building a tunnel needs to know before it builds one.
|
|
206
|
+
*
|
|
207
|
+
* The group's first binding. A second hub is a second route to the same
|
|
208
|
+
* mailbox, not a different peer, so choosing between them is a preference
|
|
209
|
+
* nothing here holds.
|
|
210
|
+
*/
|
|
211
|
+
tunnelHub: (groupID: string) => DeviceHub | undefined;
|
|
212
|
+
/**
|
|
213
|
+
* Try every hub this device holds now, rather than when each one's backoff
|
|
214
|
+
* says so, and answer with whether any of them is connected afterwards.
|
|
215
|
+
*/
|
|
216
|
+
retryHubs: () => Promise<boolean>;
|
|
94
217
|
/** Dispose every peer and hub, then clear all maps. */
|
|
95
218
|
stop: () => Promise<void>;
|
|
96
219
|
/** Alias for {@link stop}. */
|
|
@@ -101,8 +224,78 @@ export type GroupPeerManager = {
|
|
|
101
224
|
*
|
|
102
225
|
* Translates a {@link GroupBroadcastMessage} into the matching group-rpc
|
|
103
226
|
* `dispatch` on a peer's control/sync protocol surface. Variants with no carried
|
|
104
|
-
* procedure (catalog control)
|
|
105
|
-
* not a dispatch) are logged and no-op'd, matching the receive side.
|
|
227
|
+
* procedure (catalog control) are logged and no-op'd, matching the receive side.
|
|
106
228
|
*/
|
|
107
229
|
export declare function dispatchMessage(peer: GroupPeer<GroupProtocols>, message: GroupBroadcastMessage, logger?: Logger): Promise<void>;
|
|
230
|
+
/**
|
|
231
|
+
* Run one lane operation, retrying only while the peer's runtimes are mid-rebuild.
|
|
232
|
+
*
|
|
233
|
+
* Safe to retry because the throw happens BEFORE anything is sealed or published:
|
|
234
|
+
* `surfaceFor` is what fails, so a retry cannot duplicate a frame. Every other
|
|
235
|
+
* failure — a refused publish, an unrouted message type — propagates on the first
|
|
236
|
+
* attempt, which is what keeps this from papering over a real fault.
|
|
237
|
+
*/
|
|
238
|
+
export declare function throughRotation<T>(op: () => Promise<T>, label: string, logger?: Logger): Promise<T>;
|
|
239
|
+
/**
|
|
240
|
+
* Everything the seam needs to act on a lost commit: the settle deps it shares
|
|
241
|
+
* with {@link settleLostControlRequest}, plus what a lost `ledger` re-drive
|
|
242
|
+
* takes — the group whose ledger is read for the never-re-append filter, the
|
|
243
|
+
* registry that read runs through, and the narrow builder that rebuilds a
|
|
244
|
+
* surviving-token commit.
|
|
245
|
+
*/
|
|
246
|
+
export type CommitThroughPeerDeps = SettleLostControlRequestDeps & {
|
|
247
|
+
groupID: string;
|
|
248
|
+
/** Reads the group's current ledger tokens for the never-re-append filter. */
|
|
249
|
+
registry: Pick<GroupHandleRegistry, 'readHandle'>;
|
|
250
|
+
buildLedgerRedrive: BuildLedgerRedrive;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Publish a commit through the peer and act on what the lane hands back.
|
|
254
|
+
*
|
|
255
|
+
* A `LaneResult` can carry both a `lost` and a `reenact`; handle each
|
|
256
|
+
* independently. A lost `ledger` is re-issuable from its tokens, an `invite` or
|
|
257
|
+
* `remove` is not, so those settle `lost` here.
|
|
258
|
+
*
|
|
259
|
+
* The housekeeping is CONTAINED — never let it throw. By the time it runs THIS
|
|
260
|
+
* commit has landed and its request is settled, while `lost` and `reenact` name
|
|
261
|
+
* other work; an escaping throw would have the producer's per-request catch
|
|
262
|
+
* settle the terminal request `rejected`, writing a failure over a success and
|
|
263
|
+
* nulling the artifact for a member who really was added. That covers
|
|
264
|
+
* `RecoveryRequiredError` too: reaching {@link commitWithRecovery} would re-run
|
|
265
|
+
* the ORIGINAL `build` after its commit landed, publishing a second copy outside
|
|
266
|
+
* the never-re-append filter.
|
|
267
|
+
*/
|
|
268
|
+
export declare function commitThroughPeer(peer: Pick<GroupPeer<GroupProtocols>, 'commit'>, build: () => Promise<PendingCommit>, deps: CommitThroughPeerDeps): Promise<LaneResult>;
|
|
269
|
+
export type CommitWithRecoveryParams = {
|
|
270
|
+
peer: Pick<GroupPeer<GroupProtocols>, 'commit' | 'recover'>;
|
|
271
|
+
build: () => Promise<PendingCommit>;
|
|
272
|
+
deps: CommitThroughPeerDeps;
|
|
273
|
+
/** Repair an incomplete ledger, the cheaper of the two remedies. */
|
|
274
|
+
gatherLedger: () => Promise<unknown>;
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* Publish a commit and, on the lane's stranded/incomplete-ledger gate, self-heal.
|
|
278
|
+
*
|
|
279
|
+
* The gate conflates an incomplete ledger — repaired by a plain ledger GATHER —
|
|
280
|
+
* with a true strand, repaired only by a full rejoin via `recover()`, so the
|
|
281
|
+
* cheaper remedy runs first: gather + retry once, then `recover()` + retry once,
|
|
282
|
+
* then propagate. Each remedy runs AT MOST ONCE (≤3 commit attempts): upstream
|
|
283
|
+
* forbids a tight retry loop, and `recover()` already bounds itself with its own
|
|
284
|
+
* deadline loop. When `recover()` cannot advance, rethrow the ORIGINAL gate error
|
|
285
|
+
* so the caller settles against the real cause. The retry carries the original
|
|
286
|
+
* `requestID`, so a healed commit settles `committed` through its own
|
|
287
|
+
* `onAccepted` rather than surfacing as a failure.
|
|
288
|
+
*/
|
|
289
|
+
export declare function commitWithRecovery(params: CommitWithRecoveryParams): Promise<LaneResult>;
|
|
290
|
+
/**
|
|
291
|
+
* Rejoin the group through `GroupPeer.recover()` and map its outcome to a
|
|
292
|
+
* {@link RejoinResult}. `recover()` publishes the external commit under a head
|
|
293
|
+
* compare-and-set and bootstraps the ledger; it bounds itself, so it is never
|
|
294
|
+
* wrapped in a loop. Any `reenact` tokens it hands back — held here but absent
|
|
295
|
+
* from the authenticated ledger after the rejoin — are re-issued through the
|
|
296
|
+
* same {@link reissueLedgerTokens} filter every lane outcome uses. `advanced`
|
|
297
|
+
* maps to `recovered`; a peer that could not advance (no live responder) maps to
|
|
298
|
+
* `recovery-failed` without throwing.
|
|
299
|
+
*/
|
|
300
|
+
export declare function recoverThroughPeer(peer: Pick<GroupPeer<GroupProtocols>, 'commit' | 'recover'>, deps: CommitThroughPeerDeps): Promise<RejoinResult>;
|
|
108
301
|
export declare function createGroupPeerManager(params: GroupPeerManagerParams): GroupPeerManager;
|