@kubun/plugin-p2p 0.10.1 → 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.
- package/lib/context/delegation.js +130 -1
- package/lib/context/group.js +1319 -1
- package/lib/context/hub.js +150 -1
- package/lib/context/join.js +80 -1
- package/lib/context/sync.js +19 -1
- package/lib/context/types.d.ts +3 -3
- package/lib/context/types.js +28 -1
- package/lib/groups/admin-roster.d.ts +130 -0
- package/lib/groups/admin-roster.js +184 -0
- package/lib/groups/broadcast-codec.js +6 -1
- package/lib/groups/broadcast.d.ts +105 -91
- package/lib/groups/broadcast.js +627 -1
- package/lib/groups/circle-projection.d.ts +122 -0
- package/lib/groups/circle-projection.js +288 -0
- package/lib/groups/circle-reducers.d.ts +178 -0
- package/lib/groups/circle-reducers.js +198 -0
- package/lib/groups/events.d.ts +5 -1
- package/lib/groups/events.js +10 -1
- package/lib/groups/group-anchor.d.ts +63 -0
- package/lib/groups/group-anchor.js +107 -0
- package/lib/groups/group-crypto.d.ts +19 -0
- package/lib/groups/group-crypto.js +85 -0
- package/lib/groups/group-handle-registry.d.ts +61 -2
- package/lib/groups/group-handle-registry.js +243 -1
- package/lib/groups/group-handlers.d.ts +29 -0
- package/lib/groups/group-handlers.js +92 -0
- package/lib/groups/group-health-monitor.d.ts +11 -0
- package/lib/groups/group-health-monitor.js +139 -1
- package/lib/groups/group-mls.d.ts +35 -0
- package/lib/groups/group-mls.js +164 -0
- package/lib/groups/group-peer-manager.d.ts +108 -0
- package/lib/groups/group-peer-manager.js +344 -0
- package/lib/groups/group-protocols.d.ts +297 -0
- package/lib/groups/group-protocols.js +174 -0
- package/lib/groups/invite-payload.d.ts +1 -1
- package/lib/groups/invite-payload.js +26 -1
- package/lib/groups/join-utils.d.ts +1 -0
- package/lib/groups/join-utils.js +104 -1
- package/lib/groups/ledger-affected-events.d.ts +15 -0
- package/lib/groups/ledger-affected-events.js +96 -0
- package/lib/groups/ledger-entry.d.ts +37 -0
- package/lib/groups/ledger-entry.js +56 -0
- package/lib/groups/ledger-fold.d.ts +56 -0
- package/lib/groups/ledger-fold.js +53 -0
- package/lib/groups/manager.d.ts +20 -71
- package/lib/groups/manager.js +281 -1
- package/lib/groups/mls-codec.d.ts +1 -1
- package/lib/groups/mls-codec.js +18 -1
- package/lib/groups/mls-encryptor.d.ts +2 -2
- package/lib/groups/mls-encryptor.js +30 -1
- package/lib/groups/mls-group-handle.d.ts +1 -1
- package/lib/groups/mls-group-handle.js +10 -1
- package/lib/groups/mls-json.js +17 -1
- package/lib/groups/mls-receive-errors.d.ts +29 -0
- package/lib/groups/mls-receive-errors.js +42 -0
- package/lib/groups/mls-state.d.ts +1 -1
- package/lib/groups/mls-state.js +56 -1
- package/lib/groups/store-received-grant.d.ts +4 -1
- package/lib/groups/store-received-grant.js +116 -1
- package/lib/groups/store-received-revocation.d.ts +3 -3
- package/lib/groups/store-received-revocation.js +82 -1
- package/lib/hub/ack-backoff.d.ts +22 -0
- package/lib/hub/ack-backoff.js +88 -0
- package/lib/hub/did-observing-transport.d.ts +13 -2
- package/lib/hub/did-observing-transport.js +126 -1
- package/lib/hub/errors.d.ts +0 -6
- package/lib/hub/errors.js +33 -1
- package/lib/hub/http-client.d.ts +28 -3
- package/lib/hub/http-client.js +32 -1
- package/lib/hub/hub-like.d.ts +24 -0
- package/lib/hub/hub-like.js +535 -0
- package/lib/hub/manager.js +198 -1
- package/lib/hub/wiring.d.ts +17 -48
- package/lib/hub/wiring.js +132 -1
- package/lib/index.d.ts +17 -16
- package/lib/index.js +392 -1
- package/lib/protocol.d.ts +1 -1
- package/lib/protocol.js +251 -1
- package/lib/schema.d.ts +2 -1
- package/lib/schema.js +439 -2
- package/lib/sync/authorize.d.ts +1 -1
- package/lib/sync/authorize.js +73 -1
- package/lib/sync/broadcast-queue.js +183 -1
- package/lib/sync/broadcast-sender.js +179 -1
- package/lib/sync/catalog-scope.js +68 -1
- package/lib/sync/errors.d.ts +3 -2
- package/lib/sync/errors.js +19 -1
- package/lib/sync/forwarder.js +277 -1
- package/lib/sync/handlers.js +160 -1
- package/lib/sync/hub-tunnel-sync-listener.d.ts +8 -4
- package/lib/sync/hub-tunnel-sync-listener.js +172 -1
- package/lib/sync/hub-tunnel-sync-provider.d.ts +14 -14
- package/lib/sync/hub-tunnel-sync-provider.js +64 -1
- package/lib/sync/merkle-apply.d.ts +5 -0
- package/lib/sync/merkle-apply.js +194 -1
- package/lib/sync/merkle-channel.d.ts +2 -2
- package/lib/sync/merkle-channel.js +182 -1
- package/lib/sync/merkle-tree.js +120 -1
- package/lib/sync/peer-registry.d.ts +1 -1
- package/lib/sync/peer-registry.js +107 -1
- package/lib/sync/receive-access-gate.js +24 -1
- package/lib/sync/scope-resolver.js +41 -1
- package/lib/sync/sync-client.d.ts +3 -3
- package/lib/sync/sync-client.js +192 -1
- package/lib/sync/sync-manager.d.ts +2 -2
- package/lib/sync/sync-manager.js +272 -1
- package/lib/types.d.ts +11 -0
- package/lib/types.js +2 -1
- package/lib/util/mutex.js +10 -1
- package/lib/utils.js +21 -1
- package/package.json +47 -40
- package/lib/groups/broadcast-service.d.ts +0 -263
- package/lib/groups/broadcast-service.js +0 -1
- package/lib/groups/rejoin-codec.d.ts +0 -14
- package/lib/groups/rejoin-codec.js +0 -1
- package/lib/groups/wire-frame.d.ts +0 -34
- package/lib/groups/wire-frame.js +0 -1
- package/lib/hub/circle-catchup-requester.d.ts +0 -58
- package/lib/hub/circle-catchup-requester.js +0 -1
- package/lib/hub/circle-catchup-responder.d.ts +0 -50
- package/lib/hub/circle-catchup-responder.js +0 -1
- package/lib/hub/connection-pool.d.ts +0 -43
- package/lib/hub/connection-pool.js +0 -1
- package/lib/hub/epoch-stale-detector.d.ts +0 -18
- package/lib/hub/epoch-stale-detector.js +0 -1
- package/lib/hub/forward-remote-broadcast.d.ts +0 -15
- package/lib/hub/forward-remote-broadcast.js +0 -1
- package/lib/hub/group-channel.d.ts +0 -89
- package/lib/hub/group-channel.js +0 -1
- package/lib/hub/hub-connection.d.ts +0 -96
- package/lib/hub/hub-connection.js +0 -1
- package/lib/hub/receive-handler.d.ts +0 -51
- package/lib/hub/receive-handler.js +0 -1
- package/lib/hub/rejoin-manager.d.ts +0 -78
- package/lib/hub/rejoin-manager.js +0 -1
- package/lib/hub/rejoin-responder.d.ts +0 -32
- package/lib/hub/rejoin-responder.js +0 -1
- package/lib/hub/relay-manager.d.ts +0 -142
- package/lib/hub/relay-manager.js +0 -1
- package/lib/hub/send-handler.d.ts +0 -40
- package/lib/hub/send-handler.js +0 -1
- package/lib/hub/tunnel-inbox.d.ts +0 -20
- package/lib/hub/tunnel-inbox.js +0 -1
- package/lib/hub/wait-for-gate.d.ts +0 -14
- package/lib/hub/wait-for-gate.js +0 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { DefaultAccessLevel, GraphInternals } from '@kubun/engine';
|
|
2
|
+
import { HLC } from '@kubun/hlc';
|
|
2
3
|
import type { Logger } from '@kubun/logger';
|
|
3
|
-
import type { CatalogRecord
|
|
4
|
-
import type {
|
|
4
|
+
import type { CatalogRecord } from '@kubun/protocol';
|
|
5
|
+
import type { DelegationStoreAPI } from '@kubun/store-delegation';
|
|
6
|
+
import type { GraphStoreAPI } from '@kubun/store-graph';
|
|
5
7
|
import type { Circle, CircleMember, Group, P2PStoreAPI } from '@kubun/store-p2p';
|
|
6
8
|
import { type ForwardingConfig } from '../sync/forwarder.js';
|
|
7
9
|
import type { StoreUnreadableMode } from '../types.js';
|
|
8
10
|
import type { P2PEventEmitter } from './events.js';
|
|
11
|
+
import type { GroupAnchor } from './group-anchor.js';
|
|
9
12
|
export type MutationApplyEntry = {
|
|
10
13
|
mutationJWT: string;
|
|
11
14
|
docID: string;
|
|
@@ -14,49 +17,17 @@ export type MutationApplyEntry = {
|
|
|
14
17
|
modelID: string;
|
|
15
18
|
};
|
|
16
19
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
+
* Optional signed token over a control operation. Its issuer (`iss`) is the
|
|
21
|
+
* authenticated author; receivers verify it and authorize that author as a
|
|
22
|
+
* group admin, dropping the operation when the token is absent or invalid. The
|
|
23
|
+
* signed payload is the whole message minus this field, so the signature covers
|
|
24
|
+
* every operation field, not just the author.
|
|
20
25
|
*/
|
|
21
|
-
|
|
22
|
-
removedAtHLC: string | null;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* A circle-member row in a catch-up snapshot. Mirrors the wire form of
|
|
26
|
-
* `member:add` (matching {@link CircleMemberRecord} field names) plus
|
|
27
|
-
* `removedAtHLC` so tombstoned memberships carry their removal HLC. `null` when
|
|
28
|
-
* the membership is active.
|
|
29
|
-
*/
|
|
30
|
-
export type CircleMemberSnapshot = CircleMemberRecord & {
|
|
31
|
-
removedAtHLC: string | null;
|
|
32
|
-
};
|
|
26
|
+
type ControlAuth = string;
|
|
33
27
|
export type GroupBroadcastMessage = {
|
|
34
|
-
type: 'circle:create';
|
|
35
|
-
circle: CircleRecord;
|
|
36
|
-
} | {
|
|
37
|
-
type: 'circle:update';
|
|
38
|
-
circleID: string;
|
|
39
|
-
update: {
|
|
40
|
-
name?: string;
|
|
41
|
-
description?: string;
|
|
42
|
-
catalogIDs?: Array<string>;
|
|
43
|
-
hlc: string;
|
|
44
|
-
};
|
|
45
|
-
} | {
|
|
46
|
-
type: 'circle:delete';
|
|
47
|
-
circleID: string;
|
|
48
|
-
hlc: string;
|
|
49
|
-
} | {
|
|
50
|
-
type: 'member:add';
|
|
51
|
-
member: CircleMemberRecord;
|
|
52
|
-
} | {
|
|
53
|
-
type: 'member:remove';
|
|
54
|
-
circleID: string;
|
|
55
|
-
memberDID: string;
|
|
56
|
-
hlc: string;
|
|
57
|
-
} | {
|
|
58
28
|
type: 'catalog:create';
|
|
59
29
|
catalog: CatalogRecord;
|
|
30
|
+
auth?: ControlAuth;
|
|
60
31
|
} | {
|
|
61
32
|
type: 'catalog:update';
|
|
62
33
|
catalogID: string;
|
|
@@ -66,10 +37,12 @@ export type GroupBroadcastMessage = {
|
|
|
66
37
|
filterCriteria?: CatalogRecord['filterCriteria'];
|
|
67
38
|
hlc: string;
|
|
68
39
|
};
|
|
40
|
+
auth?: ControlAuth;
|
|
69
41
|
} | {
|
|
70
42
|
type: 'catalog:delete';
|
|
71
43
|
catalogID: string;
|
|
72
44
|
hlc: string;
|
|
45
|
+
auth?: ControlAuth;
|
|
73
46
|
} | {
|
|
74
47
|
/**
|
|
75
48
|
* Distributes a minted `document/write` capability token to group
|
|
@@ -102,13 +75,9 @@ export type GroupBroadcastMessage = {
|
|
|
102
75
|
/** HLC stamped by the revoker; mirrors the revoker-side stored row. */
|
|
103
76
|
hlc: string;
|
|
104
77
|
} | {
|
|
105
|
-
type: '
|
|
78
|
+
type: 'ledger:entry';
|
|
106
79
|
groupID: string;
|
|
107
|
-
|
|
108
|
-
name?: string;
|
|
109
|
-
description?: string;
|
|
110
|
-
hlc: string;
|
|
111
|
-
};
|
|
80
|
+
token: string;
|
|
112
81
|
} | {
|
|
113
82
|
/**
|
|
114
83
|
* A member announces a voluntary leave. MLS forbids self-removal, so this
|
|
@@ -128,38 +97,60 @@ export type GroupBroadcastMessage = {
|
|
|
128
97
|
senderPeerDID: string;
|
|
129
98
|
} | {
|
|
130
99
|
/**
|
|
131
|
-
* A rejoining peer asks current members for
|
|
132
|
-
*
|
|
133
|
-
*
|
|
100
|
+
* A rejoining peer asks current members for the group's full control
|
|
101
|
+
* ledger so it can backfill entries it missed while absent. `requestID`
|
|
102
|
+
* correlates the eventual batched reply.
|
|
134
103
|
*/
|
|
135
|
-
type: '
|
|
104
|
+
type: 'ledger-catchup:request';
|
|
136
105
|
requestID: string;
|
|
137
106
|
} | {
|
|
138
107
|
/**
|
|
139
|
-
* A
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
108
|
+
* A member's reply to a `ledger-catchup:request`: the group's control
|
|
109
|
+
* ledger as an array of signed entry tokens. The responder is UNTRUSTED —
|
|
110
|
+
* each token self-authenticates, so the requester re-verifies every one
|
|
111
|
+
* independently and a forged or unsigned token is dropped without
|
|
112
|
+
* poisoning the rest. Idempotent + order-independent on the token digest.
|
|
144
113
|
*/
|
|
145
|
-
type: '
|
|
114
|
+
type: 'ledger-catchup:reply';
|
|
146
115
|
requestID: string;
|
|
147
|
-
|
|
148
|
-
circleMembers: Array<CircleMemberSnapshot>;
|
|
116
|
+
entries: Array<string>;
|
|
149
117
|
};
|
|
150
|
-
|
|
151
|
-
|
|
118
|
+
/** Narrow {@link GroupBroadcastMessage} to the variant(s) carrying the given `type`. */
|
|
119
|
+
export type BroadcastOf<TType extends GroupBroadcastMessage['type']> = Extract<GroupBroadcastMessage, {
|
|
120
|
+
type: TType;
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* The local-event descriptor for an applied `ledger:entry`. The ingest arm
|
|
124
|
+
* captures it after reprojecting, while the store still holds the post-state,
|
|
125
|
+
* so {@link forwardRemoteBroadcast} can emit the matching local event for a
|
|
126
|
+
* remote-driven change without re-reading or re-verifying. Each variant carries
|
|
127
|
+
* the projected row plus the create-vs-change / add-vs-remove discriminators the
|
|
128
|
+
* ingest derived by comparing the pre-state it read before reprojecting.
|
|
129
|
+
*/
|
|
130
|
+
export type LedgerAffected = {
|
|
131
|
+
entry: 'circle.def';
|
|
132
|
+
row: Circle;
|
|
133
|
+
/** True when an active circle row existed before this entry (changed, not created). */
|
|
134
|
+
preExisted: boolean;
|
|
135
|
+
/** True when the entry's catalog set differs from the pre-state's (catalogs changed). */
|
|
136
|
+
catalogsChanged: boolean;
|
|
137
|
+
} | {
|
|
138
|
+
entry: 'circle.def.removed';
|
|
152
139
|
row: Circle;
|
|
153
140
|
} | {
|
|
154
|
-
|
|
141
|
+
entry: 'circle.member';
|
|
155
142
|
row: CircleMember;
|
|
156
143
|
} | {
|
|
157
|
-
|
|
158
|
-
row:
|
|
144
|
+
entry: 'circle.member.removed';
|
|
145
|
+
row: CircleMember;
|
|
159
146
|
} | {
|
|
160
|
-
|
|
147
|
+
entry: 'group.settings';
|
|
161
148
|
row: Group;
|
|
162
149
|
};
|
|
150
|
+
export type AffectedRow = {
|
|
151
|
+
kind: 'ledger';
|
|
152
|
+
ledger: LedgerAffected;
|
|
153
|
+
};
|
|
163
154
|
export type ProcessBroadcastResult = {
|
|
164
155
|
applied: boolean;
|
|
165
156
|
/**
|
|
@@ -187,9 +178,21 @@ export type ProcessBroadcastResult = {
|
|
|
187
178
|
* (possibly `0`) on `mutation:apply`.
|
|
188
179
|
*/
|
|
189
180
|
duplicates?: number;
|
|
181
|
+
/**
|
|
182
|
+
* Set to `'unknown-type'` when the message carried a `type` outside the
|
|
183
|
+
* known discriminated union (version skew). The frame is not applied and is
|
|
184
|
+
* logged; other branches never set this.
|
|
185
|
+
*/
|
|
186
|
+
reason?: 'unknown-type';
|
|
190
187
|
};
|
|
191
188
|
export type ProcessBroadcastParams = {
|
|
192
189
|
p2pStore: P2PStoreAPI;
|
|
190
|
+
/**
|
|
191
|
+
* Delegation store for received-grant / received-revocation handling. The
|
|
192
|
+
* delegation token and revocation rows live here (group-agnostic); the p2p
|
|
193
|
+
* store keeps only the `jti` → group edge.
|
|
194
|
+
*/
|
|
195
|
+
delegationStore: DelegationStoreAPI;
|
|
193
196
|
graphStore: GraphStoreAPI;
|
|
194
197
|
/**
|
|
195
198
|
* Engine graph internals — required to apply `mutation:apply` entries via
|
|
@@ -235,6 +238,21 @@ export type ProcessBroadcastParams = {
|
|
|
235
238
|
* Absent in tests that don't exercise the subscription path.
|
|
236
239
|
*/
|
|
237
240
|
emitter?: P2PEventEmitter;
|
|
241
|
+
/**
|
|
242
|
+
* Device-wide monotonic clock. On a newly-appended `ledger:entry` the
|
|
243
|
+
* receiver merges the entry's HLC into this clock so its own later entries
|
|
244
|
+
* sort strictly after observed ones. Optional: callers that never receive
|
|
245
|
+
* ledger entries (and existing tests) omit it and the merge is skipped.
|
|
246
|
+
*/
|
|
247
|
+
hlc?: HLC;
|
|
248
|
+
/**
|
|
249
|
+
* Resolve a group's genesis anchor, or `null` when none is available yet. A
|
|
250
|
+
* `ledger:entry` is always stored durably, but the admin-role overlay can
|
|
251
|
+
* only be projected once the authenticated epoch-0 root is known; a `null`
|
|
252
|
+
* anchor defers projection without dropping the entry. Optional so callers
|
|
253
|
+
* that never project (and existing tests) can omit it.
|
|
254
|
+
*/
|
|
255
|
+
getGroupAnchor?: (groupID: string) => Promise<GroupAnchor | null>;
|
|
238
256
|
/** Optional logger — warns on per-entry apply failures. */
|
|
239
257
|
logger?: Logger;
|
|
240
258
|
};
|
|
@@ -257,35 +275,31 @@ export type ProcessBroadcastParams = {
|
|
|
257
275
|
*/
|
|
258
276
|
export declare function processBroadcast(params: ProcessBroadcastParams, message: GroupBroadcastMessage, groupID: string): Promise<ProcessBroadcastResult>;
|
|
259
277
|
/**
|
|
260
|
-
* Summary of a batched catch-up apply
|
|
278
|
+
* Summary of a batched ledger catch-up apply.
|
|
261
279
|
*/
|
|
262
|
-
export type
|
|
263
|
-
/** Count of
|
|
264
|
-
|
|
265
|
-
/** Count of
|
|
266
|
-
|
|
280
|
+
export type ApplyLedgerCatchupReplyResult = {
|
|
281
|
+
/** Count of entries whose verified token was newly appended to the ledger. */
|
|
282
|
+
applied: number;
|
|
283
|
+
/** Count of entries dropped because their token failed verification. */
|
|
284
|
+
rejected: number;
|
|
267
285
|
};
|
|
268
286
|
/**
|
|
269
|
-
* Apply a batched catch-up reply
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* code the live broadcast path runs. No additional merge logic lives here.
|
|
287
|
+
* Apply a batched ledger catch-up reply from an UNTRUSTED responder. Each entry
|
|
288
|
+
* carries its own signed token, so the responder's identity is irrelevant: every
|
|
289
|
+
* token is verified independently and a forged or unsigned one is dropped without
|
|
290
|
+
* aborting the batch. Surviving entries are appended idempotently on the token
|
|
291
|
+
* digest, so a replayed or duplicated reply is a harmless no-op.
|
|
275
292
|
*
|
|
276
|
-
* A
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
293
|
+
* A catch-up reply delivers the ledger's history out of order by construction, so
|
|
294
|
+
* after any new entry lands the projection is rebuilt authoritatively from the
|
|
295
|
+
* whole ledger (a full reproject) rather than applied incrementally. All four
|
|
296
|
+
* control projections — admin roster, circle defs, circle members, group
|
|
297
|
+
* settings — rebuild here, so a circle or settings entry delivered via catch-up
|
|
298
|
+
* materializes immediately rather than waiting for a later live entry. Projection
|
|
299
|
+
* is deferred when no genesis anchor is available yet — the entries are still
|
|
300
|
+
* stored durably.
|
|
284
301
|
*
|
|
285
|
-
*
|
|
286
|
-
* rows in any order, lands the same final state because every synthesized
|
|
287
|
-
* message runs the same LWW / earliest-wins guards.
|
|
302
|
+
* Never throws out of the per-token loop: one bad token must not abort the batch.
|
|
288
303
|
*/
|
|
289
|
-
export declare function
|
|
290
|
-
|
|
291
|
-
}>, groupID: string): Promise<ApplyCatchupReplyResult>;
|
|
304
|
+
export declare function applyLedgerCatchupReply(params: ProcessBroadcastParams, reply: BroadcastOf<'ledger-catchup:reply'>, groupID: string): Promise<ApplyLedgerCatchupReplyResult>;
|
|
305
|
+
export {};
|