@kubun/store-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/api.d.ts +25 -251
- package/lib/api.js +19 -590
- package/lib/index.d.ts +2 -2
- package/lib/migrations.d.ts +21 -0
- package/lib/migrations.js +106 -26
- package/lib/ops/app-lane.d.ts +36 -0
- package/lib/ops/app-lane.js +38 -0
- package/lib/ops/circles.d.ts +153 -0
- package/lib/ops/circles.js +269 -0
- package/lib/ops/control.d.ts +118 -0
- package/lib/ops/control.js +110 -0
- package/lib/ops/delegations.d.ts +25 -0
- package/lib/ops/delegations.js +27 -0
- package/lib/ops/discovery.d.ts +92 -0
- package/lib/ops/discovery.js +90 -0
- package/lib/ops/groups.d.ts +132 -0
- package/lib/ops/groups.js +259 -0
- package/lib/ops/hubs.d.ts +56 -0
- package/lib/ops/hubs.js +222 -0
- package/lib/ops/mls.d.ts +21 -0
- package/lib/ops/mls.js +50 -0
- package/lib/ops/sync.d.ts +22 -0
- package/lib/ops/sync.js +50 -0
- package/lib/tables.d.ts +106 -26
- package/package.json +18 -18
package/lib/api.d.ts
CHANGED
|
@@ -1,254 +1,28 @@
|
|
|
1
1
|
import type { Adapter } from '@kubun/db-adapter';
|
|
2
2
|
import type { Kysely } from 'kysely';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* removal sticks only when no removal is recorded yet, or when `hlc` precedes
|
|
29
|
-
* the stored removal HLC. A removal for a `(groupID, memberDID)` with no local
|
|
30
|
-
* row is a no-op — absence means there is no member to tombstone, and no row
|
|
31
|
-
* is created.
|
|
32
|
-
*/
|
|
33
|
-
markMemberRemoved(groupID: string, memberDID: string, hlc: string): Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* Read a membership row's removal state, including tombstoned rows. This is
|
|
36
|
-
* the only query that sees soft-deleted members. Returns `undefined` when no
|
|
37
|
-
* row exists; `{ removed_at_hlc: null }` for an active member; and
|
|
38
|
-
* `{ removed_at_hlc: <hlc> }` for a removed one.
|
|
39
|
-
*/
|
|
40
|
-
getMemberRemoval(groupID: string, memberDID: string): Promise<{
|
|
41
|
-
removed_at_hlc: string | null;
|
|
42
|
-
} | undefined>;
|
|
43
|
-
getGroupMember(groupID: string, memberDID: string): Promise<GroupMember | undefined>;
|
|
44
|
-
isGroupMember(groupID: string, memberDID: string): Promise<boolean>;
|
|
45
|
-
/**
|
|
46
|
-
* Whether `did` was a member of `groupID` at the given HLC, ignoring role.
|
|
47
|
-
* Mirrors {@link isGroupAdmin}'s removal-boundary semantics without the
|
|
48
|
-
* `role = 'admin'` filter: with no `atHLC`, tombstoned rows are excluded
|
|
49
|
-
* (`removed_at_hlc IS NULL`); with `atHLC`, a member removed at HLC `R` still
|
|
50
|
-
* counts iff `atHLC < R`. Conjoined with ledger admin authority so an
|
|
51
|
-
* MLS-removed member loses admin regardless of the ledger.
|
|
52
|
-
*/
|
|
53
|
-
isGroupMemberAtHLC(groupID: string, did: string, atHLC?: string): Promise<boolean>;
|
|
54
|
-
/**
|
|
55
|
-
* Whether `did` holds an active `admin` role in `groupID`. With no `atHLC`,
|
|
56
|
-
* tombstoned rows are ignored (`removed_at_hlc IS NULL`) — the apply-time
|
|
57
|
-
* admin check. With `atHLC`, an admin removed at HLC `R` still counts iff the
|
|
58
|
-
* supplied HLC strictly precedes `R` (`atHLC < R`): a write claiming a moment
|
|
59
|
-
* before the removal is admitted, one at or after it is denied. This mirrors
|
|
60
|
-
* the membership boundary in `checkMembership` (which denies at
|
|
61
|
-
* `removed_at_hlc <= mutationHLC`), so the two checks agree on the
|
|
62
|
-
* remove-boundary instant.
|
|
63
|
-
*/
|
|
64
|
-
isGroupAdmin(groupID: string, did: string, atHLC?: string): Promise<boolean>;
|
|
65
|
-
/**
|
|
66
|
-
* Overlay the role column for an existing member. Update-only: a grant for a
|
|
67
|
-
* DID with no membership row is a no-op, since membership is MLS-native and a
|
|
68
|
-
* non-member can hold no role. Never touches `hlc` or `removed_at_hlc`, so it
|
|
69
|
-
* neither churns membership LWW nor resurrects a tombstone — it is purely the
|
|
70
|
-
* projection target for the admin-roster fold.
|
|
71
|
-
*/
|
|
72
|
-
setGroupMemberRole(groupID: string, memberDID: string, role: string): Promise<void>;
|
|
73
|
-
isMemberOfAnyGroup(viewerDID: string, groupIDs: Array<string>): Promise<boolean>;
|
|
74
|
-
listGroupMembers(groupID: string): Promise<Array<GroupMember>>;
|
|
75
|
-
getGroupsForMember(memberDID: string): Promise<Array<Group>>;
|
|
76
|
-
/**
|
|
77
|
-
* Batch fetch groups for multiple members. Returns a Map keyed by
|
|
78
|
-
* `memberDID`; values are arrays of groups for that member. Members with
|
|
79
|
-
* no groups are absent from the map. Single SQL query joining
|
|
80
|
-
* `group_members` to `groups`. Empty input short-circuits with an empty
|
|
81
|
-
* Map (no SQL).
|
|
82
|
-
*
|
|
83
|
-
* Caller is responsible for deduplicating DIDs.
|
|
84
|
-
*/
|
|
85
|
-
getGroupsForMembers(memberDIDs: Array<string>): Promise<Map<string, Array<Group>>>;
|
|
86
|
-
createCircle(circle: InsertCircle): Promise<void>;
|
|
87
|
-
/**
|
|
88
|
-
* Active-only by default (`removed_at_hlc IS NULL`). Pass
|
|
89
|
-
* `{ includeRemoved: true }` to also see tombstoned circles — used by the
|
|
90
|
-
* apply path so a `circle:create`/`circle:update` can HLC-compare against a
|
|
91
|
-
* tombstoned row and resurrect it, and by the catch-up responder.
|
|
92
|
-
*/
|
|
93
|
-
getCircle(id: string, options?: {
|
|
94
|
-
includeRemoved?: boolean;
|
|
95
|
-
}): Promise<Circle | undefined>;
|
|
96
|
-
/**
|
|
97
|
-
* Batch fetch circles by ID. Returns a Map keyed by ID; missing IDs are
|
|
98
|
-
* absent from the map. Single SQL query with `WHERE id IN (...)`. Empty
|
|
99
|
-
* input short-circuits with an empty Map (no SQL).
|
|
100
|
-
*
|
|
101
|
-
* Caller is responsible for deduplicating IDs.
|
|
102
|
-
*/
|
|
103
|
-
getCircles(ids: Array<string>): Promise<Map<string, Circle>>;
|
|
104
|
-
updateCircle(id: string, update: Partial<Pick<InsertCircle, 'name' | 'description' | 'catalog_ids' | 'hlc'>>): Promise<void>;
|
|
105
|
-
deleteCircle(id: string): Promise<void>;
|
|
106
|
-
/**
|
|
107
|
-
* Tombstone an existing circle row at `hlc` using earliest-wins LWW: the
|
|
108
|
-
* removal sticks only when no removal is recorded yet, or when `hlc` precedes
|
|
109
|
-
* the stored removal HLC. A removal for a `circleID` with no local row is a
|
|
110
|
-
* no-op — absence means there is no circle to tombstone, and no row is
|
|
111
|
-
* created.
|
|
112
|
-
*/
|
|
113
|
-
markCircleRemoved(circleID: string, hlc: string): Promise<void>;
|
|
114
|
-
/**
|
|
115
|
-
* Active-only by default (`removed_at_hlc IS NULL`). Pass
|
|
116
|
-
* `{ includeRemoved: true }` to include tombstoned circles for the catch-up
|
|
117
|
-
* responder.
|
|
118
|
-
*/
|
|
119
|
-
listCirclesByGroup(groupID: string, options?: {
|
|
120
|
-
includeRemoved?: boolean;
|
|
121
|
-
}): Promise<Array<Circle>>;
|
|
122
|
-
addCircleMember(member: InsertCircleMember): Promise<void>;
|
|
123
|
-
/**
|
|
124
|
-
* Soft-delete a circle member by tombstoning the row with `hlc`: earliest-wins
|
|
125
|
-
* LWW, ignore-if-absent. The row stays in the table so the removal HLC stays
|
|
126
|
-
* comparable.
|
|
127
|
-
*/
|
|
128
|
-
removeCircleMember(circleID: string, memberDID: string, hlc: string): Promise<void>;
|
|
129
|
-
getCircleMember(circleID: string, memberDID: string): Promise<CircleMember | undefined>;
|
|
130
|
-
/**
|
|
131
|
-
* Active-only by default (`removed_at_hlc IS NULL`). Pass
|
|
132
|
-
* `{ includeRemoved: true }` to include tombstoned members for the catch-up
|
|
133
|
-
* responder.
|
|
134
|
-
*/
|
|
135
|
-
listCircleMembers(circleID: string, options?: {
|
|
136
|
-
includeRemoved?: boolean;
|
|
137
|
-
}): Promise<Array<CircleMember>>;
|
|
138
|
-
getCirclesForMember(memberDID: string): Promise<Array<Circle>>;
|
|
139
|
-
isMemberOfAnyCircle(memberDID: string, circleIDs: Array<string>): Promise<boolean>;
|
|
140
|
-
/**
|
|
141
|
-
* Fold-authoritative circle projection write: unconditionally set the row for
|
|
142
|
-
* `id` to the supplied derived state. Distinct from the LWW writers —
|
|
143
|
-
* `createCircle` (insert-only), `updateCircle` (update-only, clears the
|
|
144
|
-
* tombstone) and `markCircleRemoved` (earliest-wins LWW). A reproject derives
|
|
145
|
-
* `hlc` from the winning active entry and `removedAtHLC` from the winning
|
|
146
|
-
* tombstone (or null when active), then overwrites every projected column so
|
|
147
|
-
* the row equals exactly what the ledger fold decides regardless of prior
|
|
148
|
-
* contents. A removed circle keeps a tombstone row (`removed_at_hlc` set), not
|
|
149
|
-
* a hard delete, so `includeRemoved` reads and the read-ACL joins keep working.
|
|
150
|
-
*/
|
|
151
|
-
reconcileCircleProjection(params: {
|
|
152
|
-
id: string;
|
|
153
|
-
groupID: string;
|
|
154
|
-
name: string;
|
|
155
|
-
description: string;
|
|
156
|
-
catalogIDs: Array<string>;
|
|
157
|
-
hlc: string;
|
|
158
|
-
removedAtHLC: string | null;
|
|
159
|
-
}): Promise<void>;
|
|
160
|
-
/**
|
|
161
|
-
* Fold-authoritative circle-member projection write, the member-row analogue
|
|
162
|
-
* of {@link reconcileCircleProjection}: unconditionally upsert the
|
|
163
|
-
* `(circleID, memberDID)` row to the derived `(role, hlc, removedAtHLC)` state.
|
|
164
|
-
* A removed member keeps a tombstone row so the read-ACL joins still gate on
|
|
165
|
-
* the marker.
|
|
166
|
-
*/
|
|
167
|
-
reconcileCircleMemberProjection(params: {
|
|
168
|
-
circleID: string;
|
|
169
|
-
memberDID: string;
|
|
170
|
-
role: string;
|
|
171
|
-
hlc: string;
|
|
172
|
-
removedAtHLC: string | null;
|
|
173
|
-
}): Promise<void>;
|
|
174
|
-
/**
|
|
175
|
-
* Record the group a delegation `jti` was granted in. Idempotent on `jti`
|
|
176
|
-
* (the primary key): a re-record for a `jti` already present is a no-op. The
|
|
177
|
-
* delegation token itself lives in the core delegation store; this edge only
|
|
178
|
-
* carries the group association the p2p layer needs.
|
|
179
|
-
*/
|
|
180
|
-
addGroupDelegation(edge: InsertGroupDelegation): Promise<void>;
|
|
181
|
-
/**
|
|
182
|
-
* Resolve the group a delegation `jti` was granted in, or `null` when no edge
|
|
183
|
-
* exists. Used to target revoke broadcasts and to enrich revocation listings
|
|
184
|
-
* with their originating group.
|
|
185
|
-
*/
|
|
186
|
-
getGroupIDByJTI(jti: string): Promise<string | null>;
|
|
187
|
-
/**
|
|
188
|
-
* Batch variant of {@link getGroupIDByJTI}: resolve the group each `jti` was
|
|
189
|
-
* granted in, returning a `Map` keyed by `jti`. A `jti` with no edge is absent
|
|
190
|
-
* from the map. Used to enrich revocation listings without an N+1 lookup.
|
|
191
|
-
*/
|
|
192
|
-
getGroupIDsByJTIs(jtis: Array<string>): Promise<Map<string, string>>;
|
|
193
|
-
saveMLSState(state: InsertGroupMLSState): Promise<void>;
|
|
194
|
-
getMLSState(groupID: string, deviceID: string): Promise<GroupMLSState | undefined>;
|
|
195
|
-
deleteMLSState(groupID: string, deviceID: string): Promise<void>;
|
|
196
|
-
listMLSStates(groupID: string): Promise<Array<GroupMLSState>>;
|
|
197
|
-
deleteGroupMLSStates(groupID: string): Promise<void>;
|
|
198
|
-
addSyncPeer(peer: InsertSyncPeer): Promise<void>;
|
|
199
|
-
getSyncPeer(peerDID: string): Promise<SyncPeer | undefined>;
|
|
200
|
-
listSyncPeers(): Promise<Array<SyncPeer>>;
|
|
201
|
-
updateSyncPeer(peerDID: string, update: Partial<InsertSyncPeer>): Promise<void>;
|
|
202
|
-
removeSyncPeer(peerDID: string): Promise<void>;
|
|
203
|
-
recordBroadcast(entry: {
|
|
204
|
-
docID: string;
|
|
205
|
-
version: string;
|
|
206
|
-
mlsGroupID: string;
|
|
207
|
-
}): Promise<boolean>;
|
|
208
|
-
hasBroadcast(entry: {
|
|
209
|
-
docID: string;
|
|
210
|
-
version: string;
|
|
211
|
-
mlsGroupID: string;
|
|
212
|
-
}): Promise<boolean>;
|
|
213
|
-
/**
|
|
214
|
-
* Append a verified ledger entry. Idempotent on `entry_id` (the token
|
|
215
|
-
* digest): a re-delivered entry is a no-op. `issuer_did` is normalized on
|
|
216
|
-
* write. Returns `true` when a new row was inserted, `false` on a duplicate.
|
|
217
|
-
*/
|
|
218
|
-
appendLedgerEntry(entry: InsertControlLedgerEntry): Promise<boolean>;
|
|
219
|
-
/** All ledger entries for a group, ordered by `(hlc, entry_id)`. */
|
|
220
|
-
getLedgerEntries(groupID: string): Promise<Array<ControlLedgerEntry>>;
|
|
221
|
-
/** Ledger entries for a group filtered by `type`, ordered by `(hlc, entry_id)`. */
|
|
222
|
-
getLedgerEntriesByType(groupID: string, type: string): Promise<Array<ControlLedgerEntry>>;
|
|
223
|
-
/**
|
|
224
|
-
* The HLC through which `projection` has been folded for `groupID`, or `null`
|
|
225
|
-
* when no projection has run yet. A caller treats an entry whose HLC is `>`
|
|
226
|
-
* this value as in-order (apply incrementally); `<=` or `null` means the
|
|
227
|
-
* cached projection is no longer a correct fold-through-this-entry and must be
|
|
228
|
-
* rebuilt from the whole ledger.
|
|
229
|
-
*/
|
|
230
|
-
getProjectionWatermark(groupID: string, projection: string): Promise<string | null>;
|
|
231
|
-
/**
|
|
232
|
-
* Set the `(groupID, projection)` watermark to `hlc`. Overwrite-on-conflict:
|
|
233
|
-
* the row is unconditionally replaced. Callers must only advance the watermark
|
|
234
|
-
* — the incremental path passes a value strictly newer than the current one,
|
|
235
|
-
* and the reproject path passes the true max over the folded ledger.
|
|
236
|
-
*/
|
|
237
|
-
setProjectionWatermark(groupID: string, projection: string, hlc: string): Promise<void>;
|
|
238
|
-
insertHub(hub: InsertHub): Promise<void>;
|
|
239
|
-
getHub(id: string): Promise<Hub | undefined>;
|
|
240
|
-
getHubByURL(url: string): Promise<Hub | undefined>;
|
|
241
|
-
updateHub(id: string, update: Partial<Pick<InsertHub, 'label' | 'url' | 'server_did'>>): Promise<void>;
|
|
242
|
-
deleteHub(id: string): Promise<void>;
|
|
243
|
-
listHubs(): Promise<Array<Hub>>;
|
|
244
|
-
insertGroupHub(binding: InsertGroupHub): Promise<boolean>;
|
|
245
|
-
deleteGroupHub(params: {
|
|
246
|
-
groupID: string;
|
|
247
|
-
hubID: string;
|
|
248
|
-
}): Promise<boolean>;
|
|
249
|
-
listGroupIDsByHubID(hubID: string): Promise<Array<string>>;
|
|
250
|
-
listHubsByGroupID(groupID: string): Promise<Array<Hub>>;
|
|
251
|
-
listGroupsByHubID(hubID: string): Promise<Array<Group>>;
|
|
252
|
-
deleteGroupHubsByHubID(hubID: string): Promise<void>;
|
|
253
|
-
};
|
|
3
|
+
import { type AppLaneOps } from './ops/app-lane.js';
|
|
4
|
+
import { type CircleOps } from './ops/circles.js';
|
|
5
|
+
import { type ControlOps } from './ops/control.js';
|
|
6
|
+
import { type DelegationOps } from './ops/delegations.js';
|
|
7
|
+
import { type DiscoveryOps } from './ops/discovery.js';
|
|
8
|
+
import { type GroupOps } from './ops/groups.js';
|
|
9
|
+
import { type HubOps } from './ops/hubs.js';
|
|
10
|
+
import { type MLSOps } from './ops/mls.js';
|
|
11
|
+
import { type SyncOps } from './ops/sync.js';
|
|
12
|
+
import type { P2PStoreTables } from './tables.js';
|
|
13
|
+
export type { AppLaneOps } from './ops/app-lane.js';
|
|
14
|
+
export type { CircleOps } from './ops/circles.js';
|
|
15
|
+
export type { CommitJournalEntryKind, ControlOps, ControlRequestKind, ControlRequestOutcome, } from './ops/control.js';
|
|
16
|
+
export type { DelegationOps } from './ops/delegations.js';
|
|
17
|
+
export type { DiscoveryOps, PutPendingJoinRequestParams, SetLocalPeerProfileParams, UpsertPeerAnnouncementParams, } from './ops/discovery.js';
|
|
18
|
+
export type { GroupOps } from './ops/groups.js';
|
|
19
|
+
export type { HubOps } from './ops/hubs.js';
|
|
20
|
+
export type { MLSOps } from './ops/mls.js';
|
|
21
|
+
export type { SyncOps } from './ops/sync.js';
|
|
22
|
+
/**
|
|
23
|
+
* The store's whole surface, one slice per domain. Each slice module owns its
|
|
24
|
+
* tables and its own helpers; this intersection is the only coupling between
|
|
25
|
+
* them, so a caller still sees one flat API.
|
|
26
|
+
*/
|
|
27
|
+
export type P2PStoreAPI = GroupOps & CircleOps & DelegationOps & MLSOps & SyncOps & ControlOps & AppLaneOps & HubOps & DiscoveryOps;
|
|
254
28
|
export declare function createP2PStore(db: Kysely<P2PStoreTables>, adapter: Adapter): P2PStoreAPI;
|