@kubun/store-graph 0.17.1 → 0.18.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/access-default-records.d.ts +18 -0
- package/lib/access-default-records.js +167 -0
- package/lib/api.d.ts +382 -51
- package/lib/api.js +2397 -186
- package/lib/catalog-merge.d.ts +5 -0
- package/lib/catalog-merge.js +117 -0
- package/lib/catalog-records.d.ts +34 -0
- package/lib/catalog-records.js +527 -0
- package/lib/catalog-scope.d.ts +120 -0
- package/lib/catalog-scope.js +165 -0
- package/lib/catalog-state.d.ts +21 -0
- package/lib/catalog-state.js +122 -0
- package/lib/catalog-types.d.ts +71 -0
- package/lib/catalog-types.js +1 -0
- package/lib/errors.d.ts +15 -0
- package/lib/errors.js +33 -0
- package/lib/identifiers.d.ts +7 -0
- package/lib/identifiers.js +27 -0
- package/lib/index.d.ts +11 -4
- package/lib/index.js +7 -2
- package/lib/migrations.d.ts +8 -10
- package/lib/migrations.js +111 -18
- package/lib/query-builder.js +1 -1
- package/lib/tables.d.ts +194 -39
- package/package.json +14 -11
package/lib/api.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import type { CustodyGuard, StoreAPIContext, StoreProvider } from '@kubun/db';
|
|
1
2
|
import type { Adapter } from '@kubun/db-adapter';
|
|
2
3
|
import { DocumentID, DocumentModelID } from '@kubun/id';
|
|
3
4
|
import type { AggregateDocumentsParams, AggregateValues, DocumentFieldsMeta, DocumentModel, DocumentModelSchema, DocumentNode, GroupedAggregateDocumentsParams, GroupedAggregateValue } from '@kubun/protocol';
|
|
4
|
-
import type { Kysely } from 'kysely';
|
|
5
|
-
import
|
|
5
|
+
import type { Kysely, RawBuilder } from 'kysely';
|
|
6
|
+
import { type GraphAccessDefaultRecordMethods } from './access-default-records.js';
|
|
7
|
+
import type { GraphCatalogRecordMethods } from './catalog-records.js';
|
|
8
|
+
import type { CatalogUse, DocumentAvailability, DocumentHold, DocumentScope, PlaceDocumentHoldParams, RouteRulesInput, ScopeCatalog, CatalogRef as ScopeCatalogRef, SweptDocument, UnavailableDocument } from './catalog-scope.js';
|
|
9
|
+
import type { CatalogStateMethods } from './catalog-state.js';
|
|
10
|
+
import type { AccessLevel, ClusterDefinitionRow, ClusterModel, CreateDocumentParams, CreateGraphParams, DocumentLeafPageParams, DocumentLeafRow, DocumentLeafRule, DocumentModelRow, GraphModel, GraphModelWithRecord, GraphTables, InsertClusterModel, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, QueryDocumentsParams, QueryDocumentsResult, SaveDocumentParams, SearchDocumentResult, SearchDocumentsParams } from './tables.js';
|
|
6
11
|
export declare function documentModelFromTable(row: DocumentModelRow): DocumentModel;
|
|
7
12
|
export declare function documentModelToTable(adapter: Adapter, id: string, model: DocumentModel): {
|
|
8
13
|
id: string;
|
|
@@ -16,6 +21,8 @@ export declare function documentModelToTable(adapter: Adapter, id: string, model
|
|
|
16
21
|
provider_merge_policy: {
|
|
17
22
|
group: Array<string>;
|
|
18
23
|
} | null;
|
|
24
|
+
date_field: string | null;
|
|
25
|
+
resolved_date_field: string | null;
|
|
19
26
|
};
|
|
20
27
|
/**
|
|
21
28
|
* Reads a document's `field_values` cell on the given transaction and
|
|
@@ -31,6 +38,16 @@ export declare function documentModelToTable(adapter: Adapter, id: string, model
|
|
|
31
38
|
* transaction rather than opening a second connection.
|
|
32
39
|
*/
|
|
33
40
|
export declare function readWinnerStateDigest(tx: Kysely<GraphTables>, documentID: string): Promise<string | null>;
|
|
41
|
+
export type ReadWinnerStateDigestsParams = {
|
|
42
|
+
tx: Kysely<GraphTables>;
|
|
43
|
+
documentIDs: Iterable<string>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Batch form of `readWinnerStateDigest`: one chunked `id in` read per model rather than one
|
|
47
|
+
* read per document. A document whose digest cannot be read (bad id, model table not deployed,
|
|
48
|
+
* no row, no digest) is left out of the map.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readWinnerStateDigests(params: ReadWinnerStateDigestsParams): Promise<Map<string, string>>;
|
|
34
51
|
/**
|
|
35
52
|
* Persisted access rule shape as stored in `user_model_access_defaults`.
|
|
36
53
|
*/
|
|
@@ -56,7 +73,108 @@ export type StoredAccessDefaultRow = StoredAccessRule & {
|
|
|
56
73
|
*/
|
|
57
74
|
hlc: string | null;
|
|
58
75
|
};
|
|
59
|
-
export type
|
|
76
|
+
export type RecomputeDocumentRefsParams = {
|
|
77
|
+
documentID: string;
|
|
78
|
+
routeRules: RouteRulesInput;
|
|
79
|
+
nowMS?: number;
|
|
80
|
+
catalog?: ScopeCatalogRef;
|
|
81
|
+
/** Custody pins to drop rather than keep, once a completed handoff is confirmed. */
|
|
82
|
+
releaseCustodyPins?: CustodyPinRelease;
|
|
83
|
+
};
|
|
84
|
+
export type CustodyPinRelease = {
|
|
85
|
+
refs: ReadonlyArray<string>;
|
|
86
|
+
/**
|
|
87
|
+
* Proves the handoff, called under the document's ref lock in the recomputing transaction, so
|
|
88
|
+
* no concurrent apply can change what it proved before the pins go. False keeps them.
|
|
89
|
+
*/
|
|
90
|
+
confirm: () => Promise<boolean>;
|
|
91
|
+
};
|
|
92
|
+
export type SweepDocumentParams = {
|
|
93
|
+
documentID: string;
|
|
94
|
+
nowMS: number;
|
|
95
|
+
/** How long a document stays marked, with no change, before it may be swept. */
|
|
96
|
+
graceMS: number;
|
|
97
|
+
/**
|
|
98
|
+
* Proves the document may go (a valid receipt, or positive foreign ownership), called last,
|
|
99
|
+
* under the document's row and ref locks, with the sweeping transaction. False keeps it.
|
|
100
|
+
*/
|
|
101
|
+
confirm: (stores: StoreProvider) => Promise<boolean>;
|
|
102
|
+
};
|
|
103
|
+
export type DocumentSweepRefusal = 'absent' | 'retained' | 'held' | 'unmarked' | 'changed' | 'grace' | 'pending' | 'unconfirmed';
|
|
104
|
+
export type DocumentSweepResult = {
|
|
105
|
+
swept: true;
|
|
106
|
+
} | {
|
|
107
|
+
swept: false;
|
|
108
|
+
refusal: DocumentSweepRefusal;
|
|
109
|
+
};
|
|
110
|
+
export type ReconcileCatalogModelRefsParams = {
|
|
111
|
+
modelID: string;
|
|
112
|
+
routeRules: RouteRulesInput;
|
|
113
|
+
nowMS: number;
|
|
114
|
+
owners?: Array<string>;
|
|
115
|
+
catalog?: ScopeCatalogRef;
|
|
116
|
+
};
|
|
117
|
+
export type RecordPendingMutationAttemptParams = {
|
|
118
|
+
mutationHash: string;
|
|
119
|
+
outcome: 'transient' | 'rejected' | 'applied';
|
|
120
|
+
now: number;
|
|
121
|
+
jitter: number;
|
|
122
|
+
};
|
|
123
|
+
export type UpdateSearchEntryParams = {
|
|
124
|
+
modelID: string;
|
|
125
|
+
documentID: string;
|
|
126
|
+
data: Record<string, unknown>;
|
|
127
|
+
fields: Array<string>;
|
|
128
|
+
};
|
|
129
|
+
export type RemoveUserModelAccessDefaultsParams = {
|
|
130
|
+
ownerDID: string;
|
|
131
|
+
modelID: string;
|
|
132
|
+
permissionTypes: Array<string>;
|
|
133
|
+
hlc: string;
|
|
134
|
+
};
|
|
135
|
+
export type GetDocumentIDsForScopeParams = {
|
|
136
|
+
scopes: Array<{
|
|
137
|
+
modelID: string;
|
|
138
|
+
ownerDID: string;
|
|
139
|
+
}>;
|
|
140
|
+
excludedDocumentIDs?: Array<string>;
|
|
141
|
+
/** Read at most this many IDs in total; a caller passes its cap plus one. */
|
|
142
|
+
limit?: number;
|
|
143
|
+
groupRead?: {
|
|
144
|
+
groupID: string;
|
|
145
|
+
circleIDs: Array<string>;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
export type GCMark = {
|
|
149
|
+
documentID: string;
|
|
150
|
+
digest: string;
|
|
151
|
+
markedAt: number;
|
|
152
|
+
};
|
|
153
|
+
/** Whether a mark has waited out the grace: the sweep's own test, shared so a listing agrees. */
|
|
154
|
+
export declare function gcMarkPastGrace(mark: Pick<GCMark, 'markedAt'>, graceMS: number, nowMS: number): boolean;
|
|
155
|
+
export type DropGCMarkParams = Pick<GCMark, 'documentID' | 'digest'>;
|
|
156
|
+
export type CustodyNonce = {
|
|
157
|
+
nonce: string;
|
|
158
|
+
custodian: string;
|
|
159
|
+
assignmentDigest: string;
|
|
160
|
+
expiresAt: number;
|
|
161
|
+
};
|
|
162
|
+
export type CustodyReceiptRecord = {
|
|
163
|
+
documentID: string;
|
|
164
|
+
custodian: string;
|
|
165
|
+
/** The custody owner's own-agents group the receipt was answered through. */
|
|
166
|
+
groupID: string;
|
|
167
|
+
custodyOwner: string;
|
|
168
|
+
catalog: ScopeCatalogRef;
|
|
169
|
+
assignmentDigest: string;
|
|
170
|
+
headDigest: string;
|
|
171
|
+
/** The digest of the accepted mutation IDs the custodian answered for. */
|
|
172
|
+
mutationDigest: string;
|
|
173
|
+
receivedAt: number;
|
|
174
|
+
};
|
|
175
|
+
/** Hex blake3 over mutation IDs, sorted and joined by newline: the document mutation digest. */
|
|
176
|
+
export declare function mutationIDsDigest(mutationIDs: ReadonlyArray<string>): string;
|
|
177
|
+
export type GraphStoreAPI = GraphAccessDefaultRecordMethods & GraphCatalogRecordMethods & CatalogStateMethods & {
|
|
60
178
|
getDocument(id: DocumentID | string): Promise<DocumentNode | null>;
|
|
61
179
|
/**
|
|
62
180
|
* Batch fetch documents, returning a Map keyed by the document ID string. A
|
|
@@ -78,18 +196,200 @@ export type GraphStoreAPI = {
|
|
|
78
196
|
* order from `addDocumentModel` (stable for a given graph creation).
|
|
79
197
|
*/
|
|
80
198
|
getModelInterfaces(modelID: string): Promise<Array<string>>;
|
|
199
|
+
/**
|
|
200
|
+
* The interface IDs of every model that declares any, keyed by model, from
|
|
201
|
+
* one read. A model without interfaces is absent.
|
|
202
|
+
*/
|
|
203
|
+
listModelInterfaces(): Promise<Map<string, Array<string>>>;
|
|
204
|
+
/** The deployed models among `ids`, from one read. An unknown ID is absent. */
|
|
205
|
+
getDocumentModelsByID(ids: ReadonlyArray<string>): Promise<Map<string, DocumentModel>>;
|
|
81
206
|
createDocument(params: CreateDocumentParams): Promise<DocumentNode>;
|
|
82
207
|
saveDocument(params: SaveDocumentParams): Promise<DocumentNode>;
|
|
208
|
+
getDocumentDates(documentID: string): Promise<{
|
|
209
|
+
createdAt: number | null;
|
|
210
|
+
updatedAt: number | null;
|
|
211
|
+
scopeDate: number | null;
|
|
212
|
+
} | null>;
|
|
213
|
+
setCatalogDefinition(ref: ScopeCatalogRef, catalog: ScopeCatalog): Promise<void>;
|
|
214
|
+
setScopeReaderDID(did: string, defaultReadLevel?: AccessLevel): Promise<void>;
|
|
215
|
+
setCatalogUse(ref: ScopeCatalogRef, use: CatalogUse): Promise<void>;
|
|
216
|
+
getCatalogUse(ref: ScopeCatalogRef): Promise<CatalogUse | null>;
|
|
217
|
+
/** The use of each catalog in `refs`, in order, from one read. */
|
|
218
|
+
getCatalogUses(refs: ReadonlyArray<ScopeCatalogRef>): Promise<Array<CatalogUse | null>>;
|
|
219
|
+
deleteCatalogUse(ref: ScopeCatalogRef): Promise<void>;
|
|
220
|
+
markDocumentLocal(documentID: string): Promise<void>;
|
|
221
|
+
/** Writes the hold row and its retain-only `hold:` ref in one transaction. */
|
|
222
|
+
placeDocumentHold(params: PlaceDocumentHoldParams): Promise<DocumentHold>;
|
|
223
|
+
/** Null when the hold is unknown or already released. */
|
|
224
|
+
releaseDocumentHold(holdID: string, nowMS: number): Promise<DocumentHold | null>;
|
|
225
|
+
getDocumentHold(holdID: string): Promise<DocumentHold | null>;
|
|
226
|
+
/** Holds on the document that are neither released nor expired at `nowMS`. */
|
|
227
|
+
listDocumentHolds(documentID: string, nowMS: number): Promise<Array<DocumentHold>>;
|
|
228
|
+
/**
|
|
229
|
+
* The earliest expiry among holds not released that scope aging has not yet passed, or null.
|
|
230
|
+
* It may already be due: aging recomputes a hold's document only once its tick passes it.
|
|
231
|
+
*/
|
|
232
|
+
nextDocumentHoldExpiry(): Promise<number | null>;
|
|
233
|
+
getDocumentScope(documentID: string): Promise<DocumentScope>;
|
|
234
|
+
/**
|
|
235
|
+
* `LOCAL` for a document here (a tombstone reads null), `UNAVAILABLE` for one swept here that
|
|
236
|
+
* a retaining rule matches again, else null. Says nothing of who may read it.
|
|
237
|
+
*/
|
|
238
|
+
getDocumentAvailability(documentID: string, nowMS: number): Promise<DocumentAvailability | null>;
|
|
239
|
+
/**
|
|
240
|
+
* The earliest time after `nowMS` at which a rule window starts or stops matching a swept
|
|
241
|
+
* document, or null. Ignores the read check: an extra wake costs one refresh.
|
|
242
|
+
*/
|
|
243
|
+
nextSweptDocumentTransition(nowMS: number): Promise<number | null>;
|
|
244
|
+
/** What this device kept of a document it swept and has not re-acquired. */
|
|
245
|
+
getSweptDocument(documentID: string): Promise<SweptDocument | null>;
|
|
246
|
+
/** Swept documents a retaining rule matches again, ordered by ID, strictly after `after`. */
|
|
247
|
+
listUnavailableDocuments(params: {
|
|
248
|
+
nowMS: number;
|
|
249
|
+
limit: number;
|
|
250
|
+
after?: string;
|
|
251
|
+
}): Promise<Array<UnavailableDocument>>;
|
|
252
|
+
/**
|
|
253
|
+
* Evaluate swept documents (of one model, or all) against the current rules and record a scope
|
|
254
|
+
* change for each that started or stopped matching one. With `ttlMS`, drop those out of every
|
|
255
|
+
* scope for that long.
|
|
256
|
+
*/
|
|
257
|
+
refreshSweptDocuments(params: {
|
|
258
|
+
nowMS: number;
|
|
259
|
+
ttlMS?: number;
|
|
260
|
+
modelID?: string;
|
|
261
|
+
}): Promise<void>;
|
|
262
|
+
/** Whether a custody pin or a `SERVE_ONLY` catalog keeps the live document's bytes here. */
|
|
263
|
+
documentNeedsBytes(documentID: string): Promise<boolean>;
|
|
264
|
+
/** Hex blake3 over the document's applied mutation hashes, sorted and joined by newline. */
|
|
265
|
+
documentMutationDigest(documentID: string): Promise<string>;
|
|
266
|
+
/** Whether every listed mutation is applied to the document. */
|
|
267
|
+
hasAppliedMutations(documentID: string, mutationIDs: ReadonlyArray<string>): Promise<boolean>;
|
|
268
|
+
/** Records a receipt nonce this device issued, dropping expired ones. */
|
|
269
|
+
putCustodyNonce(nonce: CustodyNonce): Promise<void>;
|
|
270
|
+
/** True once only: for an unexpired nonce issued to this custodian for this assignment. */
|
|
271
|
+
consumeCustodyNonce(params: Omit<CustodyNonce, 'expiresAt'> & {
|
|
272
|
+
nowMS: number;
|
|
273
|
+
}): Promise<boolean>;
|
|
274
|
+
/** One receipt per document and custodian; a later receipt replaces the earlier. */
|
|
275
|
+
putCustodyReceipts(receipts: ReadonlyArray<CustodyReceiptRecord>): Promise<void>;
|
|
276
|
+
/** Ordered by custodian. */
|
|
277
|
+
listCustodyReceipts(documentID: string): Promise<Array<CustodyReceiptRecord>>;
|
|
278
|
+
/** Documents holding this custody pin ref, ordered by ID, strictly after `after`. */
|
|
279
|
+
listCustodyPinnedDocuments(params: {
|
|
280
|
+
ref: string;
|
|
281
|
+
limit: number;
|
|
282
|
+
after?: string;
|
|
283
|
+
}): Promise<Array<string>>;
|
|
284
|
+
getGCMark(documentID: string): Promise<GCMark | null>;
|
|
285
|
+
/**
|
|
286
|
+
* Drop the document's mark only while it still carries `digest`: a mutation since remarks
|
|
287
|
+
* the document, and that mark stays. Dropping a mark only ever keeps a document.
|
|
288
|
+
*/
|
|
289
|
+
dropGCMark(params: DropGCMarkParams): Promise<void>;
|
|
290
|
+
/** Marks ordered by document ID, strictly after `after`. */
|
|
291
|
+
listGCMarks(params: {
|
|
292
|
+
limit: number;
|
|
293
|
+
after?: string;
|
|
294
|
+
}): Promise<Array<GCMark>>;
|
|
295
|
+
/** Distinct documents holding any of the catalog's rule refs. */
|
|
296
|
+
countCatalogDocuments(ref: ScopeCatalogRef): Promise<number>;
|
|
297
|
+
listPendingScopeChanges(): Promise<Array<{
|
|
298
|
+
documentID: string;
|
|
299
|
+
version: number;
|
|
300
|
+
}>>;
|
|
301
|
+
ackDocumentScopeChange(documentID: string, version: number): Promise<void>;
|
|
302
|
+
recomputeDocumentRefs(params: RecomputeDocumentRefsParams): Promise<DocumentScope>;
|
|
303
|
+
/**
|
|
304
|
+
* Delete the document's graph rows, under its row and ref locks, once its refs recomputed now
|
|
305
|
+
* retain nothing, its mark is past grace with an unchanged digest, no pending mutation waits,
|
|
306
|
+
* and `confirm` agrees. Writes no tombstone; bumps the scope change so a displayed copy leaves
|
|
307
|
+
* the view. Call inside the transaction that also sweeps the other stores.
|
|
308
|
+
*/
|
|
309
|
+
sweepDocument(params: SweepDocumentParams): Promise<DocumentSweepResult>;
|
|
310
|
+
/**
|
|
311
|
+
* Drop this custody pin ref from every document holding it, at once, under the exclusive ref
|
|
312
|
+
* lock; each recompute then marks or releases what nothing else keeps. Returns how many
|
|
313
|
+
* documents were recomputed. Deletes no document.
|
|
314
|
+
*/
|
|
315
|
+
releaseCustodyPinRef(params: {
|
|
316
|
+
ref: string;
|
|
317
|
+
nowMS: number;
|
|
318
|
+
}): Promise<number>;
|
|
319
|
+
/** Whether a rule of the catalog, as this device stores its definition, matches the document. */
|
|
320
|
+
catalogRulesMatchDocument(params: {
|
|
321
|
+
catalog: ScopeCatalogRef;
|
|
322
|
+
documentID: string;
|
|
323
|
+
nowMS: number;
|
|
324
|
+
}): Promise<boolean>;
|
|
325
|
+
/**
|
|
326
|
+
* Lock the document's row until the transaction ends (Postgres; SQLite transactions already
|
|
327
|
+
* run one at a time) and say whether it exists. Taken first, as an apply and the sweep take
|
|
328
|
+
* it, so a writer outside the apply re-checks the document against a sweep without inverting
|
|
329
|
+
* their locks.
|
|
330
|
+
*/
|
|
331
|
+
lockDocumentRow(documentID: string): Promise<boolean>;
|
|
332
|
+
/**
|
|
333
|
+
* Recompute these documents' refs in one transaction, under the all-documents ref lock.
|
|
334
|
+
* Absent documents are skipped.
|
|
335
|
+
*/
|
|
336
|
+
recomputeDocuments(params: {
|
|
337
|
+
documentIDs: ReadonlyArray<string>;
|
|
338
|
+
routeRules: RouteRulesInput;
|
|
339
|
+
nowMS: number;
|
|
340
|
+
}): Promise<void>;
|
|
341
|
+
/**
|
|
342
|
+
* A catalog argument updates only that catalog's contribution, including former holders.
|
|
343
|
+
* Without one, the recompute of every document runs in batches, each in its own transaction
|
|
344
|
+
* when called outside one, and `shouldStop` is checked before each: a stopped run returns
|
|
345
|
+
* without recording the reconcile, so the next call redoes it in full.
|
|
346
|
+
*/
|
|
347
|
+
reconcileCatalogRefs(nowMS: number, routeRules: RouteRulesInput, catalog?: ScopeCatalogRef, options?: {
|
|
348
|
+
shouldStop?: () => boolean;
|
|
349
|
+
}): Promise<void>;
|
|
350
|
+
/** Settle already queued scope work now, without reconciling any catalog of its own. */
|
|
351
|
+
settlePendingCatalogRefs(nowMS: number): Promise<void>;
|
|
352
|
+
/**
|
|
353
|
+
* Queue a recompute of every model's refs after the enclosing transaction
|
|
354
|
+
* commits. Route rules are read from the root provider when it runs; a
|
|
355
|
+
* failure keeps the existing refs and retries with the scheduler's backoff.
|
|
356
|
+
*/
|
|
357
|
+
scheduleCatalogRefReconcile(): Promise<void>;
|
|
358
|
+
reconcileCatalogModelRefs(params: ReconcileCatalogModelRefsParams): Promise<void>;
|
|
359
|
+
/** Queue a scan that pins the guarded catalog's existing documents, restarting one queued. */
|
|
360
|
+
scheduleCustodyScan(catalog: ScopeCatalogRef): Promise<void>;
|
|
361
|
+
/** Scan one batch of the oldest queued custody scan. True while scans remain. */
|
|
362
|
+
advanceCustodyScan(params: {
|
|
363
|
+
nowMS: number;
|
|
364
|
+
batchSize: number;
|
|
365
|
+
}): Promise<boolean>;
|
|
366
|
+
/**
|
|
367
|
+
* Run queued custody scans, each batch in its own transaction, so a restart resumes after the
|
|
368
|
+
* last committed batch. Call outside a transaction. True once no scan remains.
|
|
369
|
+
*/
|
|
370
|
+
runCustodyScans(options?: {
|
|
371
|
+
nowMS?: number;
|
|
372
|
+
batchSize?: number;
|
|
373
|
+
maxBatches?: number;
|
|
374
|
+
}): Promise<boolean>;
|
|
375
|
+
onScopeRecomputed(listener: () => Promise<void> | void): () => void;
|
|
376
|
+
advanceCatalogAging(nowMS: number, routeRules: RouteRulesInput): Promise<void>;
|
|
83
377
|
queryDocuments(params: QueryDocumentsParams): Promise<QueryDocumentsResult>;
|
|
84
378
|
aggregateDocuments(params: AggregateDocumentsParams): Promise<AggregateValues>;
|
|
85
379
|
groupedAggregateDocuments(params: GroupedAggregateDocumentsParams): Promise<Array<GroupedAggregateValue>>;
|
|
86
380
|
listDocuments(params: ListDocumentsParams): Promise<Array<DocumentNode>>;
|
|
87
381
|
listDocumentModelIDs(): Promise<Array<string>>;
|
|
88
|
-
getDistinctOwnersForModel(modelID: string): Promise<Array<string>>;
|
|
89
382
|
queryDocumentsByOwner(modelID: string, ownerDID: string): Promise<Array<DocumentNode>>;
|
|
90
383
|
insertMutationLogEntry(entry: InsertMutationLogEntry): Promise<void>;
|
|
384
|
+
parkPushedMutation(entry: InsertMutationLogEntry & {
|
|
385
|
+
arrival_group_id: string;
|
|
386
|
+
sender_peer_did: string;
|
|
387
|
+
}): Promise<'parked' | 'duplicate' | 'full'>;
|
|
91
388
|
hasMutationHash(hash: string): Promise<boolean>;
|
|
92
389
|
updateMutationStatus(mutationHash: string, status: string): Promise<void>;
|
|
390
|
+
getDuePendingMutations(now: number): Promise<Array<MutationLogEntry>>;
|
|
391
|
+
getNextPendingAttemptAt(): Promise<number | null>;
|
|
392
|
+
recordPendingMutationAttempt(params: RecordPendingMutationAttemptParams): Promise<void>;
|
|
93
393
|
getMutationLogForDocuments(documentIDs: Array<string>): Promise<Array<MutationLogEntry>>;
|
|
94
394
|
getPendingMutations(documentID: string): Promise<Array<MutationLogEntry>>;
|
|
95
395
|
/**
|
|
@@ -102,6 +402,8 @@ export type GraphStoreAPI = {
|
|
|
102
402
|
getMaxMutationHLC(): Promise<string | null>;
|
|
103
403
|
getFieldHLCs(documentID: string): Promise<Record<string, string> | null>;
|
|
104
404
|
getFieldValues(documentID: string): Promise<Record<string, unknown> | null>;
|
|
405
|
+
/** `getFieldValues` for many documents in one read per model; absent documents are left out. */
|
|
406
|
+
getFieldValuesMany(documentIDs: ReadonlyArray<string>): Promise<Map<string, Record<string, unknown>>>;
|
|
105
407
|
updateFieldHLCs(docID: DocumentID, fieldHLCs: Record<string, string>, fieldValues: Record<string, unknown>): Promise<void>;
|
|
106
408
|
listGraphs(): Promise<Array<GraphModel>>;
|
|
107
409
|
createGraph(params: CreateGraphParams): Promise<string>;
|
|
@@ -113,49 +415,9 @@ export type GraphStoreAPI = {
|
|
|
113
415
|
getClusters(ids: Array<string>): Promise<Record<string, unknown>>;
|
|
114
416
|
createSearchIndex(modelID: string, fields: Array<string>): Promise<void>;
|
|
115
417
|
dropSearchIndex(modelID: string): Promise<void>;
|
|
116
|
-
updateSearchEntry(
|
|
418
|
+
updateSearchEntry(params: UpdateSearchEntryParams): Promise<void>;
|
|
117
419
|
removeSearchEntry(modelID: string, documentID: string): Promise<void>;
|
|
118
420
|
searchDocuments(params: SearchDocumentsParams): Promise<Array<SearchDocumentResult>>;
|
|
119
|
-
/** Create an own catalog: stored active (scopes sync) with null provenance. */
|
|
120
|
-
createCatalog(catalog: InsertCatalog): Promise<void>;
|
|
121
|
-
/**
|
|
122
|
-
* Insert a discovered catalog as known (not active) with first-discovery
|
|
123
|
-
* provenance. Idempotent on the id: an already-stored catalog is left
|
|
124
|
-
* untouched, so its local `active` flag and first-discovery source columns
|
|
125
|
-
* are never overwritten by a later re-discovery.
|
|
126
|
-
*/
|
|
127
|
-
upsertDiscoveredCatalog(params: {
|
|
128
|
-
catalog: InsertCatalog;
|
|
129
|
-
sourceGroupID: string | null;
|
|
130
|
-
sourceCircleID: string | null;
|
|
131
|
-
}): Promise<void>;
|
|
132
|
-
/** Toggle a catalog's local sync activation. */
|
|
133
|
-
setCatalogActive(id: string, active: boolean): Promise<void>;
|
|
134
|
-
/** Flip several catalogs together — one statement, not one per id. */
|
|
135
|
-
setCatalogsActive(ids: Array<string>, active: boolean): Promise<void>;
|
|
136
|
-
/**
|
|
137
|
-
* All locally-stored catalog rows regardless of owner, optionally filtered by
|
|
138
|
-
* activation state. Backs the viewer's known-catalogs surface.
|
|
139
|
-
*/
|
|
140
|
-
listStoredCatalogs(filter?: {
|
|
141
|
-
active?: boolean;
|
|
142
|
-
}): Promise<Array<Catalog>>;
|
|
143
|
-
getCatalog(id: string): Promise<Catalog | undefined>;
|
|
144
|
-
/**
|
|
145
|
-
* Batch fetch catalogs by ID. Returns a Map keyed by ID; missing IDs are
|
|
146
|
-
* absent from the map. Single SQL query with `WHERE id IN (...)`. Empty
|
|
147
|
-
* input short-circuits with an empty Map (no SQL).
|
|
148
|
-
*
|
|
149
|
-
* Caller is responsible for deduplicating IDs (e.g. via `Array.from(new Set(...))`).
|
|
150
|
-
*/
|
|
151
|
-
getCatalogs(ids: Array<string>): Promise<Map<string, Catalog>>;
|
|
152
|
-
updateCatalog(id: string, update: Partial<Pick<InsertCatalog, 'name' | 'description' | 'filter_criteria' | 'hlc' | 'signed_token'>>): Promise<void>;
|
|
153
|
-
deleteCatalog(id: string): Promise<void>;
|
|
154
|
-
listCatalogs(ownerDID: string): Promise<Array<Catalog>>;
|
|
155
|
-
resolveCatalogScope(catalogID: string): Promise<{
|
|
156
|
-
models: Array<string> | undefined;
|
|
157
|
-
owners: Array<string> | undefined;
|
|
158
|
-
}>;
|
|
159
421
|
registerClusterModels(clusterID: string, entries: Array<InsertClusterModel>): Promise<void>;
|
|
160
422
|
/** A tombstoned (removed) rule reads as absent. */
|
|
161
423
|
getUserModelAccessDefault(ownerDID: string, modelID: string, permissionType: 'read' | 'write'): Promise<StoredAccessRule | null>;
|
|
@@ -190,20 +452,89 @@ export type GraphStoreAPI = {
|
|
|
190
452
|
* (not deleted) so a stale set arriving after the removal is rejected by HLC.
|
|
191
453
|
* A type with no existing row is skipped (nothing to tombstone).
|
|
192
454
|
*/
|
|
193
|
-
removeUserModelAccessDefaults(
|
|
455
|
+
removeUserModelAccessDefaults(params: RemoveUserModelAccessDefaultsParams): Promise<void>;
|
|
456
|
+
hasControllerAccessDefaults(ownerDID: string, modelID?: string): Promise<boolean>;
|
|
457
|
+
invalidateAccessDefaultProjections(ownerDID?: string): Promise<void>;
|
|
194
458
|
/**
|
|
195
459
|
* Document IDs across every scope, one query per distinct model. Repeating a
|
|
196
460
|
* (model, owner) pair yields its documents once — the result is a set, and the
|
|
197
461
|
* caller builds a Merkle tree from it, where a duplicate would be a defect.
|
|
198
462
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
ownerDID: string;
|
|
202
|
-
}>, excludedDocumentIDs?: Array<string>): Promise<Array<string>>;
|
|
463
|
+
/** Read at most this many IDs in total; a caller passes its cap plus one. */
|
|
464
|
+
getDocumentIDsForScope(params: GetDocumentIDsForScopeParams): Promise<Array<string>>;
|
|
203
465
|
getDocumentMetadataForSync(modelID: string, documentIDs: Array<string>): Promise<Array<{
|
|
204
466
|
id: string;
|
|
205
467
|
model: string;
|
|
206
468
|
owner: string;
|
|
207
469
|
}>>;
|
|
470
|
+
/**
|
|
471
|
+
* One keyset page of stored documents matching any rule, in bytewise
|
|
472
|
+
* document-ID order, each with the sorted IDs of its applied mutations.
|
|
473
|
+
* Pending and rejected mutations are not included. One statement per model
|
|
474
|
+
* reads membership and mutation IDs together, and the per-model pages are
|
|
475
|
+
* merged; no statement binds a list of document IDs.
|
|
476
|
+
*/
|
|
477
|
+
listDocumentLeafPage(params: DocumentLeafPageParams): Promise<Array<DocumentLeafRow>>;
|
|
478
|
+
/** A document's applied mutation log entries, in HLC order. */
|
|
479
|
+
getAppliedMutations(documentID: string): Promise<Array<MutationLogEntry>>;
|
|
480
|
+
/**
|
|
481
|
+
* Each document's applied mutation log entries, in HLC order, keyed by document ID. A
|
|
482
|
+
* document with none is absent.
|
|
483
|
+
*/
|
|
484
|
+
getAppliedMutationsForDocuments(documentIDs: Iterable<string>): Promise<Map<string, Array<MutationLogEntry>>>;
|
|
208
485
|
};
|
|
209
|
-
|
|
486
|
+
/**
|
|
487
|
+
* Resolves once the root's scope scheduler has no timer armed, no recompute running and nothing
|
|
488
|
+
* queued. While recomputes keep failing it keeps retrying, so this does not resolve.
|
|
489
|
+
*/
|
|
490
|
+
export declare function scopeSchedulerIdle(root: StoreProvider): Promise<void>;
|
|
491
|
+
/** The sticky ref a custodian pins a document with: the catalog ID part holds no `:`. */
|
|
492
|
+
export declare function custodyPinRef(guard: CustodyGuard): string;
|
|
493
|
+
export declare function isCustodyPinRef(ref: string): boolean;
|
|
494
|
+
export declare function catalogRuleRef(catalog: ScopeCatalogRef, ruleID: string): string;
|
|
495
|
+
/**
|
|
496
|
+
* Whether a ref is one of the catalog's rule refs. Catalog IDs may contain `:`, so a prefix
|
|
497
|
+
* alone would also claim the refs of a catalog whose ID extends this one.
|
|
498
|
+
*/
|
|
499
|
+
export declare function isCatalogRuleRef(ref: string, catalog: ScopeCatalogRef): boolean;
|
|
500
|
+
/** A document holding a ref that may be one of a catalog's rule refs. */
|
|
501
|
+
export type CatalogRefHolder = {
|
|
502
|
+
document_id: string;
|
|
503
|
+
ref: string;
|
|
504
|
+
};
|
|
505
|
+
/**
|
|
506
|
+
* The refs that start with a catalog's rule-ref prefix: a bytewise range rather
|
|
507
|
+
* than LIKE, whose wildcards and escape character catalog IDs may contain.
|
|
508
|
+
* On a Postgres adapter it compares `ref collate "C"`, which the ref index is
|
|
509
|
+
* built on. The caller keeps only the catalog's own refs with
|
|
510
|
+
* `isCatalogRuleRef`. Exported so the plan of the exact statement can be
|
|
511
|
+
* checked.
|
|
512
|
+
*/
|
|
513
|
+
export declare function catalogRefHoldersQuery(db: Kysely<GraphTables>, adapter: Adapter, catalog: ScopeCatalogRef): import("kysely").SelectQueryBuilder<GraphTables, "kubun_graph_document_refs", {
|
|
514
|
+
document_id: string;
|
|
515
|
+
ref: string;
|
|
516
|
+
}>;
|
|
517
|
+
/** One row of a document-leaf page: a document and one applied mutation of it, if any. */
|
|
518
|
+
type LeafPageSQLRow = {
|
|
519
|
+
id: string;
|
|
520
|
+
owner: string;
|
|
521
|
+
authored_here: unknown;
|
|
522
|
+
mutation_hash: string | null;
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* The statement one model's keyset leaf page runs: matching documents after
|
|
526
|
+
* `after` (and up to `through`) in bytewise ID order, at most `limit`, each with
|
|
527
|
+
* whether it was created here and joined to its applied mutations. Exported so
|
|
528
|
+
* the plan of the exact statement can be checked.
|
|
529
|
+
*/
|
|
530
|
+
export declare function documentLeafPageStatement(params: {
|
|
531
|
+
modelID: string;
|
|
532
|
+
rules: ReadonlyArray<DocumentLeafRule>;
|
|
533
|
+
after: string | null;
|
|
534
|
+
through: string | null;
|
|
535
|
+
limit: number;
|
|
536
|
+
postgres: boolean;
|
|
537
|
+
groupReadPredicate?: RawBuilder<boolean>;
|
|
538
|
+
}): RawBuilder<LeafPageSQLRow>;
|
|
539
|
+
export declare function createGraphStore(db: Kysely<GraphTables>, adapter: Adapter, context?: StoreAPIContext): GraphStoreAPI;
|
|
540
|
+
export {};
|