@haverstack/core 0.36.0 → 0.38.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/README.md +19 -15
- package/dist/access.d.ts +4 -6
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +7 -8
- package/dist/access.js.map +1 -1
- package/dist/adapter-entry.d.ts +7 -6
- package/dist/adapter-entry.d.ts.map +1 -1
- package/dist/adapter-entry.js +6 -5
- package/dist/adapter-entry.js.map +1 -1
- package/dist/attachment-download.d.ts +3 -1
- package/dist/attachment-download.d.ts.map +1 -1
- package/dist/attachment-download.js +1 -1
- package/dist/attachment-download.js.map +1 -1
- package/dist/changes.d.ts +22 -16
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +43 -32
- package/dist/changes.js.map +1 -1
- package/dist/combine.d.ts +1 -1
- package/dist/combine.js +6 -6
- package/dist/combine.js.map +1 -1
- package/dist/errors.d.ts +24 -12
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +32 -17
- package/dist/errors.js.map +1 -1
- package/dist/grants.d.ts +15 -24
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +14 -13
- package/dist/grants.js.map +1 -1
- package/dist/identity-bindings.js +2 -2
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/dist/query-validation.d.ts +11 -11
- package/dist/query-validation.d.ts.map +1 -1
- package/dist/query-validation.js +41 -36
- package/dist/query-validation.js.map +1 -1
- package/dist/record-changes.d.ts +11 -10
- package/dist/record-changes.d.ts.map +1 -1
- package/dist/record-changes.js +33 -25
- package/dist/record-changes.js.map +1 -1
- package/dist/record-id.d.ts +3 -3
- package/dist/record-id.js +8 -8
- package/dist/record-id.js.map +1 -1
- package/dist/scoped-stack.d.ts +78 -33
- package/dist/scoped-stack.d.ts.map +1 -1
- package/dist/scoped-stack.js +119 -89
- package/dist/scoped-stack.js.map +1 -1
- package/dist/stack-reads.d.ts +2 -2
- package/dist/stack-reads.js +5 -5
- package/dist/stack-reads.js.map +1 -1
- package/dist/stack.d.ts +162 -154
- package/dist/stack.d.ts.map +1 -1
- package/dist/stack.js +307 -290
- package/dist/stack.js.map +1 -1
- package/dist/testing.d.ts +17 -17
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +46 -42
- package/dist/testing.js.map +1 -1
- package/dist/types.d.ts +169 -143
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/wire-entry.d.ts +5 -6
- package/dist/wire-entry.d.ts.map +1 -1
- package/dist/wire-entry.js +5 -11
- package/dist/wire-entry.js.map +1 -1
- package/dist/wire-record.d.ts +4 -4
- package/dist/wire-record.d.ts.map +1 -1
- package/dist/wire-record.js +10 -10
- package/dist/wire-record.js.map +1 -1
- package/dist/wire-request.d.ts +2 -2
- package/dist/wire-request.d.ts.map +1 -1
- package/dist/wire-request.js +103 -61
- package/dist/wire-request.js.map +1 -1
- package/package.json +1 -1
package/dist/stack.d.ts
CHANGED
|
@@ -9,13 +9,20 @@
|
|
|
9
9
|
* - Content validation on write
|
|
10
10
|
* - Migration registry and explicit, owner-driven migrateAll()
|
|
11
11
|
* - Version snapshotting on update
|
|
12
|
-
* - Soft and
|
|
12
|
+
* - Soft delete and purge
|
|
13
13
|
*
|
|
14
14
|
* Apps should never talk to a StackAdapter directly.
|
|
15
15
|
*/
|
|
16
|
-
import type { StackRecord, StackType, TypeSchema, TypeId, StackAdapter, StackQuery, QueryResult, AuthorityAssociation, DataAssociation, Migration, RecordVersion,
|
|
17
|
-
import type { GrantQuery
|
|
16
|
+
import type { StackRecord, StackType, TypeSchema, TypeId, BaseId, StackAdapter, StackQuery, QueryResult, AuthorityAssociation, DataAssociation, Migration, RecordVersion, StackCapabilities, IfVersionOptions, GrantContent, TypeGrant, PutAttachmentOptions, AttachmentContent, FileId, EntityId, AppId, RecordId, Actor, ActorOptions, RecordChange, RecordChangeSet, SubscribeOptions, Unsubscribe, JournalQuery, RecordJournalEntry } from './types.js';
|
|
17
|
+
import type { GrantQuery } from './grants.js';
|
|
18
18
|
import { ScopedStack } from './scoped-stack.js';
|
|
19
|
+
/**
|
|
20
|
+
* An Actor in the one form `Stack` stores: a `principalId` equal to the
|
|
21
|
+
* subject is dropped, so "acted as itself" has a single spelling, and an
|
|
22
|
+
* empty id is refused rather than stored as a name for nobody.
|
|
23
|
+
* See docs/spec/data-model.md § Actor.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeActor(actor: Actor | undefined): Actor | undefined;
|
|
19
26
|
export type CreateRecordOptions = {
|
|
20
27
|
/**
|
|
21
28
|
* Client-minted record ID. Must be 12 lowercase Crockford base-32
|
|
@@ -23,17 +30,16 @@ export type CreateRecordOptions = {
|
|
|
23
30
|
* library generate one. See Stack.create() and ScopedStack.create()
|
|
24
31
|
* for the validation each applies.
|
|
25
32
|
*/
|
|
26
|
-
id?:
|
|
27
|
-
parentId?:
|
|
28
|
-
entityId?: EntityId;
|
|
29
|
-
/** Reverse-DNS identifier of the writing software — see AppId. */
|
|
30
|
-
appId?: AppId;
|
|
33
|
+
id?: RecordId;
|
|
34
|
+
parentId?: RecordId;
|
|
31
35
|
/**
|
|
32
|
-
* The
|
|
33
|
-
*
|
|
34
|
-
*
|
|
36
|
+
* The author. ScopedStack sets this from its own identities; callers of
|
|
37
|
+
* plain Stack supply it only when reconstructing an attributed write.
|
|
38
|
+
* See StackRecord.createdBy.
|
|
35
39
|
*/
|
|
36
|
-
|
|
40
|
+
createdBy?: Actor;
|
|
41
|
+
/** Reverse-DNS identifier of the writing software — see AppId. */
|
|
42
|
+
appId?: AppId;
|
|
37
43
|
permissions?: AuthorityAssociation[];
|
|
38
44
|
associations?: DataAssociation[];
|
|
39
45
|
/**
|
|
@@ -69,14 +75,6 @@ export type BackdatableCreateRecordOptions = CreateRecordOptions & {
|
|
|
69
75
|
*/
|
|
70
76
|
updatedAt?: Date;
|
|
71
77
|
};
|
|
72
|
-
export type ScopedStackOptions = {
|
|
73
|
-
/**
|
|
74
|
-
* The entity a delegated app acts for. Omit when the principal acts as
|
|
75
|
-
* itself — the case for an app riding its user's identity, which needs
|
|
76
|
-
* no delegation. See docs/spec/identity.md § App.
|
|
77
|
-
*/
|
|
78
|
-
onBehalfOf?: EntityId;
|
|
79
|
-
};
|
|
80
78
|
export type StackOptions = {
|
|
81
79
|
/**
|
|
82
80
|
* Ensures the owner's own `_entity` profile record exists, creating it on
|
|
@@ -109,7 +107,8 @@ export type CollectAttachmentGarbageOptions = {
|
|
|
109
107
|
dryRun?: boolean;
|
|
110
108
|
};
|
|
111
109
|
export type CollectAttachmentGarbageResult = {
|
|
112
|
-
|
|
110
|
+
/** The files collected — or, on a dry run, the ones that would be. */
|
|
111
|
+
deletedFileIds: FileId[];
|
|
113
112
|
reclaimedBytes: number;
|
|
114
113
|
};
|
|
115
114
|
export type GetRecordOptions = {
|
|
@@ -120,18 +119,9 @@ export type GetRecordOptions = {
|
|
|
120
119
|
*/
|
|
121
120
|
presentAt?: 'stored' | 'latest';
|
|
122
121
|
};
|
|
123
|
-
/**
|
|
124
|
-
* Opt-in optimistic-concurrency precondition, accepted by every mutation
|
|
125
|
-
* that bumps a record's version. On mismatch the mutation throws
|
|
126
|
-
* StackVersionConflictError and changes nothing; omit to keep
|
|
127
|
-
* last-writer-wins. See docs/spec/versioning.md § Optimistic concurrency (`ifVersion`).
|
|
128
|
-
*/
|
|
129
|
-
export type IfVersionOptions = {
|
|
130
|
-
ifVersion?: number;
|
|
131
|
-
};
|
|
132
122
|
export type DeleteRecordOptions = IfVersionOptions & {
|
|
133
123
|
/** If true, permanently remove the record and all its history. Default: false */
|
|
134
|
-
|
|
124
|
+
purge?: boolean;
|
|
135
125
|
};
|
|
136
126
|
/**
|
|
137
127
|
* What a delete reports back. Information, not action: a purge never
|
|
@@ -149,7 +139,26 @@ export type DeleteResult = {
|
|
|
149
139
|
*/
|
|
150
140
|
referencedFileIds: FileId[];
|
|
151
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* What deleteAndReturn() reports back — DeleteResult plus the record itself,
|
|
144
|
+
* captured inside the same atomic operation as the destroy rather than a
|
|
145
|
+
* read beforehand. See Stack.deleteAndReturn().
|
|
146
|
+
*/
|
|
147
|
+
export type DeleteAndReturnResult = DeleteResult & {
|
|
148
|
+
/**
|
|
149
|
+
* The record as it stood at the moment of deletion: immediately before
|
|
150
|
+
* destruction for a purge, or the resulting tombstone for a soft
|
|
151
|
+
* delete. Null only for the purge no-op — there was nothing to
|
|
152
|
+
* delete, and nothing to report; every other outcome throws instead of
|
|
153
|
+
* returning null (see Stack.delete()'s own no-op cases).
|
|
154
|
+
*/
|
|
155
|
+
record: StackRecord | null;
|
|
156
|
+
};
|
|
157
|
+
/** The argument to Stack.defineType(). */
|
|
152
158
|
export type DefineTypeOptions = {
|
|
159
|
+
id: TypeId;
|
|
160
|
+
name: string;
|
|
161
|
+
schema: TypeSchema;
|
|
153
162
|
migratesFrom?: TypeId;
|
|
154
163
|
};
|
|
155
164
|
/**
|
|
@@ -158,11 +167,11 @@ export type DefineTypeOptions = {
|
|
|
158
167
|
* and work equally well with a full Stack or a permission-scoped view.
|
|
159
168
|
*/
|
|
160
169
|
export interface StackClient {
|
|
161
|
-
readonly
|
|
170
|
+
readonly capabilities: StackCapabilities;
|
|
162
171
|
create<T extends Record<string, unknown> = Record<string, unknown>>(typeId: TypeId, content: T, opts?: CreateRecordOptions): Promise<StackRecord & {
|
|
163
172
|
content: T;
|
|
164
173
|
}>;
|
|
165
|
-
get(id:
|
|
174
|
+
get(id: RecordId, opts?: GetRecordOptions): Promise<StackRecord | null>;
|
|
166
175
|
query(query?: StackQuery): Promise<QueryResult>;
|
|
167
176
|
/**
|
|
168
177
|
* Resolve a DID to its `_entity` card — family-wide and soft-deleted
|
|
@@ -180,35 +189,42 @@ export interface StackClient {
|
|
|
180
189
|
* producing one version where it names `contentPatch`, and none where it
|
|
181
190
|
* doesn't. Keys are read for presence, so `unlisted: false`
|
|
182
191
|
* and `parentId: null` are changes; a change set naming no key at all is
|
|
183
|
-
* a
|
|
192
|
+
* a StackBadRequestError. Under ScopedStack each key carries its own gate and
|
|
184
193
|
* one refused key refuses the call.
|
|
185
194
|
* See docs/spec/data-model.md § Mutations.
|
|
186
195
|
*/
|
|
187
|
-
mutate(id:
|
|
196
|
+
mutate(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
188
197
|
/** mutate() with `contentPatch` alone — the common case, named for it. */
|
|
189
|
-
patchContent(id:
|
|
198
|
+
patchContent(id: RecordId, patch: Record<string, unknown | null>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
190
199
|
/**
|
|
191
200
|
* Add an association. Never bumps `version`/`updatedAt` and takes no
|
|
192
201
|
* `ifVersion` — a set-add composes regardless of write order.
|
|
193
202
|
* See docs/spec/versioning.md § Version history.
|
|
194
203
|
*/
|
|
195
|
-
associate(id:
|
|
204
|
+
associate(id: RecordId, association: DataAssociation): Promise<StackRecord>;
|
|
196
205
|
/** Remove an association. Never bumps `version`/`updatedAt` — see associate(). */
|
|
197
|
-
dissociate(id:
|
|
206
|
+
dissociate(id: RecordId, association: DataAssociation): Promise<StackRecord>;
|
|
198
207
|
/**
|
|
199
208
|
* Extend who reaches a record by one element — the record-level mirror of
|
|
200
|
-
* the type-level `
|
|
209
|
+
* the type-level `grantType()`, and the amending spelling of the
|
|
201
210
|
* `permissions` key, which replaces the whole set. No-bump, like
|
|
202
211
|
* associate(). See docs/spec/access-control.md § Record-level permissions.
|
|
203
212
|
*/
|
|
204
|
-
grantAccess(id:
|
|
213
|
+
grantAccess(id: RecordId, permission: AuthorityAssociation): Promise<StackRecord>;
|
|
205
214
|
/** Withdraw one element of who reaches a record — see grantAccess(). */
|
|
206
|
-
revokeAccess(id:
|
|
207
|
-
delete(id:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
revokeAccess(id: RecordId, permission: AuthorityAssociation): Promise<StackRecord>;
|
|
216
|
+
delete(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteResult>;
|
|
217
|
+
/**
|
|
218
|
+
* delete(), plus the record it acted on — read and destroyed as one
|
|
219
|
+
* atomic operation, so a caller that needs the record for its own
|
|
220
|
+
* response (e.g. a server building a purge's body) never opens a
|
|
221
|
+
* gap between reading it and destroying it. See Stack.deleteAndReturn().
|
|
222
|
+
*/
|
|
223
|
+
deleteAndReturn(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteAndReturnResult>;
|
|
224
|
+
undelete(id: RecordId, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
225
|
+
getVersions(id: RecordId): Promise<RecordVersion[]>;
|
|
226
|
+
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
227
|
+
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
212
228
|
/**
|
|
213
229
|
* A record's change journal, oldest first. On the mutate surface, on the
|
|
214
230
|
* same footing as getVersions() — a plain reader is refused.
|
|
@@ -218,7 +234,7 @@ export interface StackClient {
|
|
|
218
234
|
* unconditionally, so an adapter with nothing to read refuses and names
|
|
219
235
|
* why instead. See docs/spec/journal.md § Reading it.
|
|
220
236
|
*/
|
|
221
|
-
getJournal(id:
|
|
237
|
+
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
222
238
|
/**
|
|
223
239
|
* Commit a per-record migration: change `typeId` and `content` together,
|
|
224
240
|
* validated against `toTypeId`'s schema. The only way a record's typeId
|
|
@@ -227,12 +243,12 @@ export interface StackClient {
|
|
|
227
243
|
* record's version (see docs/spec/versioning.md § Optimistic
|
|
228
244
|
* concurrency); over the wire that is `If-Match`.
|
|
229
245
|
*/
|
|
230
|
-
commitMigration(id:
|
|
231
|
-
getAttachment(fileId:
|
|
232
|
-
putAttachment(data: Uint8Array,
|
|
246
|
+
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
247
|
+
getAttachment(fileId: FileId): Promise<Uint8Array>;
|
|
248
|
+
putAttachment(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord & {
|
|
233
249
|
content: AttachmentContent;
|
|
234
250
|
}>;
|
|
235
|
-
deleteAttachment(fileId:
|
|
251
|
+
deleteAttachment(fileId: FileId): Promise<void>;
|
|
236
252
|
collectAttachmentGarbage(opts?: CollectAttachmentGarbageOptions): Promise<CollectAttachmentGarbageResult>;
|
|
237
253
|
subscribe(handler: (change: RecordChange) => void, opts?: SubscribeOptions): Promise<Unsubscribe>;
|
|
238
254
|
}
|
|
@@ -277,20 +293,11 @@ export declare class Stack implements StackClient {
|
|
|
277
293
|
* carries `appId`, which ActorOptions has no field for.
|
|
278
294
|
*/
|
|
279
295
|
private static createActor;
|
|
280
|
-
/**
|
|
281
|
-
* The requester behind a write that stamps nothing on the record itself —
|
|
282
|
-
* a hard delete, which leaves no record to stamp, and associate()/
|
|
283
|
-
* dissociate(), which don't bump and so don't touch updatedBy/updatedVia.
|
|
284
|
-
* Hard delete is owner-acting-alone only, so it never has a principal to
|
|
285
|
-
* name beside the subject; associate()/dissociate() can run delegated,
|
|
286
|
-
* so `updatedVia` rides along here when present.
|
|
287
|
-
*/
|
|
288
|
-
private static actorFrom;
|
|
289
296
|
private getTypeCached;
|
|
290
297
|
/**
|
|
291
|
-
*
|
|
298
|
+
* Open a Stack over an adapter. Reads ownerEntityId and timezone from the adapter.
|
|
292
299
|
*/
|
|
293
|
-
static
|
|
300
|
+
static open(adapter: StackAdapter, opts?: StackOptions): Promise<Stack>;
|
|
294
301
|
/**
|
|
295
302
|
* Idempotent bootstrap for StackOptions.ownerProfile. Filters by family
|
|
296
303
|
* only (content filtering is capability-gated) and matches `content.did`
|
|
@@ -306,33 +313,25 @@ export declare class Stack implements StackClient {
|
|
|
306
313
|
getEntityByDid(did: EntityId): Promise<StackRecord | null>;
|
|
307
314
|
getOwnerEntity(): Promise<StackRecord | null>;
|
|
308
315
|
get timezone(): string | undefined;
|
|
309
|
-
get
|
|
316
|
+
get capabilities(): StackCapabilities;
|
|
310
317
|
/**
|
|
311
318
|
* Get a permission-scoped view of this Stack, as if requests came from
|
|
312
|
-
* the given
|
|
313
|
-
* unscoped; use asEntity() when one Stack serves multiple,
|
|
314
|
-
* untrusted, entities.
|
|
315
|
-
*
|
|
316
|
-
* `onBehalfOf` names the subject a delegated app acts for: authority is
|
|
317
|
-
* then the intersection of both parties' grants, while authorship and
|
|
318
|
-
* `-own` resolve against the subject. See
|
|
319
|
+
* the given entity acting as itself (null = anonymous). Plain Stack
|
|
320
|
+
* methods are unscoped; use asEntity() when one Stack serves multiple,
|
|
321
|
+
* possibly untrusted, entities. See
|
|
319
322
|
* docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
320
323
|
*/
|
|
321
|
-
asEntity(entityId: EntityId | null
|
|
324
|
+
asEntity(entityId: EntityId | null): ScopedStack;
|
|
322
325
|
/**
|
|
323
|
-
* Scope to an
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
* case where they are equal — it would surface only once delegation is in
|
|
330
|
-
* use, as authority no longer fenced by the app's grants and every write
|
|
331
|
-
* attributed to the app rather than the person. Taking the pair whole
|
|
332
|
-
* removes the order to get wrong. See
|
|
333
|
-
* docs/spec/access-control.md § Delegation: principal and subject.
|
|
326
|
+
* Scope to an Actor — a delegated app acting for its user, or a
|
|
327
|
+
* TokenSession exactly as StackTokenStore.lookupToken() returns it, which
|
|
328
|
+
* is what a server should reach for at its request boundary. Authority is
|
|
329
|
+
* the intersection of both parties' grants, while authorship and `-own`
|
|
330
|
+
* resolve against the subject. Taking the pair whole leaves no order to
|
|
331
|
+
* swap. See docs/spec/access-control.md § Delegation: principal and subject.
|
|
334
332
|
*/
|
|
335
|
-
|
|
333
|
+
asActor(actor: Actor): ScopedStack;
|
|
334
|
+
private scope;
|
|
336
335
|
/**
|
|
337
336
|
* Define and persist a Type; call at app startup before creating records
|
|
338
337
|
* of the type. Redefining an existing typeId is checked against the
|
|
@@ -340,7 +339,7 @@ export declare class Stack implements StackClient {
|
|
|
340
339
|
* anything beyond additive evolution throws StackSchemaDriftError. See
|
|
341
340
|
* docs/spec/data-model.md § Schema drift detection.
|
|
342
341
|
*/
|
|
343
|
-
defineType(id
|
|
342
|
+
defineType({ id, name, schema, migratesFrom }: DefineTypeOptions): Promise<StackType>;
|
|
344
343
|
getType(id: TypeId): Promise<StackType | null>;
|
|
345
344
|
/** Refreshes typeCache wholesale — the explicit way to see a rename made by another writer. */
|
|
346
345
|
listTypes(): Promise<StackType[]>;
|
|
@@ -372,7 +371,7 @@ export declare class Stack implements StackClient {
|
|
|
372
371
|
* too, validates each result before writing, and aborts on the first
|
|
373
372
|
* validation failure. See docs/spec/data-model.md § Type migrations.
|
|
374
373
|
*/
|
|
375
|
-
migrateAll(
|
|
374
|
+
migrateAll(baseId: BaseId): Promise<{
|
|
376
375
|
migrated: number;
|
|
377
376
|
}>;
|
|
378
377
|
/**
|
|
@@ -402,7 +401,7 @@ export declare class Stack implements StackClient {
|
|
|
402
401
|
* { presentAt: 'latest' } to migrate in memory; only migrateAll()
|
|
403
402
|
* commits migrations to disk.
|
|
404
403
|
*/
|
|
405
|
-
get(id:
|
|
404
|
+
get(id: RecordId, opts?: GetRecordOptions): Promise<StackRecord | null>;
|
|
406
405
|
/**
|
|
407
406
|
* Apply a change set as one atomic write — see the StackClient
|
|
408
407
|
* declaration above for what it accepts. Atomicity is what it is for: a
|
|
@@ -413,13 +412,13 @@ export declare class Stack implements StackClient {
|
|
|
413
412
|
* against the record's *current* stored type; `typeId` never changes here.
|
|
414
413
|
* See docs/spec/data-model.md § Mutations.
|
|
415
414
|
*/
|
|
416
|
-
mutate(id:
|
|
415
|
+
mutate(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
417
416
|
/**
|
|
418
417
|
* mutate() with `contentPatch` alone. The common case by a wide margin,
|
|
419
418
|
* and named for what it does rather than for a symmetry with create()
|
|
420
419
|
* that a patch does not have.
|
|
421
420
|
*/
|
|
422
|
-
patchContent(id:
|
|
421
|
+
patchContent(id: RecordId, patch: Record<string, unknown | null>, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
423
422
|
/**
|
|
424
423
|
* Every check a change set owes before anything is written, in one pass:
|
|
425
424
|
* one refused key refuses the call, so none of them may run after a
|
|
@@ -455,7 +454,7 @@ export declare class Stack implements StackClient {
|
|
|
455
454
|
* file. What a re-point overwrote is kept only by the journal, on that
|
|
456
455
|
* entry's `repoint`. See docs/spec/journal.md § The entry.
|
|
457
456
|
*/
|
|
458
|
-
associate(id:
|
|
457
|
+
associate(id: RecordId, association: DataAssociation, opts?: ActorOptions): Promise<StackRecord>;
|
|
459
458
|
/**
|
|
460
459
|
* Remove an association from a record — see associate(). Matched by kind,
|
|
461
460
|
* label and payload; a no-op if not found. The emitted event names the
|
|
@@ -463,7 +462,7 @@ export declare class Stack implements StackClient {
|
|
|
463
462
|
* `attachmentRecordId` describes nothing current once it is gone; the
|
|
464
463
|
* journal is where it survives.
|
|
465
464
|
*/
|
|
466
|
-
dissociate(id:
|
|
465
|
+
dissociate(id: RecordId, association: DataAssociation, opts?: ActorOptions): Promise<StackRecord>;
|
|
467
466
|
/**
|
|
468
467
|
* Extend who reaches a record by one element. The spelling that survives
|
|
469
468
|
* two admins sharing a record at once: a `permissions` key write replaces
|
|
@@ -471,13 +470,13 @@ export declare class Stack implements StackClient {
|
|
|
471
470
|
* earlier granted. No-bump, like associate(); an element the record
|
|
472
471
|
* already carries is a no-op.
|
|
473
472
|
*/
|
|
474
|
-
grantAccess(id:
|
|
473
|
+
grantAccess(id: RecordId, permission: AuthorityAssociation, opts?: ActorOptions): Promise<StackRecord>;
|
|
475
474
|
/**
|
|
476
475
|
* Withdraw one element of who reaches a record — see grantAccess() for
|
|
477
476
|
* why this is a verb rather than a key write. An element the record does
|
|
478
477
|
* not carry is a no-op. Returns the record as it now stands.
|
|
479
478
|
*/
|
|
480
|
-
revokeAccess(id:
|
|
479
|
+
revokeAccess(id: RecordId, permission: AuthorityAssociation, opts?: ActorOptions): Promise<StackRecord>;
|
|
481
480
|
/**
|
|
482
481
|
* Hold a permission set to the cross-element invariant — see
|
|
483
482
|
* validatePermissions() in access.ts for why it reads the post-state.
|
|
@@ -514,7 +513,7 @@ export declare class Stack implements StackClient {
|
|
|
514
513
|
*/
|
|
515
514
|
private assertNoParentCycle;
|
|
516
515
|
/**
|
|
517
|
-
* Soft-delete a record (default) or
|
|
516
|
+
* Soft-delete a record (default) or purge it permanently, removing
|
|
518
517
|
* the record and its version history. Soft delete snapshots and bumps
|
|
519
518
|
* version; a no-op if already deleted. `_config` is never deletable
|
|
520
519
|
* (docs/spec.md § The `_config` record). See docs/spec/versioning.md
|
|
@@ -525,8 +524,23 @@ export declare class Stack implements StackClient {
|
|
|
525
524
|
* destroys the only rows naming them, so a caller who means to erase the
|
|
526
525
|
* bytes too has nowhere else to read the argument from afterwards. See
|
|
527
526
|
* docs/spec/attachments.md § A purge strands the bytes it referenced.
|
|
527
|
+
*
|
|
528
|
+
* deleteAndReturn() is this plus the record itself; reach for that
|
|
529
|
+
* instead when the caller needs the record too — building a response
|
|
530
|
+
* body from a separate read beforehand is exactly the race and the extra
|
|
531
|
+
* round trip it exists to remove.
|
|
532
|
+
*/
|
|
533
|
+
delete(id: RecordId, opts?: DeleteRecordOptions & ActorOptions): Promise<DeleteResult>;
|
|
534
|
+
/**
|
|
535
|
+
* delete(), reporting the record it acted on alongside the files it
|
|
536
|
+
* stranded: as it stood immediately before destruction for a
|
|
537
|
+
* purge, or as the resulting tombstone for a soft delete. Both are
|
|
538
|
+
* captured inside the same write that destroys or tombstones the record,
|
|
539
|
+
* never a read beforehand — a read-then-delete would leave a window
|
|
540
|
+
* where a concurrent write can land, get destroyed or overwritten by
|
|
541
|
+
* this call, and never appear in the record this returns.
|
|
528
542
|
*/
|
|
529
|
-
|
|
543
|
+
deleteAndReturn(id: RecordId, opts?: DeleteRecordOptions & ActorOptions): Promise<DeleteAndReturnResult>;
|
|
530
544
|
/**
|
|
531
545
|
* The files a record references, by the same definition
|
|
532
546
|
* deleteAttachment() and the garbage sweep use: attachment associations
|
|
@@ -537,11 +551,11 @@ export declare class Stack implements StackClient {
|
|
|
537
551
|
private referencedFileIds;
|
|
538
552
|
/**
|
|
539
553
|
* Reverse a soft delete. Idempotent — undeleting a record that isn't
|
|
540
|
-
* deleted returns it unchanged.
|
|
554
|
+
* deleted returns it unchanged. Purged records are gone, so this
|
|
541
555
|
* throws StackNotFoundError for them just like any other missing record.
|
|
542
556
|
* Snapshots and bumps version, same as delete().
|
|
543
557
|
*/
|
|
544
|
-
undelete(id:
|
|
558
|
+
undelete(id: RecordId, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
545
559
|
/**
|
|
546
560
|
* Query records. filter.baseId matches every version of a type family,
|
|
547
561
|
* resolved against registered Types. Results come back exactly as
|
|
@@ -556,7 +570,7 @@ export declare class Stack implements StackClient {
|
|
|
556
570
|
* the caller can short-circuit without an adapter round trip.
|
|
557
571
|
*/
|
|
558
572
|
private resolveBaseIdFilter;
|
|
559
|
-
getVersions(id:
|
|
573
|
+
getVersions(id: RecordId): Promise<RecordVersion[]>;
|
|
560
574
|
/**
|
|
561
575
|
* A record's change journal, oldest first — what moved, who moved it, and
|
|
562
576
|
* the association deltas nothing else retains. `ScopedStack` applies the
|
|
@@ -566,15 +580,15 @@ export declare class Stack implements StackClient {
|
|
|
566
580
|
* a destroyed log and an empty one are not the same answer.
|
|
567
581
|
* See docs/spec/journal.md § Reading it.
|
|
568
582
|
*/
|
|
569
|
-
getJournal(id:
|
|
570
|
-
getVersion(id:
|
|
583
|
+
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
584
|
+
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
571
585
|
/**
|
|
572
586
|
* Restore a record to a previous version by creating a new version —
|
|
573
587
|
* never rewrites history. The snapshot is validated against its own
|
|
574
588
|
* stored typeId, and puts back `content` and `typeId` alone: a snapshot
|
|
575
589
|
* carries nothing else. See docs/spec/versioning.md § Restore semantics.
|
|
576
590
|
*/
|
|
577
|
-
restoreVersion(id:
|
|
591
|
+
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
578
592
|
/**
|
|
579
593
|
* Commit a per-record migration — the single-record counterpart to
|
|
580
594
|
* migrateAll(), with `content` supplied by the caller rather than by a
|
|
@@ -587,7 +601,7 @@ export declare class Stack implements StackClient {
|
|
|
587
601
|
* either half would make migrate a second, unguarded write path to a
|
|
588
602
|
* state create()/mutate() refuse to reach.
|
|
589
603
|
*/
|
|
590
|
-
commitMigration(id:
|
|
604
|
+
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
591
605
|
/**
|
|
592
606
|
* The checked migration write, shared by commitMigration() and
|
|
593
607
|
* migrateAll(). Takes the record already in hand rather than an id: a
|
|
@@ -625,8 +639,8 @@ export declare class Stack implements StackClient {
|
|
|
625
639
|
*/
|
|
626
640
|
private checkBindingsOnMigrate;
|
|
627
641
|
/**
|
|
628
|
-
* A unique binding field is what a lookup resolves *by* —
|
|
629
|
-
* `principalId` by `_app.did`, its `
|
|
642
|
+
* A unique binding field is what a lookup resolves *by* — an Actor's
|
|
643
|
+
* `principalId` by `_app.did`, its `subjectId` by `_entity.did`. Two cards
|
|
630
644
|
* claiming one value would leave that lookup without a single answer, and
|
|
631
645
|
* ambiguity is all an impersonating card needs. Enforced here rather than
|
|
632
646
|
* by schema, since uniqueness is a property of the set, not of the value.
|
|
@@ -697,16 +711,16 @@ export declare class Stack implements StackClient {
|
|
|
697
711
|
private checkConfigEntityIdUnchanged;
|
|
698
712
|
/**
|
|
699
713
|
* Store bytes and create an _attachment@1 metadata record (owner-
|
|
700
|
-
* attributed, no
|
|
714
|
+
* attributed, no createdBy), returning that record — `content.fileId`
|
|
701
715
|
* addresses the bytes, `id` addresses the metadata. Delegates to the
|
|
702
716
|
* adapter's atomic putAttachmentWithMetadata() when implemented, trusting
|
|
703
717
|
* the returned record as backend-authoritative; otherwise falls back to
|
|
704
718
|
* bytes-then-create(). See docs/spec/wire-format.md § Attachments.
|
|
705
719
|
*/
|
|
706
|
-
putAttachment(data: Uint8Array,
|
|
720
|
+
putAttachment(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord & {
|
|
707
721
|
content: AttachmentContent;
|
|
708
722
|
}>;
|
|
709
|
-
getAttachment(fileId:
|
|
723
|
+
getAttachment(fileId: FileId): Promise<Uint8Array>;
|
|
710
724
|
/**
|
|
711
725
|
* Every `_attachment` record describing `fileId`, earliest-recorded
|
|
712
726
|
* first — so `records[0]` is the one that establishes the file's
|
|
@@ -734,7 +748,7 @@ export declare class Stack implements StackClient {
|
|
|
734
748
|
* still references the file, StackNotFoundError if neither metadata
|
|
735
749
|
* records nor bytes exist.
|
|
736
750
|
*/
|
|
737
|
-
deleteAttachment(fileId:
|
|
751
|
+
deleteAttachment(fileId: FileId, opts?: ActorOptions): Promise<void>;
|
|
738
752
|
/**
|
|
739
753
|
* Non-atomic fallback for adapters that don't implement
|
|
740
754
|
* deleteUnreferencedAttachmentRecords(): a concurrent associate() can
|
|
@@ -766,16 +780,13 @@ export declare class Stack implements StackClient {
|
|
|
766
780
|
*
|
|
767
781
|
* The subscription's own filter goes to the relay rather than being
|
|
768
782
|
* applied on the way back: the emitter at the far end holds the record,
|
|
769
|
-
* so it can answer `
|
|
783
|
+
* so it can answer `createdBy` and `parentId`, which the envelope
|
|
770
784
|
* deliberately does not carry. That is also why a relay is opened per
|
|
771
785
|
* subscription rather than shared.
|
|
772
786
|
*/
|
|
773
787
|
private openRelay;
|
|
774
|
-
/**
|
|
775
|
-
|
|
776
|
-
* ScopedStack can refuse a scope it cannot honor; not an app-facing API.
|
|
777
|
-
*/
|
|
778
|
-
get relaysChanges(): boolean;
|
|
788
|
+
/** Whether changes reach this stack from elsewhere. */
|
|
789
|
+
private get relaysChanges();
|
|
779
790
|
/**
|
|
780
791
|
* Flush pending writes to the underlying storage. A no-op for adapters
|
|
781
792
|
* that commit on every call (SQLite, the API adapter); meaningful for
|
|
@@ -790,17 +801,14 @@ export declare class Stack implements StackClient {
|
|
|
790
801
|
* See docs/spec/adapters.md § Lifecycle.
|
|
791
802
|
*/
|
|
792
803
|
close(): Promise<void>;
|
|
793
|
-
/**
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
* `{ kind: 'entity' }` for one DID, `{ kind: 'group' }` for a `_group`
|
|
802
|
-
* Record's roster at a role, `{ kind: 'authenticated' }` for any
|
|
803
|
-
* authenticated entity.
|
|
804
|
+
/** Throws once close() has run. */
|
|
805
|
+
private assertOpen;
|
|
806
|
+
/**
|
|
807
|
+
* Create a _grant record authorizing `grantee` to take `actions` on
|
|
808
|
+
* records of `typeId`: `{ kind: 'entity' }` for one DID, `{ kind: 'group' }`
|
|
809
|
+
* for a `_group` Record's roster at a role, `{ kind: 'authenticated' }` for
|
|
810
|
+
* any authenticated entity. The type-level mirror of grantAccess() —
|
|
811
|
+
* subject first, grantee inside the element.
|
|
804
812
|
*
|
|
805
813
|
* Granting an **app** a `-own` action does not contain it the way the
|
|
806
814
|
* suffix suggests: when that app acts for someone, `-own` is read as the
|
|
@@ -810,13 +818,13 @@ export declare class Stack implements StackClient {
|
|
|
810
818
|
* needs, not the suffix that looks narrowest. See
|
|
811
819
|
* docs/spec/access-control.md § Delegation: principal and subject.
|
|
812
820
|
*
|
|
813
|
-
*
|
|
821
|
+
* `typeOrBaseId` is a versioned TypeId (`"baseId@version"`) or a bare
|
|
822
|
+
* baseId; either names the whole family. See
|
|
814
823
|
* docs/spec/access-control.md § Type-level grants.
|
|
815
824
|
*/
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
}>): Promise<StackRecord[]>;
|
|
825
|
+
grantType(typeOrBaseId: TypeId | BaseId, grant: TypeGrant): Promise<StackRecord & {
|
|
826
|
+
content: GrantContent;
|
|
827
|
+
}>;
|
|
820
828
|
/**
|
|
821
829
|
* List _grant records. Omit `query` for all grants;
|
|
822
830
|
* `{ kind: 'authenticated' }` for only default grants;
|
|
@@ -826,36 +834,36 @@ export declare class Stack implements StackClient {
|
|
|
826
834
|
* (ones naming them, ones naming a group they belong to at a role they
|
|
827
835
|
* hold, plus every default grant) — the same resolution hasGrant() uses.
|
|
828
836
|
*
|
|
829
|
-
* Every arm but `entity` answers identity — what `
|
|
837
|
+
* Every arm but `entity` answers identity — what `grantType()` would have
|
|
830
838
|
* written with the same argument. The `entity` arm answers coverage, so
|
|
831
|
-
* its result is not a preview of what `
|
|
839
|
+
* its result is not a preview of what `revokeType()` would withdraw.
|
|
832
840
|
* See docs/spec/access-control.md § Type-level grants.
|
|
833
841
|
*/
|
|
834
|
-
|
|
842
|
+
listTypeGrants(query?: GrantQuery): Promise<(StackRecord & {
|
|
843
|
+
content: GrantContent;
|
|
844
|
+
})[]>;
|
|
835
845
|
/**
|
|
836
|
-
* The inverse of
|
|
837
|
-
*
|
|
838
|
-
* writes — the grantee is matched whole, role included
|
|
839
|
-
* like any other — the owner can
|
|
846
|
+
* The inverse of grantType(): soft-deletes the _grant records on
|
|
847
|
+
* `typeOrBaseId`'s family matching `grant`, at the same granularity
|
|
848
|
+
* grantType() writes — the grantee is matched whole, role included, and
|
|
849
|
+
* the actions exactly. A soft delete like any other — the owner can
|
|
850
|
+
* undelete a revocation.
|
|
840
851
|
*
|
|
841
|
-
* Returns the grants it withdrew, as they stood
|
|
842
|
-
*
|
|
843
|
-
* is not an error — a
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*/
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
}>): Promise<StackRecord[]>;
|
|
852
|
+
* Returns the grants it withdrew, as they stood: an array, where
|
|
853
|
+
* revokeAccess() returns one Record, because one target can match several
|
|
854
|
+
* _grant records. An empty result is not an error — re-running a
|
|
855
|
+
* revocation has to stay safe. See
|
|
856
|
+
* docs/spec/access-control.md § Listing and revoking.
|
|
857
|
+
*/
|
|
858
|
+
revokeType(typeOrBaseId: TypeId | BaseId, grant: TypeGrant): Promise<(StackRecord & {
|
|
859
|
+
content: GrantContent;
|
|
860
|
+
})[]>;
|
|
851
861
|
/**
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* _grant/_config families are refused — see docs/spec/access-control.md
|
|
856
|
-
* § Type-level grants.
|
|
862
|
+
* Actions must be known GrantAction values, typeIds must be well-formed,
|
|
863
|
+
* and the _grant/_config families are refused — see
|
|
864
|
+
* docs/spec/access-control.md § Type-level grants.
|
|
857
865
|
*/
|
|
858
|
-
private
|
|
866
|
+
private checkGrantValid;
|
|
859
867
|
private seedSystemTypes;
|
|
860
868
|
/**
|
|
861
869
|
* Fast-fail for the ifVersion precondition using the already-fetched
|
|
@@ -868,8 +876,8 @@ export declare class Stack implements StackClient {
|
|
|
868
876
|
* The options every version-bumping adapter write carries: the `ifVersion`
|
|
869
877
|
* precondition, the prior-state snapshot that has to land in the same
|
|
870
878
|
* atomic write, and who to attribute the change to. Taken together so a
|
|
871
|
-
* new mutating verb cannot quietly omit one — `
|
|
872
|
-
* whose absence reads as an undelegated write.
|
|
879
|
+
* new mutating verb cannot quietly omit one — the actor's `principalId`
|
|
880
|
+
* most of all, whose absence reads as an undelegated write.
|
|
873
881
|
* See docs/spec/versioning.md § Version history.
|
|
874
882
|
*/
|
|
875
883
|
private writeOptions;
|