@kubun/plugin-p2p 0.11.0 → 0.12.1
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 +59 -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
package/lib/context/hub.js
CHANGED
package/lib/context/join.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { decodeInvitePayload, encodeJoinRequest } from '../groups/invite-payload.js';
|
|
4
|
-
import { applyInviteGrants, applyInviteRevocations, finalizeJoinedGroup } from '../groups/join-utils.js';
|
|
1
|
+
import { getP2PStore } from '@kubun/store-p2p';
|
|
2
|
+
import { controlCapabilities, createKeyPackageBundle, readGroupAnchor } from '@kumiai/mls';
|
|
3
|
+
import { decodeFullJoinRequest, decodeInvitePayload, encodeFullJoinRequest, encodeJoinRequest } from '../groups/invite-payload.js';
|
|
4
|
+
import { applyInviteControlState, applyInviteGrants, applyInviteRevocations, finalizeJoinedGroup } from '../groups/join-utils.js';
|
|
5
5
|
import { checkPeerAccess } from './types.js';
|
|
6
6
|
export function createJoinContext(ctx, deps) {
|
|
7
7
|
return {
|
|
@@ -11,12 +11,21 @@ export function createJoinContext(ctx, deps) {
|
|
|
11
11
|
// The invitee leaf must advertise the anchor extension capability or
|
|
12
12
|
// commitInvite rejects the added leaf when joining an anchored group.
|
|
13
13
|
const bundle = await createKeyPackageBundle(ownIdentity, {
|
|
14
|
-
capabilities:
|
|
14
|
+
capabilities: controlCapabilities()
|
|
15
15
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
// Persisted, not stashed in memory: the offline exchange spans a human
|
|
17
|
+
// round-trip, so the answering call is routinely a different process —
|
|
18
|
+
// always so for a CLI device, where the two halves are two commands.
|
|
19
|
+
const p2pStore = await getP2PStore(deps.stores);
|
|
20
|
+
await p2pStore.putPendingJoinRequest({
|
|
21
|
+
did: ctx.viewerDID,
|
|
22
|
+
// The same encoding the connected join path hands between devices — a
|
|
23
|
+
// key package carries BigInts and binary that plain JSON drops.
|
|
24
|
+
payload: encodeFullJoinRequest({
|
|
25
|
+
did: ownIdentity.id,
|
|
26
|
+
publicPackage: bundle.publicPackage,
|
|
27
|
+
privatePackage: bundle.privatePackage
|
|
28
|
+
})
|
|
20
29
|
});
|
|
21
30
|
const encoded = encodeJoinRequest({
|
|
22
31
|
did: ownIdentity.id,
|
|
@@ -28,15 +37,20 @@ export function createJoinContext(ctx, deps) {
|
|
|
28
37
|
},
|
|
29
38
|
complete: async (invitePayloadStr)=>{
|
|
30
39
|
checkPeerAccess(ctx.viewerDID, deps.identity.id, deps.autoAcceptPeers);
|
|
31
|
-
const
|
|
40
|
+
const p2pStore = await getP2PStore(deps.stores);
|
|
41
|
+
const stored = await p2pStore.getPendingJoinRequest(ctx.viewerDID);
|
|
32
42
|
if (stored == null) {
|
|
33
|
-
|
|
43
|
+
// Naming the way out matters: "no pending join request" reads to an
|
|
44
|
+
// operator as "the payload you were handed is bad", and they go asking
|
|
45
|
+
// for a new invite against key material that was never the problem.
|
|
46
|
+
throw new Error('The invite payload is fine, but this device has no join request awaiting it — create a new join request and ask to be invited again.');
|
|
34
47
|
}
|
|
35
48
|
const ownIdentity = deps.identity;
|
|
36
49
|
const invite = decodeInvitePayload(invitePayloadStr);
|
|
50
|
+
const pending = decodeFullJoinRequest(stored.payload);
|
|
37
51
|
const keyPackageBundle = {
|
|
38
|
-
publicPackage:
|
|
39
|
-
privatePackage:
|
|
52
|
+
publicPackage: pending.publicPackage,
|
|
53
|
+
privatePackage: pending.privatePackage,
|
|
40
54
|
ownerDID: ownIdentity.id
|
|
41
55
|
};
|
|
42
56
|
await deps.groupManager.joinGroup({
|
|
@@ -68,12 +82,33 @@ export function createJoinContext(ctx, deps) {
|
|
|
68
82
|
emitter: deps.emitter,
|
|
69
83
|
logger: deps.logger
|
|
70
84
|
});
|
|
85
|
+
// Fold the invite-carried control state (ledger, access-defaults,
|
|
86
|
+
// catalogs) so the joiner projects circles/members at join — the same
|
|
87
|
+
// seeding `joinGroup` performs. The MLS handle now exists, so the genesis
|
|
88
|
+
// anchor is readable; the anchor is read through `deps.stores` so the
|
|
89
|
+
// registry shares its connection (a separate connection deadlocks
|
|
90
|
+
// single-connection SQLite).
|
|
91
|
+
await applyInviteControlState({
|
|
92
|
+
stores: deps.stores,
|
|
93
|
+
groupID: invite.groupID,
|
|
94
|
+
accessDefaults: invite.accessDefaults,
|
|
95
|
+
catalogs: invite.catalogs,
|
|
96
|
+
hlc: deps.hlc,
|
|
97
|
+
getGroupAnchor: (gid)=>deps.registry.readHandle(gid, (handle)=>readGroupAnchor(handle), {
|
|
98
|
+
stores: deps.stores
|
|
99
|
+
}),
|
|
100
|
+
getGroupLedger: (gid)=>deps.registry.readHandle(gid, (handle)=>handle.ledger, {
|
|
101
|
+
stores: deps.stores
|
|
102
|
+
}),
|
|
103
|
+
logger: deps.logger
|
|
104
|
+
});
|
|
71
105
|
const result = await finalizeJoinedGroup({
|
|
72
106
|
stores: deps.stores,
|
|
73
107
|
emitter: deps.emitter,
|
|
74
|
-
invite
|
|
108
|
+
invite,
|
|
109
|
+
logger: deps.logger
|
|
75
110
|
});
|
|
76
|
-
|
|
111
|
+
await p2pStore.deletePendingJoinRequest(ctx.viewerDID);
|
|
77
112
|
return result;
|
|
78
113
|
}
|
|
79
114
|
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ExecutionContext } from '@kubun/engine';
|
|
2
|
+
import type { InviteAccessDefault } from '../groups/invite-payload.js';
|
|
3
|
+
import type { GroupRequestContext, PeerRequestContext, SharePeerGroupData } from '../types.js';
|
|
4
|
+
import type { ContextDeps } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* The inviter leg of the inbound dance, run on behalf of a verified caller by
|
|
7
|
+
* the `group/invite` peer handler. It designates NO circle itself: the joiner
|
|
8
|
+
* lands only in circles the inviter ALREADY designated — a `sharePeerGroup`
|
|
9
|
+
* pre-add, or an explicit `requestAddCircleMember` — which `collectInviteSeeds`
|
|
10
|
+
* snapshots from the ledger. Both of those land through an enacted commit, so
|
|
11
|
+
* by the time a designation is snapshottable here it is already durable. The
|
|
12
|
+
* invite runs as THIS device's own identity; the caller only supplies the group
|
|
13
|
+
* and its KeyPackage.
|
|
14
|
+
*/
|
|
15
|
+
export declare function serveGroupInvite(deps: ContextDeps, params: {
|
|
16
|
+
callerDID: string;
|
|
17
|
+
groupID: string;
|
|
18
|
+
joinRequest: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
invitePayload: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Apply the access-default rows a verified caller pushed for itself, run by the
|
|
24
|
+
* `group/push-control` peer handler. The source is UNTRUSTED, so the rows apply
|
|
25
|
+
* sender-bound — a row is kept only when its owner equals the authenticated
|
|
26
|
+
* caller, on top of the owner-equals-token-issuer check
|
|
27
|
+
* `applyAccessDefaultSetFrame` already enforces. A caller therefore cannot
|
|
28
|
+
* inject another owner's sharing policy.
|
|
29
|
+
*
|
|
30
|
+
* The caller must additionally be a member of the named group per THIS device's
|
|
31
|
+
* own membership view. The other remote ledger-ingest path rides the group's hub
|
|
32
|
+
* topic, whose MLS derivation is an implicit membership perimeter; this
|
|
33
|
+
* procedure is reachable by any accepted peer, so the perimeter is restated
|
|
34
|
+
* here. Fail-closed: an unknown group reads as no membership.
|
|
35
|
+
*/
|
|
36
|
+
export declare function servePushControl(deps: ContextDeps, params: {
|
|
37
|
+
callerDID: string;
|
|
38
|
+
groupID: string;
|
|
39
|
+
accessDefaults: Array<InviteAccessDefault>;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
accessDefaultsApplied: number;
|
|
42
|
+
}>;
|
|
43
|
+
export type DesignatePeerAccessParams = {
|
|
44
|
+
/**
|
|
45
|
+
* The request/settle facade, supplied rather than built here so a caller that
|
|
46
|
+
* mints an invite afterwards drives it through the same one.
|
|
47
|
+
*/
|
|
48
|
+
groupCtx: GroupRequestContext;
|
|
49
|
+
/**
|
|
50
|
+
* The designating admin: admitted to the share circle beside the peer, and the
|
|
51
|
+
* owner whose read defaults are classified.
|
|
52
|
+
*/
|
|
53
|
+
selfDID: string;
|
|
54
|
+
peerDID: string;
|
|
55
|
+
/** Share an existing group, or create a new one with this name. */
|
|
56
|
+
target: {
|
|
57
|
+
groupID: string;
|
|
58
|
+
} | {
|
|
59
|
+
name: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The calling mutation's name and the action its admin gate refuses by, so a
|
|
63
|
+
* failure inside a shared step names the operation the caller actually
|
|
64
|
+
* invoked. Without it every caller's errors would answer to whichever one
|
|
65
|
+
* happened to be written first.
|
|
66
|
+
*/
|
|
67
|
+
operation: {
|
|
68
|
+
name: string;
|
|
69
|
+
adminAction: string;
|
|
70
|
+
};
|
|
71
|
+
/** The user's exact model selection, or `null` for no send leg. */
|
|
72
|
+
sendModels: Array<string> | null;
|
|
73
|
+
receiveActivate: boolean;
|
|
74
|
+
/** See {@link SharePeerGroupParams.setReadDefaultForCircle}. */
|
|
75
|
+
setReadDefaultForCircle: (modelID: string, circleID: string) => Promise<void>;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Designate one peer's access to one group: resolve or create the group, fold
|
|
79
|
+
* the commit-hub designation, find or create the share circle, admit both DIDs,
|
|
80
|
+
* and write the catalog + read defaults the share's scope rests on.
|
|
81
|
+
*
|
|
82
|
+
* Local state only — no peer connection is read or written. Whatever follows a
|
|
83
|
+
* designation (the MLS dance, registering the sync peer) belongs to the caller,
|
|
84
|
+
* so admitting a peer without a live connection reuses this rather than copying
|
|
85
|
+
* it: an invite payload snapshots exactly what these steps wrote, so a second
|
|
86
|
+
* copy of the seeding order drifts into a joiner landing in no circle, silently.
|
|
87
|
+
*
|
|
88
|
+
* The steps are ORDER-dependent — each reads what an earlier one wrote — so the
|
|
89
|
+
* sequence below is the contract, not an arrangement.
|
|
90
|
+
*/
|
|
91
|
+
export declare function designatePeerAccess(deps: ContextDeps, params: DesignatePeerAccessParams): Promise<SharePeerGroupData>;
|
|
92
|
+
export declare function createPeerContext(ctx: ExecutionContext, deps: ContextDeps): PeerRequestContext;
|