@kubun/plugin-p2p 0.10.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 (136) hide show
  1. package/lib/context/delegation.js +130 -1
  2. package/lib/context/group.js +1319 -1
  3. package/lib/context/hub.js +150 -1
  4. package/lib/context/join.js +80 -1
  5. package/lib/context/sync.js +19 -1
  6. package/lib/context/types.d.ts +12 -3
  7. package/lib/context/types.js +28 -1
  8. package/lib/groups/admin-roster.d.ts +130 -0
  9. package/lib/groups/admin-roster.js +184 -0
  10. package/lib/groups/broadcast-codec.js +6 -1
  11. package/lib/groups/broadcast.d.ts +122 -38
  12. package/lib/groups/broadcast.js +627 -1
  13. package/lib/groups/circle-projection.d.ts +122 -0
  14. package/lib/groups/circle-projection.js +288 -0
  15. package/lib/groups/circle-reducers.d.ts +178 -0
  16. package/lib/groups/circle-reducers.js +198 -0
  17. package/lib/groups/events.d.ts +7 -2
  18. package/lib/groups/events.js +10 -1
  19. package/lib/groups/group-anchor.d.ts +63 -0
  20. package/lib/groups/group-anchor.js +107 -0
  21. package/lib/groups/group-crypto.d.ts +19 -0
  22. package/lib/groups/group-crypto.js +85 -0
  23. package/lib/groups/group-handle-registry.d.ts +69 -2
  24. package/lib/groups/group-handle-registry.js +243 -1
  25. package/lib/groups/group-handlers.d.ts +29 -0
  26. package/lib/groups/group-handlers.js +92 -0
  27. package/lib/groups/group-health-monitor.d.ts +56 -0
  28. package/lib/groups/group-health-monitor.js +139 -0
  29. package/lib/groups/group-mls.d.ts +35 -0
  30. package/lib/groups/group-mls.js +164 -0
  31. package/lib/groups/group-peer-manager.d.ts +108 -0
  32. package/lib/groups/group-peer-manager.js +344 -0
  33. package/lib/groups/group-protocols.d.ts +297 -0
  34. package/lib/groups/group-protocols.js +174 -0
  35. package/lib/groups/invite-payload.d.ts +1 -1
  36. package/lib/groups/invite-payload.js +26 -1
  37. package/lib/groups/join-utils.d.ts +1 -0
  38. package/lib/groups/join-utils.js +104 -1
  39. package/lib/groups/ledger-affected-events.d.ts +15 -0
  40. package/lib/groups/ledger-affected-events.js +96 -0
  41. package/lib/groups/ledger-entry.d.ts +37 -0
  42. package/lib/groups/ledger-entry.js +56 -0
  43. package/lib/groups/ledger-fold.d.ts +56 -0
  44. package/lib/groups/ledger-fold.js +53 -0
  45. package/lib/groups/manager.d.ts +29 -71
  46. package/lib/groups/manager.js +281 -1
  47. package/lib/groups/mls-codec.d.ts +1 -1
  48. package/lib/groups/mls-codec.js +18 -1
  49. package/lib/groups/mls-encryptor.d.ts +2 -2
  50. package/lib/groups/mls-encryptor.js +30 -1
  51. package/lib/groups/mls-group-handle.d.ts +1 -1
  52. package/lib/groups/mls-group-handle.js +10 -1
  53. package/lib/groups/mls-json.js +17 -1
  54. package/lib/groups/mls-receive-errors.d.ts +29 -0
  55. package/lib/groups/mls-receive-errors.js +42 -0
  56. package/lib/groups/mls-state.d.ts +1 -1
  57. package/lib/groups/mls-state.js +56 -1
  58. package/lib/groups/store-received-grant.d.ts +4 -1
  59. package/lib/groups/store-received-grant.js +116 -1
  60. package/lib/groups/store-received-revocation.d.ts +3 -3
  61. package/lib/groups/store-received-revocation.js +82 -1
  62. package/lib/hub/ack-backoff.d.ts +22 -0
  63. package/lib/hub/ack-backoff.js +88 -0
  64. package/lib/hub/did-observing-transport.d.ts +13 -2
  65. package/lib/hub/did-observing-transport.js +126 -1
  66. package/lib/hub/errors.d.ts +4 -8
  67. package/lib/hub/errors.js +33 -1
  68. package/lib/hub/http-client.d.ts +28 -3
  69. package/lib/hub/http-client.js +32 -1
  70. package/lib/hub/hub-like.d.ts +24 -0
  71. package/lib/hub/hub-like.js +535 -0
  72. package/lib/hub/manager.d.ts +5 -4
  73. package/lib/hub/manager.js +198 -1
  74. package/lib/hub/wiring.d.ts +28 -41
  75. package/lib/hub/wiring.js +132 -1
  76. package/lib/index.d.ts +29 -13
  77. package/lib/index.js +392 -1
  78. package/lib/protocol.d.ts +8 -1
  79. package/lib/protocol.js +251 -1
  80. package/lib/schema.d.ts +2 -1
  81. package/lib/schema.js +471 -2
  82. package/lib/sync/authorize.d.ts +25 -0
  83. package/lib/sync/authorize.js +73 -0
  84. package/lib/sync/broadcast-queue.js +183 -1
  85. package/lib/sync/broadcast-sender.js +179 -1
  86. package/lib/sync/catalog-scope.js +68 -1
  87. package/lib/sync/errors.d.ts +12 -0
  88. package/lib/sync/errors.js +19 -0
  89. package/lib/sync/forwarder.js +277 -1
  90. package/lib/sync/handlers.d.ts +3 -22
  91. package/lib/sync/handlers.js +160 -1
  92. package/lib/sync/hub-tunnel-sync-listener.d.ts +9 -3
  93. package/lib/sync/hub-tunnel-sync-listener.js +172 -1
  94. package/lib/sync/hub-tunnel-sync-provider.d.ts +14 -14
  95. package/lib/sync/hub-tunnel-sync-provider.js +64 -1
  96. package/lib/sync/merkle-apply.d.ts +5 -0
  97. package/lib/sync/merkle-apply.js +194 -1
  98. package/lib/sync/merkle-channel.d.ts +19 -0
  99. package/lib/sync/merkle-channel.js +182 -1
  100. package/lib/sync/merkle-tree.js +120 -1
  101. package/lib/sync/peer-registry.d.ts +8 -1
  102. package/lib/sync/peer-registry.js +107 -1
  103. package/lib/sync/receive-access-gate.js +24 -1
  104. package/lib/sync/scope-resolver.js +41 -1
  105. package/lib/sync/sync-client.d.ts +5 -3
  106. package/lib/sync/sync-client.js +192 -1
  107. package/lib/sync/sync-manager.d.ts +2 -2
  108. package/lib/sync/sync-manager.js +272 -1
  109. package/lib/types.d.ts +41 -0
  110. package/lib/types.js +2 -1
  111. package/lib/util/mutex.js +10 -1
  112. package/lib/utils.d.ts +5 -0
  113. package/lib/utils.js +21 -0
  114. package/package.json +48 -41
  115. package/lib/groups/broadcast-service.d.ts +0 -189
  116. package/lib/groups/broadcast-service.js +0 -1
  117. package/lib/groups/wire-frame.d.ts +0 -32
  118. package/lib/groups/wire-frame.js +0 -1
  119. package/lib/hub/connection-pool.d.ts +0 -43
  120. package/lib/hub/connection-pool.js +0 -1
  121. package/lib/hub/forward-remote-broadcast.d.ts +0 -15
  122. package/lib/hub/forward-remote-broadcast.js +0 -1
  123. package/lib/hub/group-channel.d.ts +0 -67
  124. package/lib/hub/group-channel.js +0 -1
  125. package/lib/hub/hub-connection.d.ts +0 -96
  126. package/lib/hub/hub-connection.js +0 -1
  127. package/lib/hub/receive-handler.d.ts +0 -33
  128. package/lib/hub/receive-handler.js +0 -1
  129. package/lib/hub/relay-manager.d.ts +0 -127
  130. package/lib/hub/relay-manager.js +0 -1
  131. package/lib/hub/send-handler.d.ts +0 -40
  132. package/lib/hub/send-handler.js +0 -1
  133. package/lib/hub/tunnel-inbox.d.ts +0 -20
  134. package/lib/hub/tunnel-inbox.js +0 -1
  135. package/lib/hub/wait-for-gate.d.ts +0 -14
  136. package/lib/hub/wait-for-gate.js +0 -1
@@ -0,0 +1,297 @@
1
+ import type { FromSchema } from '@sozai/schema';
2
+ /**
3
+ * App-lane group-rpc protocols carried over a group's rotating broadcast topics.
4
+ * Each peer is group-scoped (its topics encode the group), so payloads omit
5
+ * `groupID` — the handler already knows which group it serves. Loopback drop is
6
+ * automatic: the hub fans a publish to subscribers minus the sender, so a peer
7
+ * never receives its own broadcast.
8
+ *
9
+ * Procedure kinds map to the broadcast surface: `event` is fire-and-forget
10
+ * (`dispatch`); `request` is correlated (`request` for the first reply,
11
+ * `gather` for every reply within a window).
12
+ */
13
+ /**
14
+ * Control plane: membership ledger, delegation, and advisory leave. All are
15
+ * self-authenticating at the payload level (signed tokens / HLC-stamped
16
+ * records), so the lane provides ordering + delivery, not authorization.
17
+ */
18
+ export declare const controlProtocol: {
19
+ readonly 'control/ledgerEntry': {
20
+ readonly type: "event";
21
+ readonly description: "A self-signed control-ledger entry appended by its author.";
22
+ readonly data: {
23
+ readonly type: "object";
24
+ readonly properties: {
25
+ readonly token: {
26
+ readonly type: "string";
27
+ readonly description: "Signed control-ledger entry token.";
28
+ };
29
+ };
30
+ readonly required: readonly ["token"];
31
+ readonly additionalProperties: false;
32
+ };
33
+ };
34
+ readonly 'control/ledgerCatchup': {
35
+ readonly type: "request";
36
+ readonly description: "Ask current members for the group control ledger to backfill missed entries. Gathered: each member replies with its entries; the requester re-verifies every token.";
37
+ readonly param: {
38
+ readonly type: "object";
39
+ readonly properties: {};
40
+ readonly additionalProperties: false;
41
+ };
42
+ readonly result: {
43
+ readonly type: "object";
44
+ readonly properties: {
45
+ readonly entries: {
46
+ readonly type: "array";
47
+ readonly items: {
48
+ readonly type: "string";
49
+ };
50
+ readonly description: "Signed control-ledger entry tokens.";
51
+ };
52
+ };
53
+ readonly required: readonly ["entries"];
54
+ readonly additionalProperties: false;
55
+ };
56
+ };
57
+ readonly 'control/delegationShare': {
58
+ readonly type: "event";
59
+ readonly description: "Distribute a minted document/write capability token to group co-members.";
60
+ readonly data: {
61
+ readonly type: "object";
62
+ readonly properties: {
63
+ readonly token: {
64
+ readonly type: "string";
65
+ readonly description: "Stringified capability JWT.";
66
+ };
67
+ readonly hlc: {
68
+ readonly type: "string";
69
+ readonly description: "Grantor-stamped HLC, mirroring the issued row.";
70
+ };
71
+ };
72
+ readonly required: readonly ["token", "hlc"];
73
+ readonly additionalProperties: false;
74
+ };
75
+ };
76
+ readonly 'control/delegationRevoke': {
77
+ readonly type: "event";
78
+ readonly description: "Distribute a signed revocation record for a previously minted capability.";
79
+ readonly data: {
80
+ readonly type: "object";
81
+ readonly properties: {
82
+ readonly token: {
83
+ readonly type: "string";
84
+ readonly description: "Stringified signed revocation JWT.";
85
+ };
86
+ readonly hlc: {
87
+ readonly type: "string";
88
+ readonly description: "Revoker-stamped HLC, mirroring the stored row.";
89
+ };
90
+ };
91
+ readonly required: readonly ["token", "hlc"];
92
+ readonly additionalProperties: false;
93
+ };
94
+ };
95
+ readonly 'control/groupLeaveRequest': {
96
+ readonly type: "event";
97
+ readonly description: "Advisory voluntary-leave notice. Not authoritative — an admin must issue a real removeMember; receivers surface it as an event and never tombstone on it.";
98
+ readonly data: {
99
+ readonly type: "object";
100
+ readonly properties: {
101
+ readonly memberDID: {
102
+ readonly type: "string";
103
+ readonly description: "DID of the member announcing departure.";
104
+ };
105
+ readonly hlc: {
106
+ readonly type: "string";
107
+ };
108
+ };
109
+ readonly required: readonly ["memberDID", "hlc"];
110
+ readonly additionalProperties: false;
111
+ };
112
+ };
113
+ };
114
+ /**
115
+ * Sync plane: document mutation broadcasts. Each entry carries a signed mutation
116
+ * JWT the receiver verifies before applying, so the lane is transport only.
117
+ */
118
+ export declare const syncProtocol: {
119
+ readonly 'sync/mutationApply': {
120
+ readonly type: "event";
121
+ readonly description: "Broadcast a batch of signed document mutations to group members.";
122
+ readonly data: {
123
+ readonly type: "object";
124
+ readonly properties: {
125
+ readonly entries: {
126
+ readonly type: "array";
127
+ readonly items: {
128
+ readonly type: "object";
129
+ readonly properties: {
130
+ readonly mutationJWT: {
131
+ readonly type: "string";
132
+ };
133
+ readonly docID: {
134
+ readonly type: "string";
135
+ };
136
+ readonly version: {
137
+ readonly type: "string";
138
+ readonly description: "HLC string identifying this version.";
139
+ };
140
+ readonly modelID: {
141
+ readonly type: "string";
142
+ };
143
+ };
144
+ readonly required: readonly ["mutationJWT", "docID", "version", "modelID"];
145
+ readonly additionalProperties: false;
146
+ };
147
+ };
148
+ };
149
+ readonly required: readonly ["entries"];
150
+ readonly additionalProperties: false;
151
+ };
152
+ };
153
+ };
154
+ export type ControlProtocol = typeof controlProtocol;
155
+ export type SyncProtocol = typeof syncProtocol;
156
+ export type LedgerEntryData = FromSchema<(typeof controlProtocol)['control/ledgerEntry']['data']>;
157
+ export type LedgerCatchupResult = FromSchema<(typeof controlProtocol)['control/ledgerCatchup']['result']>;
158
+ export type DelegationShareData = FromSchema<(typeof controlProtocol)['control/delegationShare']['data']>;
159
+ export type DelegationRevokeData = FromSchema<(typeof controlProtocol)['control/delegationRevoke']['data']>;
160
+ export type GroupLeaveRequestData = FromSchema<(typeof controlProtocol)['control/groupLeaveRequest']['data']>;
161
+ export type MutationApplyData = FromSchema<(typeof syncProtocol)['sync/mutationApply']['data']>;
162
+ /** The two app-lane protocols, keyed for `createGroupPeer({ protocols })`. */
163
+ export declare const groupProtocols: {
164
+ control: {
165
+ readonly 'control/ledgerEntry': {
166
+ readonly type: "event";
167
+ readonly description: "A self-signed control-ledger entry appended by its author.";
168
+ readonly data: {
169
+ readonly type: "object";
170
+ readonly properties: {
171
+ readonly token: {
172
+ readonly type: "string";
173
+ readonly description: "Signed control-ledger entry token.";
174
+ };
175
+ };
176
+ readonly required: readonly ["token"];
177
+ readonly additionalProperties: false;
178
+ };
179
+ };
180
+ readonly 'control/ledgerCatchup': {
181
+ readonly type: "request";
182
+ readonly description: "Ask current members for the group control ledger to backfill missed entries. Gathered: each member replies with its entries; the requester re-verifies every token.";
183
+ readonly param: {
184
+ readonly type: "object";
185
+ readonly properties: {};
186
+ readonly additionalProperties: false;
187
+ };
188
+ readonly result: {
189
+ readonly type: "object";
190
+ readonly properties: {
191
+ readonly entries: {
192
+ readonly type: "array";
193
+ readonly items: {
194
+ readonly type: "string";
195
+ };
196
+ readonly description: "Signed control-ledger entry tokens.";
197
+ };
198
+ };
199
+ readonly required: readonly ["entries"];
200
+ readonly additionalProperties: false;
201
+ };
202
+ };
203
+ readonly 'control/delegationShare': {
204
+ readonly type: "event";
205
+ readonly description: "Distribute a minted document/write capability token to group co-members.";
206
+ readonly data: {
207
+ readonly type: "object";
208
+ readonly properties: {
209
+ readonly token: {
210
+ readonly type: "string";
211
+ readonly description: "Stringified capability JWT.";
212
+ };
213
+ readonly hlc: {
214
+ readonly type: "string";
215
+ readonly description: "Grantor-stamped HLC, mirroring the issued row.";
216
+ };
217
+ };
218
+ readonly required: readonly ["token", "hlc"];
219
+ readonly additionalProperties: false;
220
+ };
221
+ };
222
+ readonly 'control/delegationRevoke': {
223
+ readonly type: "event";
224
+ readonly description: "Distribute a signed revocation record for a previously minted capability.";
225
+ readonly data: {
226
+ readonly type: "object";
227
+ readonly properties: {
228
+ readonly token: {
229
+ readonly type: "string";
230
+ readonly description: "Stringified signed revocation JWT.";
231
+ };
232
+ readonly hlc: {
233
+ readonly type: "string";
234
+ readonly description: "Revoker-stamped HLC, mirroring the stored row.";
235
+ };
236
+ };
237
+ readonly required: readonly ["token", "hlc"];
238
+ readonly additionalProperties: false;
239
+ };
240
+ };
241
+ readonly 'control/groupLeaveRequest': {
242
+ readonly type: "event";
243
+ readonly description: "Advisory voluntary-leave notice. Not authoritative — an admin must issue a real removeMember; receivers surface it as an event and never tombstone on it.";
244
+ readonly data: {
245
+ readonly type: "object";
246
+ readonly properties: {
247
+ readonly memberDID: {
248
+ readonly type: "string";
249
+ readonly description: "DID of the member announcing departure.";
250
+ };
251
+ readonly hlc: {
252
+ readonly type: "string";
253
+ };
254
+ };
255
+ readonly required: readonly ["memberDID", "hlc"];
256
+ readonly additionalProperties: false;
257
+ };
258
+ };
259
+ };
260
+ sync: {
261
+ readonly 'sync/mutationApply': {
262
+ readonly type: "event";
263
+ readonly description: "Broadcast a batch of signed document mutations to group members.";
264
+ readonly data: {
265
+ readonly type: "object";
266
+ readonly properties: {
267
+ readonly entries: {
268
+ readonly type: "array";
269
+ readonly items: {
270
+ readonly type: "object";
271
+ readonly properties: {
272
+ readonly mutationJWT: {
273
+ readonly type: "string";
274
+ };
275
+ readonly docID: {
276
+ readonly type: "string";
277
+ };
278
+ readonly version: {
279
+ readonly type: "string";
280
+ readonly description: "HLC string identifying this version.";
281
+ };
282
+ readonly modelID: {
283
+ readonly type: "string";
284
+ };
285
+ };
286
+ readonly required: readonly ["mutationJWT", "docID", "version", "modelID"];
287
+ readonly additionalProperties: false;
288
+ };
289
+ };
290
+ };
291
+ readonly required: readonly ["entries"];
292
+ readonly additionalProperties: false;
293
+ };
294
+ };
295
+ };
296
+ };
297
+ export type GroupProtocols = typeof groupProtocols;
@@ -0,0 +1,174 @@
1
+ import { defineGroupProtocol } from '@kumiai/rpc';
2
+ /**
3
+ * App-lane group-rpc protocols carried over a group's rotating broadcast topics.
4
+ * Each peer is group-scoped (its topics encode the group), so payloads omit
5
+ * `groupID` — the handler already knows which group it serves. Loopback drop is
6
+ * automatic: the hub fans a publish to subscribers minus the sender, so a peer
7
+ * never receives its own broadcast.
8
+ *
9
+ * Procedure kinds map to the broadcast surface: `event` is fire-and-forget
10
+ * (`dispatch`); `request` is correlated (`request` for the first reply,
11
+ * `gather` for every reply within a window).
12
+ */ /**
13
+ * Control plane: membership ledger, delegation, and advisory leave. All are
14
+ * self-authenticating at the payload level (signed tokens / HLC-stamped
15
+ * records), so the lane provides ordering + delivery, not authorization.
16
+ */ export const controlProtocol = defineGroupProtocol({
17
+ 'control/ledgerEntry': {
18
+ type: 'event',
19
+ description: 'A self-signed control-ledger entry appended by its author.',
20
+ data: {
21
+ type: 'object',
22
+ properties: {
23
+ token: {
24
+ type: 'string',
25
+ description: 'Signed control-ledger entry token.'
26
+ }
27
+ },
28
+ required: [
29
+ 'token'
30
+ ],
31
+ additionalProperties: false
32
+ }
33
+ },
34
+ 'control/ledgerCatchup': {
35
+ type: 'request',
36
+ description: 'Ask current members for the group control ledger to backfill missed entries. Gathered: each member replies with its entries; the requester re-verifies every token.',
37
+ param: {
38
+ type: 'object',
39
+ properties: {},
40
+ additionalProperties: false
41
+ },
42
+ result: {
43
+ type: 'object',
44
+ properties: {
45
+ entries: {
46
+ type: 'array',
47
+ items: {
48
+ type: 'string'
49
+ },
50
+ description: 'Signed control-ledger entry tokens.'
51
+ }
52
+ },
53
+ required: [
54
+ 'entries'
55
+ ],
56
+ additionalProperties: false
57
+ }
58
+ },
59
+ 'control/delegationShare': {
60
+ type: 'event',
61
+ description: 'Distribute a minted document/write capability token to group co-members.',
62
+ data: {
63
+ type: 'object',
64
+ properties: {
65
+ token: {
66
+ type: 'string',
67
+ description: 'Stringified capability JWT.'
68
+ },
69
+ hlc: {
70
+ type: 'string',
71
+ description: 'Grantor-stamped HLC, mirroring the issued row.'
72
+ }
73
+ },
74
+ required: [
75
+ 'token',
76
+ 'hlc'
77
+ ],
78
+ additionalProperties: false
79
+ }
80
+ },
81
+ 'control/delegationRevoke': {
82
+ type: 'event',
83
+ description: 'Distribute a signed revocation record for a previously minted capability.',
84
+ data: {
85
+ type: 'object',
86
+ properties: {
87
+ token: {
88
+ type: 'string',
89
+ description: 'Stringified signed revocation JWT.'
90
+ },
91
+ hlc: {
92
+ type: 'string',
93
+ description: 'Revoker-stamped HLC, mirroring the stored row.'
94
+ }
95
+ },
96
+ required: [
97
+ 'token',
98
+ 'hlc'
99
+ ],
100
+ additionalProperties: false
101
+ }
102
+ },
103
+ 'control/groupLeaveRequest': {
104
+ type: 'event',
105
+ description: 'Advisory voluntary-leave notice. Not authoritative — an admin must issue a real removeMember; receivers surface it as an event and never tombstone on it.',
106
+ data: {
107
+ type: 'object',
108
+ properties: {
109
+ memberDID: {
110
+ type: 'string',
111
+ description: 'DID of the member announcing departure.'
112
+ },
113
+ hlc: {
114
+ type: 'string'
115
+ }
116
+ },
117
+ required: [
118
+ 'memberDID',
119
+ 'hlc'
120
+ ],
121
+ additionalProperties: false
122
+ }
123
+ }
124
+ });
125
+ /**
126
+ * Sync plane: document mutation broadcasts. Each entry carries a signed mutation
127
+ * JWT the receiver verifies before applying, so the lane is transport only.
128
+ */ export const syncProtocol = defineGroupProtocol({
129
+ 'sync/mutationApply': {
130
+ type: 'event',
131
+ description: 'Broadcast a batch of signed document mutations to group members.',
132
+ data: {
133
+ type: 'object',
134
+ properties: {
135
+ entries: {
136
+ type: 'array',
137
+ items: {
138
+ type: 'object',
139
+ properties: {
140
+ mutationJWT: {
141
+ type: 'string'
142
+ },
143
+ docID: {
144
+ type: 'string'
145
+ },
146
+ version: {
147
+ type: 'string',
148
+ description: 'HLC string identifying this version.'
149
+ },
150
+ modelID: {
151
+ type: 'string'
152
+ }
153
+ },
154
+ required: [
155
+ 'mutationJWT',
156
+ 'docID',
157
+ 'version',
158
+ 'modelID'
159
+ ],
160
+ additionalProperties: false
161
+ }
162
+ }
163
+ },
164
+ required: [
165
+ 'entries'
166
+ ],
167
+ additionalProperties: false
168
+ }
169
+ }
170
+ });
171
+ /** The two app-lane protocols, keyed for `createGroupPeer({ protocols })`. */ export const groupProtocols = {
172
+ control: controlProtocol,
173
+ sync: syncProtocol
174
+ };
@@ -1,4 +1,4 @@
1
- import type { Invite, KeyPackageBundle } from '@enkaku/group';
1
+ import type { Invite, KeyPackageBundle } from '@kumiai/mls';
2
2
  export type JoinRequestPayload = {
3
3
  did: string;
4
4
  publicPackage: KeyPackageBundle['publicPackage'];
@@ -1 +1,26 @@
1
- import{fromB64 as e,toB64 as n}from"@enkaku/codec";import{replacer as o,reviver as t}from"./mls-json.js";export function encodeJoinRequest(e){let t=JSON.stringify(e,o);return n(new TextEncoder().encode(t))}export function decodeJoinRequest(n){return JSON.parse(new TextDecoder().decode(e(n)),t)}export function encodeInvitePayload(e){let t=JSON.stringify(e,o);return n(new TextEncoder().encode(t))}export function decodeInvitePayload(n){return JSON.parse(new TextDecoder().decode(e(n)),t)}export function encodeFullJoinRequest(e){let t=JSON.stringify(e,o);return n(new TextEncoder().encode(t))}export function decodeFullJoinRequest(n){return JSON.parse(new TextDecoder().decode(e(n)),t)}
1
+ import { fromB64, toB64 } from '@sozai/codec';
2
+ import { replacer, reviver } from './mls-json.js';
3
+ export function encodeJoinRequest(payload) {
4
+ const json = JSON.stringify(payload, replacer);
5
+ return toB64(new TextEncoder().encode(json));
6
+ }
7
+ export function decodeJoinRequest(encoded) {
8
+ const json = new TextDecoder().decode(fromB64(encoded));
9
+ return JSON.parse(json, reviver);
10
+ }
11
+ export function encodeInvitePayload(payload) {
12
+ const json = JSON.stringify(payload, replacer);
13
+ return toB64(new TextEncoder().encode(json));
14
+ }
15
+ export function decodeInvitePayload(encoded) {
16
+ const json = new TextDecoder().decode(fromB64(encoded));
17
+ return JSON.parse(json, reviver);
18
+ }
19
+ export function encodeFullJoinRequest(payload) {
20
+ const json = JSON.stringify(payload, replacer);
21
+ return toB64(new TextEncoder().encode(json));
22
+ }
23
+ export function decodeFullJoinRequest(encoded) {
24
+ const json = new TextDecoder().decode(fromB64(encoded));
25
+ return JSON.parse(json, reviver);
26
+ }
@@ -9,6 +9,7 @@ export type FinalizeJoinedGroupParams = {
9
9
  invite: {
10
10
  groupID: string;
11
11
  };
12
+ logger?: Logger;
12
13
  };
13
14
  export declare function finalizeJoinedGroup(params: FinalizeJoinedGroupParams): Promise<{
14
15
  group: GroupData | null;
@@ -1 +1,104 @@
1
- import{HLC as e}from"@kubun/hlc";import{getP2PStore as t}from"@kubun/store-p2p";import{toISO as r}from"../context/types.js";import{storeReceivedGrant as n}from"./store-received-grant.js";import{storeReceivedRevocation as i}from"./store-received-revocation.js";export async function finalizeJoinedGroup(e){let{stores:n,emitter:i,invite:o}=e,a=await t(n),l=await a.getGroup(o.groupID),p=null!=l?{id:l.id,name:l.name,description:l.description,createdBy:l.created_by,createdAt:r(l.created_at)}:null;return null!=p&&await i.emit("groupJoined",p),{group:p}}export async function applyInviteGrants(r){let{stores:i,selfDID:o,groupID:a,grants:l,hlc:p,emitter:u,logger:c}=r;if(null==l||0===l.length)return 0;let s=await t(i);return(await Promise.all(l.map(t=>n({p2pStore:s,token:t,groupID:a,hlc:e.serialize(p.now()),selfDID:o,...null!=u?{emitter:u}:{},...null!=c?{logger:c}:{}})))).reduce((e,t)=>e+ +!!t,0)}export async function applyInviteRevocations(r){let{stores:n,groupID:o,revocations:a,hlc:l,selfDID:p,emitter:u,logger:c}=r;if(null==a||0===a.length)return 0;let s=await t(n);return(await Promise.all(a.map(t=>i({p2pStore:s,token:t,groupID:o,hlc:e.serialize(l.now()),selfDID:p,...null!=u?{emitter:u}:{},...null!=c?{logger:c}:{}})))).reduce((e,t)=>e+ +!!t,0)}
1
+ import { HLC as HLCClass } from '@kubun/hlc';
2
+ import { getDelegationStore } from '@kubun/store-delegation';
3
+ import { getP2PStore } from '@kubun/store-p2p';
4
+ import { toISO } from '../context/types.js';
5
+ import { storeReceivedGrant } from './store-received-grant.js';
6
+ import { storeReceivedRevocation } from './store-received-revocation.js';
7
+ export async function finalizeJoinedGroup(params) {
8
+ const { stores, emitter, invite, logger } = params;
9
+ const store = await getP2PStore(stores);
10
+ const groupRow = await store.getGroup(invite.groupID);
11
+ const joinedGroupData = groupRow != null ? {
12
+ id: groupRow.id,
13
+ name: groupRow.name,
14
+ description: groupRow.description,
15
+ createdBy: groupRow.created_by,
16
+ createdAt: toISO(groupRow.created_at)
17
+ } : null;
18
+ if (joinedGroupData != null) {
19
+ // Defer past the outermost commit (`stores` is that tx): the `groupJoined`
20
+ // listener reads the P2P store on the main connection (deadlocks single-conn
21
+ // SQLite / uncommitted on PG).
22
+ stores.onCommit(()=>{
23
+ emitter.emit('groupJoined', joinedGroupData).catch((error)=>{
24
+ logger?.error('groupJoined emit failed', {
25
+ groupID: invite.groupID,
26
+ error
27
+ });
28
+ });
29
+ });
30
+ }
31
+ return {
32
+ group: joinedGroupData
33
+ };
34
+ }
35
+ /**
36
+ * Apply invite-bootstrap grants after a join completes. Each token is verified
37
+ * and, when addressed to the joining device, stored as a held row so the
38
+ * engine's auto-attach can use it on the very first mutation — before any group
39
+ * broadcast arrives.
40
+ *
41
+ * No grantor HLC travels in the invite (it carries plain tokens, not the
42
+ * grantor's issued rows), so the joiner stamps a fresh HLC of its own at apply
43
+ * time. This is consistent with how every other join-time row the joiner
44
+ * materializes is locally stamped.
45
+ *
46
+ * Returns the number of grants that resulted in a stored held row.
47
+ */ export async function applyInviteGrants(params) {
48
+ const { stores, selfDID, groupID, grants, hlc, emitter, logger } = params;
49
+ if (grants == null || grants.length === 0) {
50
+ return 0;
51
+ }
52
+ const [store, delegationStore] = await Promise.all([
53
+ getP2PStore(stores),
54
+ getDelegationStore(stores)
55
+ ]);
56
+ const results = await Promise.all(grants.map((token)=>storeReceivedGrant({
57
+ delegationStore,
58
+ p2pStore: store,
59
+ token,
60
+ groupID,
61
+ hlc: HLCClass.serialize(hlc.now()),
62
+ selfDID,
63
+ ...emitter != null ? {
64
+ emitter
65
+ } : {},
66
+ ...logger != null ? {
67
+ logger
68
+ } : {}
69
+ })));
70
+ return results.reduce((count, applied)=>count + (applied ? 1 : 0), 0);
71
+ }
72
+ /**
73
+ * Apply invite-bootstrap revocations after a join completes. Each token is
74
+ * verified and stored — cap-known locally with matching `iss` yields a
75
+ * verified row, cap-unknown yields a pending row that the joiner will
76
+ * cross-check when the cap later arrives.
77
+ *
78
+ * The inviter's caller is responsible for filtering to verified revocations
79
+ * only; pending revocations do not travel via the invite envelope. The joiner
80
+ * stamps a fresh HLC since the inviter's HLC for these rows is not in the
81
+ * payload.
82
+ *
83
+ * Returns the number of revocations that resulted in a stored row.
84
+ */ export async function applyInviteRevocations(params) {
85
+ const { stores, groupID, revocations, hlc, selfDID, emitter, logger } = params;
86
+ if (revocations == null || revocations.length === 0) {
87
+ return 0;
88
+ }
89
+ const delegationStore = await getDelegationStore(stores);
90
+ const results = await Promise.all(revocations.map((token)=>storeReceivedRevocation({
91
+ delegationStore,
92
+ token,
93
+ groupID,
94
+ hlc: HLCClass.serialize(hlc.now()),
95
+ selfDID,
96
+ ...emitter != null ? {
97
+ emitter
98
+ } : {},
99
+ ...logger != null ? {
100
+ logger
101
+ } : {}
102
+ })));
103
+ return results.reduce((count, applied)=>count + (applied ? 1 : 0), 0);
104
+ }
@@ -0,0 +1,15 @@
1
+ import type { ProcessBroadcastResult } from './broadcast.js';
2
+ import type { P2PEventEmitter } from './events.js';
3
+ /**
4
+ * Emit the local `P2PEventEmitter` events for a remote-driven control-ledger
5
+ * entry that a receiving peer just applied, so GraphQL subscribers see
6
+ * remote circle/group changes live — the same events a local producer fires.
7
+ *
8
+ * Only `ledger:entry` projections surface as `affected`; every other applied
9
+ * message (delegation grant/revoke, advisory leave) already emits its own event
10
+ * from inside `processBroadcast`, so this covers exactly the circle/group
11
+ * projection rows the apply core returns rather than emits. The payloads are
12
+ * built from `affected.row`, which `processBroadcast` snapshots at the right
13
+ * moment (after-state for create/change, before-state for delete/remove).
14
+ */
15
+ export declare function emitLedgerAffectedEvents(emitter: P2PEventEmitter, result: ProcessBroadcastResult): Promise<void>;