@kubun/plugin-p2p 0.8.3 → 0.10.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 (88) hide show
  1. package/lib/context/delegation.d.ts +4 -0
  2. package/lib/context/delegation.js +1 -0
  3. package/lib/context/group.js +1 -1
  4. package/lib/context/hub.d.ts +4 -0
  5. package/lib/context/hub.js +1 -0
  6. package/lib/context/join.js +1 -1
  7. package/lib/context/types.d.ts +28 -2
  8. package/lib/groups/broadcast-service.d.ts +130 -17
  9. package/lib/groups/broadcast-service.js +1 -1
  10. package/lib/groups/broadcast.d.ts +162 -5
  11. package/lib/groups/broadcast.js +1 -1
  12. package/lib/groups/events.d.ts +26 -5
  13. package/lib/groups/events.js +1 -1
  14. package/lib/groups/group-handle-registry.d.ts +90 -0
  15. package/lib/groups/group-handle-registry.js +1 -0
  16. package/lib/groups/invite-payload.d.ts +21 -1
  17. package/lib/groups/join-utils.d.ts +68 -2
  18. package/lib/groups/join-utils.js +1 -1
  19. package/lib/groups/manager.d.ts +26 -18
  20. package/lib/groups/manager.js +1 -1
  21. package/lib/groups/mls-codec.d.ts +7 -0
  22. package/lib/groups/mls-codec.js +1 -0
  23. package/lib/groups/mls-encryptor.d.ts +25 -0
  24. package/lib/groups/mls-encryptor.js +1 -0
  25. package/lib/groups/store-received-grant.d.ts +47 -0
  26. package/lib/groups/store-received-grant.js +1 -0
  27. package/lib/groups/store-received-revocation.d.ts +46 -0
  28. package/lib/groups/store-received-revocation.js +1 -0
  29. package/lib/groups/wire-frame.d.ts +32 -0
  30. package/lib/groups/wire-frame.js +1 -0
  31. package/lib/hub/connection-pool.d.ts +24 -0
  32. package/lib/hub/connection-pool.js +1 -1
  33. package/lib/hub/did-observing-transport.d.ts +64 -0
  34. package/lib/hub/did-observing-transport.js +1 -0
  35. package/lib/hub/errors.d.ts +28 -0
  36. package/lib/hub/errors.js +1 -0
  37. package/lib/hub/forward-remote-broadcast.d.ts +15 -0
  38. package/lib/hub/forward-remote-broadcast.js +1 -0
  39. package/lib/hub/group-channel.d.ts +37 -21
  40. package/lib/hub/group-channel.js +1 -1
  41. package/lib/hub/http-client.d.ts +17 -0
  42. package/lib/hub/http-client.js +1 -0
  43. package/lib/hub/hub-connection.d.ts +96 -0
  44. package/lib/hub/hub-connection.js +1 -0
  45. package/lib/hub/manager.d.ts +117 -0
  46. package/lib/hub/manager.js +1 -0
  47. package/lib/hub/receive-handler.d.ts +3 -6
  48. package/lib/hub/receive-handler.js +1 -1
  49. package/lib/hub/relay-manager.d.ts +92 -2
  50. package/lib/hub/relay-manager.js +1 -1
  51. package/lib/hub/send-handler.d.ts +28 -16
  52. package/lib/hub/send-handler.js +1 -1
  53. package/lib/hub/tunnel-inbox.d.ts +20 -0
  54. package/lib/hub/tunnel-inbox.js +1 -0
  55. package/lib/hub/wait-for-gate.d.ts +14 -0
  56. package/lib/hub/wait-for-gate.js +1 -0
  57. package/lib/hub/wiring.d.ts +85 -0
  58. package/lib/hub/wiring.js +1 -0
  59. package/lib/index.d.ts +102 -7
  60. package/lib/index.js +1 -1
  61. package/lib/schema.d.ts +2 -2
  62. package/lib/schema.js +113 -21
  63. package/lib/sync/broadcast-queue.d.ts +59 -0
  64. package/lib/sync/broadcast-queue.js +1 -0
  65. package/lib/sync/broadcast-sender.d.ts +52 -0
  66. package/lib/sync/broadcast-sender.js +1 -0
  67. package/lib/sync/forwarder.d.ts +97 -0
  68. package/lib/sync/forwarder.js +1 -0
  69. package/lib/sync/handlers.d.ts +20 -1
  70. package/lib/sync/handlers.js +1 -1
  71. package/lib/sync/hub-tunnel-sync-listener.d.ts +24 -0
  72. package/lib/sync/hub-tunnel-sync-listener.js +1 -0
  73. package/lib/sync/hub-tunnel-sync-provider.d.ts +36 -0
  74. package/lib/sync/hub-tunnel-sync-provider.js +1 -0
  75. package/lib/sync/merkle-apply.d.ts +41 -0
  76. package/lib/sync/merkle-apply.js +1 -1
  77. package/lib/sync/merkle-channel.d.ts +15 -0
  78. package/lib/sync/merkle-channel.js +1 -1
  79. package/lib/sync/receive-access-gate.d.ts +36 -0
  80. package/lib/sync/receive-access-gate.js +1 -0
  81. package/lib/sync/scope-resolver.d.ts +32 -0
  82. package/lib/sync/scope-resolver.js +1 -0
  83. package/lib/sync/sync-manager.d.ts +10 -0
  84. package/lib/sync/sync-manager.js +1 -1
  85. package/lib/types.d.ts +151 -1
  86. package/lib/util/mutex.d.ts +4 -0
  87. package/lib/util/mutex.js +1 -0
  88. package/package.json +40 -37
package/lib/types.d.ts CHANGED
@@ -3,6 +3,15 @@ import type { SyncDirection, SyncProtocol } from './protocol.js';
3
3
  import type { PeerConfig, PeerConfigWithID } from './sync/peer-registry.js';
4
4
  import type { SyncScope } from './sync/sync-client.js';
5
5
  import type { SyncEvent, SyncStatus } from './sync/sync-manager.js';
6
+ /**
7
+ * Receiver storage mode for incoming peer mutations.
8
+ * - `'persist'` — store every doc that passes catalog/group checks. Access
9
+ * enforced at query time; unreadable docs remain in DB but filtered.
10
+ * - `'drop'` — apply read-access check at receive time using the local
11
+ * peer's own DID as viewer. Mutations the local peer cannot read are
12
+ * not persisted.
13
+ */
14
+ export type StoreUnreadableMode = 'persist' | 'drop';
6
15
  export type GroupData = {
7
16
  id: string;
8
17
  name: string;
@@ -37,6 +46,14 @@ export type CatalogData = {
37
46
  filterCriteria: string;
38
47
  createdAt: string;
39
48
  };
49
+ export type HubData = {
50
+ id: string;
51
+ label: string | null;
52
+ url: string;
53
+ serverDID: string | null;
54
+ createdAt: string;
55
+ updatedAt: string | null;
56
+ };
40
57
  export type InviteToGroupData = {
41
58
  invitePayload: string;
42
59
  groupID: string;
@@ -76,6 +93,10 @@ export type GroupRequestContext = {
76
93
  create: (input: {
77
94
  name: string;
78
95
  description?: string;
96
+ hubs?: Array<{
97
+ url: string;
98
+ serverDID?: string | null;
99
+ }>;
79
100
  }) => Promise<GroupData>;
80
101
  list: () => Promise<Array<GroupData>>;
81
102
  get: (id: string) => Promise<GroupData | null>;
@@ -94,7 +115,15 @@ export type GroupRequestContext = {
94
115
  filterCriteria: string;
95
116
  }) => Promise<CatalogData>;
96
117
  listCatalogs: (ownerDID?: string) => Promise<Array<CatalogData>>;
97
- invite: (groupID: string, joinRequest: string) => Promise<InviteToGroupData>;
118
+ /**
119
+ * Build an invite payload for a join request.
120
+ *
121
+ * `grants` are stringified write-capability JWTs the caller wants the joiner
122
+ * to hold immediately on join. `revocations` are signed revocation JWTs the
123
+ * caller wants the joiner to apply immediately — only verified ones travel;
124
+ * pending revocations (cap not yet known by the inviter) do not.
125
+ */
126
+ invite: (groupID: string, joinRequest: string, grants?: Array<string>, revocations?: Array<string>) => Promise<InviteToGroupData>;
98
127
  join: (invitePayload: string, joinRequestPayload: string) => Promise<JoinGroupData>;
99
128
  leave: (groupID: string) => Promise<LeaveGroupData>;
100
129
  removeMember: (groupID: string, memberDID: string) => Promise<RemoveGroupMemberData>;
@@ -108,6 +137,53 @@ export type GroupRequestContext = {
108
137
  deleteCatalog: (catalogID: string) => Promise<DeleteCatalogData>;
109
138
  deleteCircle: (circleID: string) => Promise<DeleteCircleData>;
110
139
  removeCircleMember: (circleID: string, memberDID: string) => Promise<RemoveCircleMemberData>;
140
+ /**
141
+ * Mint a `document/write` capability granting `to` write access on resources
142
+ * matching `res`. Token is stored grantor-side, broadcast to the group, and
143
+ * returned for direct delivery.
144
+ *
145
+ * `res` is a URN. Most-specific wins; broader URNs grant strictly more:
146
+ * - `urn:kubun:document:<docID>` — single doc
147
+ * - `urn:kubun:model:<modelID>` — every doc of that model owned by the grantor
148
+ * - `urn:kubun:model:<interfaceID>` — every doc of every model implementing
149
+ * the interface (footgun: a grant on a widely-implemented interface like
150
+ * `Owned` or `Timestamped` becomes a near-wildcard)
151
+ * - `urn:kubun:user:<DID>` — every doc owned by that DID (the grantor)
152
+ * - `*` — every doc the grantor owns, present and future
153
+ *
154
+ * Prefer the narrowest URN that satisfies the use case. Broad grants combine
155
+ * with the long default `exp` (30 days) to expand the blast radius of a
156
+ * leaked or misdirected token.
157
+ */
158
+ grantWriteCapability: (params: {
159
+ to: string;
160
+ res: string;
161
+ groupID: string;
162
+ expiresIn?: number;
163
+ }) => Promise<string>;
164
+ /**
165
+ * Revoke a previously-granted `document/write` capability by its `jti`.
166
+ *
167
+ * Revocation is binary: once a peer learns of the revocation, every
168
+ * mutation that authenticates via this `jti` is denied. The check is
169
+ * reactive, not retroactive — mutations already applied locally stay
170
+ * applied; only future writes carrying the revoked `jti` are gated.
171
+ *
172
+ * Only the original capability issuer may revoke it. The resolver looks up
173
+ * the capability locally and rejects:
174
+ * - `REVOCATION_CAP_UNKNOWN` when no row matches the `jti` on this peer
175
+ * (multi-device-grantor case, where the issuing device is not the one
176
+ * calling `revokeCapability`, is not yet supported).
177
+ * - `REVOCATION_UNAUTHORIZED` when the viewer is not the capability's
178
+ * issuer.
179
+ *
180
+ * Returns the boolean reported by the store: `true` when the revocation
181
+ * row was newly written (or materially changed), `false` on an idempotent
182
+ * no-op (already revoked at an equal or newer HLC).
183
+ */
184
+ revokeCapability: (params: {
185
+ jti: string;
186
+ }) => Promise<boolean>;
111
187
  };
112
188
  export type SyncRequestContext = {
113
189
  addPeer: (config: PeerConfig) => Promise<void>;
@@ -123,10 +199,79 @@ export type P2PJoinRequestContext = {
123
199
  group: GroupData | null;
124
200
  }>;
125
201
  };
202
+ export type CreateHubInput = {
203
+ url: string;
204
+ label?: string | null;
205
+ serverDID?: string | null;
206
+ };
207
+ export type UpdateHubInput = {
208
+ id: string;
209
+ url?: string;
210
+ label?: string | null;
211
+ serverDID?: string | null;
212
+ };
213
+ export type DeleteHubData = {
214
+ success: boolean;
215
+ boundGroupIDs: Array<string>;
216
+ };
217
+ export type HubRequestContext = {
218
+ list: () => Promise<Array<HubData>>;
219
+ get: (id: string) => Promise<HubData | null>;
220
+ create: (input: CreateHubInput) => Promise<HubData>;
221
+ update: (input: UpdateHubInput) => Promise<HubData>;
222
+ delete: (id: string, force?: boolean) => Promise<DeleteHubData>;
223
+ bind: (params: {
224
+ hubID: string;
225
+ groupID: string;
226
+ }) => Promise<boolean>;
227
+ unbind: (params: {
228
+ hubID: string;
229
+ groupID: string;
230
+ }) => Promise<boolean>;
231
+ listByGroup: (groupID: string) => Promise<Array<HubData>>;
232
+ listGroups: (hubID: string) => Promise<Array<GroupData>>;
233
+ };
234
+ export type DelegationData = {
235
+ jwt: string;
236
+ jti: string;
237
+ grantor: string;
238
+ audience: string;
239
+ resource: string;
240
+ exp: number;
241
+ };
242
+ export type DelegationTokenCovers = {
243
+ modelID?: string | null;
244
+ docID?: string | null;
245
+ };
246
+ export type ListOwnDelegationTokensParams = {
247
+ viewerDID: string;
248
+ grantor?: string | null;
249
+ covers?: DelegationTokenCovers | null;
250
+ };
251
+ export type RevokedDelegationData = {
252
+ jti: string;
253
+ grantor: string;
254
+ audience: string;
255
+ revokerDID: string;
256
+ revokedAt: number;
257
+ verifiedAt: number;
258
+ capExp: number | null;
259
+ groupID: string;
260
+ };
261
+ export type ListOwnRevokedTokensParams = {
262
+ viewerDID: string;
263
+ grantor?: string | null;
264
+ };
265
+ export type DelegationRequestContext = {
266
+ listOwnTokens: (params: ListOwnDelegationTokensParams) => Promise<Array<DelegationData>>;
267
+ listOwnRevokedTokens: (params: ListOwnRevokedTokensParams) => Promise<Array<RevokedDelegationData>>;
268
+ };
126
269
  export type P2PContext = {
127
270
  group: GroupRequestContext;
128
271
  sync: SyncRequestContext;
129
272
  join: P2PJoinRequestContext;
273
+ hub: HubRequestContext;
274
+ delegation: DelegationRequestContext;
130
275
  };
131
276
  declare module '@kubun/graphql' {
132
277
  interface PluginContextMap {
@@ -143,6 +288,11 @@ export type SyncSessionResult = {
143
288
  export type SyncPluginAPI = {
144
289
  /** Resolves when the HTTP sync transport is registered (only present when http option is enabled). */
145
290
  syncReady?: Promise<void>;
291
+ /**
292
+ * Resolves when hub relay setup completes. `DISABLED_HUB.ready` is already
293
+ * resolved when the `hub` plugin option is absent.
294
+ */
295
+ hubReady: Promise<void>;
146
296
  addPeer(config: PeerConfig): Promise<void>;
147
297
  removePeer(peerDID: string): Promise<void>;
148
298
  listPeers(): Promise<Array<PeerConfigWithID>>;
@@ -0,0 +1,4 @@
1
+ export type Mutex = {
2
+ run<T>(fn: () => Promise<T>): Promise<T>;
3
+ };
4
+ export declare function createMutex(): Mutex;
@@ -0,0 +1 @@
1
+ export function createMutex(){let e=Promise.resolve();return{run(t){let r=e.then(()=>t());return e=r.catch(()=>{}),r}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/plugin-p2p",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "license": "see LICENSE.md",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -14,47 +14,50 @@
14
14
  ],
15
15
  "sideEffects": false,
16
16
  "dependencies": {
17
- "@enkaku/async": "^0.14.1",
18
- "@enkaku/capability": "^0.14.0",
19
- "@enkaku/client": "^0.14.4",
20
- "@enkaku/codec": "^0.14.0",
21
- "@enkaku/event": "^0.14.1",
22
- "@enkaku/generator": "^0.14.0",
23
- "@enkaku/group": "^0.14.6",
24
- "@enkaku/http-client-transport": "^0.14.3",
25
- "@enkaku/http-server-transport": "^0.14.2",
26
- "@enkaku/hub-protocol": "^0.14.0",
27
- "@enkaku/protocol": "^0.14.0",
28
- "@enkaku/runtime": "^0.14.0",
29
- "@enkaku/schema": "^0.14.0",
30
- "@enkaku/server": "^0.14.4",
31
- "@enkaku/stream": "^0.14.1",
32
- "@enkaku/token": "0.14.1",
33
- "@enkaku/transport": "0.14.1",
17
+ "@enkaku/async": "^0.16.0",
18
+ "@enkaku/capability": "^0.16.0",
19
+ "@enkaku/client": "^0.16.0",
20
+ "@enkaku/codec": "^0.16.0",
21
+ "@enkaku/event": "^0.16.0",
22
+ "@enkaku/generator": "^0.16.0",
23
+ "@enkaku/group": "^0.16.1",
24
+ "@enkaku/http-client-transport": "^0.16.0",
25
+ "@enkaku/http-server-transport": "^0.16.0",
26
+ "@enkaku/hub-protocol": "^0.16.0",
27
+ "@enkaku/hub-tunnel": "^0.16.0",
28
+ "@enkaku/protocol": "^0.16.0",
29
+ "@enkaku/runtime": "^0.16.0",
30
+ "@enkaku/schema": "^0.16.0",
31
+ "@enkaku/server": "^0.16.0",
32
+ "@enkaku/stream": "^0.16.0",
33
+ "@enkaku/token": "^0.16.0",
34
+ "@enkaku/transport": "^0.16.0",
34
35
  "@noble/hashes": "^2.2.0",
35
36
  "graphql": "^16.13.2",
36
- "kysely": "^0.28.16",
37
- "@kubun/client": "^0.8.0",
38
- "@kubun/db": "^0.8.1",
39
- "@kubun/engine": "^0.8.3",
40
- "@kubun/db-adapter": "^0.8.1",
41
- "@kubun/store-p2p": "^0.8.0",
42
- "@kubun/store-graph": "^0.8.1",
43
- "@kubun/graphql": "^0.8.2",
44
- "@kubun/hlc": "^0.8.0",
45
- "@kubun/mutation": "^0.8.1",
46
- "@kubun/protocol": "^0.8.1",
47
- "@kubun/id": "^0.8.0",
48
- "@kubun/logger": "^0.8.0"
37
+ "kysely": "^0.29.2",
38
+ "@kubun/client": "^0.10.0",
39
+ "@kubun/db": "^0.10.0",
40
+ "@kubun/store-graph": "^0.10.0",
41
+ "@kubun/graphql": "^0.10.0",
42
+ "@kubun/db-adapter": "^0.10.0",
43
+ "@kubun/hlc": "^0.10.0",
44
+ "@kubun/id": "^0.10.0",
45
+ "@kubun/engine": "^0.10.0",
46
+ "@kubun/store-p2p": "^0.10.0",
47
+ "@kubun/mutation": "^0.10.0",
48
+ "@kubun/logger": "^0.10.0",
49
+ "@kubun/protocol": "^0.10.0"
49
50
  },
50
51
  "devDependencies": {
51
- "@enkaku/hub-server": "^0.14.1",
52
+ "@enkaku/hub-server": "^0.16.0",
52
53
  "get-port": "^7.2.0",
53
- "@kubun/db-better-sqlite": "^0.8.1",
54
- "@kubun/plugin-connector": "^0.8.2",
55
- "@kubun/plugin-http": "^0.8.1",
56
- "@kubun/plugin-rpc": "^0.8.1",
57
- "@kubun/test-utils": "^0.8.0"
54
+ "@kubun/db-better-sqlite": "^0.10.0",
55
+ "@kubun/plugin-connector": "^0.10.0",
56
+ "@kubun/hub": "^0.10.0",
57
+ "@kubun/db-node-sqlite": "^0.10.0",
58
+ "@kubun/plugin-http": "^0.10.0",
59
+ "@kubun/plugin-rpc": "^0.10.0",
60
+ "@kubun/test-utils": "^0.10.0"
58
61
  },
59
62
  "scripts": {
60
63
  "build:clean": "del lib",