@haverstack/core 0.40.0 → 0.42.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 +121 -59
- package/dist/access.d.ts +34 -36
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +65 -42
- package/dist/access.js.map +1 -1
- package/dist/{combine.d.ts → adapter/combine.d.ts} +8 -1
- package/dist/adapter/combine.d.ts.map +1 -0
- package/dist/{combine.js → adapter/combine.js} +7 -0
- package/dist/adapter/combine.js.map +1 -0
- package/dist/{adapter-entry.d.ts → adapter/index.d.ts} +6 -5
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/{adapter-entry.js → adapter/index.js} +5 -4
- package/dist/adapter/index.js.map +1 -0
- package/dist/{sort.d.ts → adapter/sort.d.ts} +20 -20
- package/dist/adapter/sort.d.ts.map +1 -0
- package/dist/{sort.js → adapter/sort.js} +37 -27
- package/dist/adapter/sort.js.map +1 -0
- package/dist/associations/identity.d.ts +93 -0
- package/dist/associations/identity.d.ts.map +1 -0
- package/dist/associations/identity.js +198 -0
- package/dist/associations/identity.js.map +1 -0
- package/dist/associations/validation.d.ts +90 -0
- package/dist/associations/validation.d.ts.map +1 -0
- package/dist/associations/validation.js +339 -0
- package/dist/associations/validation.js.map +1 -0
- package/dist/attachment-records.d.ts +48 -0
- package/dist/attachment-records.d.ts.map +1 -0
- package/dist/attachment-records.js +52 -0
- package/dist/attachment-records.js.map +1 -0
- package/dist/collection.d.ts +182 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +407 -0
- package/dist/collection.js.map +1 -0
- package/dist/content-match.d.ts +25 -0
- package/dist/content-match.d.ts.map +1 -0
- package/dist/content-match.js +51 -0
- package/dist/content-match.js.map +1 -0
- package/dist/content-translation.d.ts +42 -0
- package/dist/content-translation.d.ts.map +1 -0
- package/dist/content-translation.js +108 -0
- package/dist/content-translation.js.map +1 -0
- package/dist/did/did.d.ts.map +1 -0
- package/dist/{did.js → did/did.js} +3 -4
- package/dist/did/did.js.map +1 -0
- package/dist/{did-entry.d.ts → did/index.d.ts} +1 -1
- package/dist/did/index.d.ts.map +1 -0
- package/dist/{did-entry.js → did/index.js} +3 -3
- package/dist/did/index.js.map +1 -0
- package/dist/errors.d.ts +36 -63
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +35 -58
- package/dist/errors.js.map +1 -1
- package/dist/grants.d.ts +20 -43
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +71 -134
- package/dist/grants.js.map +1 -1
- package/dist/id.d.ts +13 -31
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +13 -31
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +14 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +141 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +219 -0
- package/dist/install.js.map +1 -0
- package/dist/merge.d.ts.map +1 -1
- package/dist/merge.js +5 -11
- package/dist/merge.js.map +1 -1
- package/dist/migration-steps.d.ts +102 -0
- package/dist/migration-steps.d.ts.map +1 -0
- package/dist/migration-steps.js +293 -0
- package/dist/migration-steps.js.map +1 -0
- package/dist/query-validation.d.ts +28 -94
- package/dist/query-validation.d.ts.map +1 -1
- package/dist/query-validation.js +156 -336
- package/dist/query-validation.js.map +1 -1
- package/dist/record-changes.d.ts +2 -117
- package/dist/record-changes.d.ts.map +1 -1
- package/dist/record-changes.js +10 -212
- package/dist/record-changes.js.map +1 -1
- package/dist/schema.d.ts +18 -7
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +59 -30
- package/dist/schema.js.map +1 -1
- package/dist/scoped-stack/authority.d.ts +156 -0
- package/dist/scoped-stack/authority.d.ts.map +1 -0
- package/dist/scoped-stack/authority.js +384 -0
- package/dist/scoped-stack/authority.js.map +1 -0
- package/dist/scoped-stack/scoped-stack.d.ts +338 -0
- package/dist/scoped-stack/scoped-stack.d.ts.map +1 -0
- package/dist/scoped-stack/scoped-stack.js +776 -0
- package/dist/scoped-stack/scoped-stack.js.map +1 -0
- package/dist/scoped-stack/subscription.d.ts +55 -0
- package/dist/scoped-stack/subscription.d.ts.map +1 -0
- package/dist/scoped-stack/subscription.js +110 -0
- package/dist/scoped-stack/subscription.js.map +1 -0
- package/dist/stack/attachments.d.ts +24 -0
- package/dist/stack/attachments.d.ts.map +1 -0
- package/dist/stack/attachments.js +113 -0
- package/dist/stack/attachments.js.map +1 -0
- package/dist/{changes.d.ts → stack/changes.d.ts} +29 -65
- package/dist/stack/changes.d.ts.map +1 -0
- package/dist/{changes.js → stack/changes.js} +32 -66
- package/dist/stack/changes.js.map +1 -0
- package/dist/stack/client.d.ts +271 -0
- package/dist/stack/client.d.ts.map +1 -0
- package/dist/stack/client.js +9 -0
- package/dist/stack/client.js.map +1 -0
- package/dist/stack/identity-bindings.d.ts.map +1 -0
- package/dist/{identity-bindings.js → stack/identity-bindings.js} +8 -14
- package/dist/stack/identity-bindings.js.map +1 -0
- package/dist/stack/install-app.d.ts +22 -0
- package/dist/stack/install-app.d.ts.map +1 -0
- package/dist/stack/install-app.js +260 -0
- package/dist/stack/install-app.js.map +1 -0
- package/dist/stack/integrity.d.ts +94 -0
- package/dist/stack/integrity.d.ts.map +1 -0
- package/dist/stack/integrity.js +268 -0
- package/dist/stack/integrity.js.map +1 -0
- package/dist/{limits.d.ts → stack/limits.d.ts} +2 -5
- package/dist/stack/limits.d.ts.map +1 -0
- package/dist/{limits.js → stack/limits.js} +3 -6
- package/dist/stack/limits.js.map +1 -0
- package/dist/stack/migrations.d.ts +59 -0
- package/dist/stack/migrations.d.ts.map +1 -0
- package/dist/stack/migrations.js +141 -0
- package/dist/stack/migrations.js.map +1 -0
- package/dist/{stack-reads.d.ts → stack/reads.d.ts} +33 -6
- package/dist/stack/reads.d.ts.map +1 -0
- package/dist/{stack-reads.js → stack/reads.js} +49 -7
- package/dist/stack/reads.js.map +1 -0
- package/dist/stack/record-id.d.ts +35 -0
- package/dist/stack/record-id.d.ts.map +1 -0
- package/dist/stack/record-id.js +82 -0
- package/dist/stack/record-id.js.map +1 -0
- package/dist/stack/stack.d.ts +438 -0
- package/dist/stack/stack.d.ts.map +1 -0
- package/dist/stack/stack.js +1366 -0
- package/dist/stack/stack.js.map +1 -0
- package/dist/stack/system-types.d.ts +16 -0
- package/dist/stack/system-types.d.ts.map +1 -0
- package/dist/stack/system-types.js +111 -0
- package/dist/stack/system-types.js.map +1 -0
- package/dist/stack/type-grants.d.ts +20 -0
- package/dist/stack/type-grants.d.ts.map +1 -0
- package/dist/stack/type-grants.js +69 -0
- package/dist/stack/type-grants.js.map +1 -0
- package/dist/stack/write-expectation.d.ts +78 -0
- package/dist/stack/write-expectation.d.ts.map +1 -0
- package/dist/stack/write-expectation.js +71 -0
- package/dist/stack/write-expectation.js.map +1 -0
- package/dist/testing.d.ts +21 -26
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +50 -70
- package/dist/testing.js.map +1 -1
- package/dist/type-handle.d.ts +67 -78
- package/dist/type-handle.d.ts.map +1 -1
- package/dist/type-handle.js +44 -111
- package/dist/type-handle.js.map +1 -1
- package/dist/types/adapter.d.ts +223 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/adapter.js +5 -0
- package/dist/types/adapter.js.map +1 -0
- package/dist/types/associations.d.ts +156 -0
- package/dist/types/associations.d.ts.map +1 -0
- package/dist/types/associations.js +13 -0
- package/dist/types/associations.js.map +1 -0
- package/dist/types/capabilities.d.ts +89 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +5 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/events.d.ts +155 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +5 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/ids.d.ts +43 -0
- package/dist/types/ids.d.ts.map +1 -0
- package/dist/types/ids.js +5 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/journal.d.ts +47 -0
- package/dist/types/journal.d.ts.map +1 -0
- package/dist/types/journal.js +5 -0
- package/dist/types/journal.js.map +1 -0
- package/dist/types/query.d.ts +185 -0
- package/dist/types/query.d.ts.map +1 -0
- package/dist/types/query.js +10 -0
- package/dist/types/query.js.map +1 -0
- package/dist/types/records.d.ts +76 -0
- package/dist/types/records.d.ts.map +1 -0
- package/dist/types/records.js +5 -0
- package/dist/types/records.js.map +1 -0
- package/dist/types/schema.d.ts +74 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +5 -0
- package/dist/types/schema.js.map +1 -0
- package/dist/types/system.d.ts +161 -0
- package/dist/types/system.d.ts.map +1 -0
- package/dist/types/system.js +32 -0
- package/dist/types/system.js.map +1 -0
- package/dist/types/tokens.d.ts +39 -0
- package/dist/types/tokens.d.ts.map +1 -0
- package/dist/types/tokens.js +5 -0
- package/dist/types/tokens.js.map +1 -0
- package/dist/validate.d.ts +29 -70
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +65 -97
- package/dist/validate.js.map +1 -1
- package/dist/{attachment-download.d.ts → wire/attachment-download.d.ts} +0 -57
- package/dist/wire/attachment-download.d.ts.map +1 -0
- package/dist/{attachment-download.js → wire/attachment-download.js} +0 -61
- package/dist/wire/attachment-download.js.map +1 -0
- package/dist/{auth.d.ts → wire/auth.d.ts} +5 -8
- package/dist/wire/auth.d.ts.map +1 -0
- package/dist/{auth.js → wire/auth.js} +5 -8
- package/dist/wire/auth.js.map +1 -0
- package/dist/{wire-body.d.ts → wire/body.d.ts} +13 -5
- package/dist/wire/body.d.ts.map +1 -0
- package/dist/{wire-body.js → wire/body.js} +65 -7
- package/dist/wire/body.js.map +1 -0
- package/dist/{wire-entry.d.ts → wire/index.d.ts} +12 -12
- package/dist/wire/index.d.ts.map +1 -0
- package/dist/{wire-entry.js → wire/index.js} +13 -17
- package/dist/wire/index.js.map +1 -0
- package/dist/{wire-record.d.ts → wire/record.d.ts} +10 -22
- package/dist/wire/record.d.ts.map +1 -0
- package/dist/{wire-record.js → wire/record.js} +12 -24
- package/dist/wire/record.js.map +1 -0
- package/dist/{wire-request.d.ts → wire/request.d.ts} +20 -37
- package/dist/wire/request.d.ts.map +1 -0
- package/dist/{wire-request.js → wire/request.js} +79 -54
- package/dist/wire/request.js.map +1 -0
- package/package.json +7 -7
- package/dist/adapter-entry.d.ts.map +0 -1
- package/dist/adapter-entry.js.map +0 -1
- package/dist/attachment-download.d.ts.map +0 -1
- package/dist/attachment-download.js.map +0 -1
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/changes.d.ts.map +0 -1
- package/dist/changes.js.map +0 -1
- package/dist/combine.d.ts.map +0 -1
- package/dist/combine.js.map +0 -1
- package/dist/did-entry.d.ts.map +0 -1
- package/dist/did-entry.js.map +0 -1
- package/dist/did.d.ts.map +0 -1
- package/dist/did.js.map +0 -1
- package/dist/identity-bindings.d.ts.map +0 -1
- package/dist/identity-bindings.js.map +0 -1
- package/dist/limits.d.ts.map +0 -1
- package/dist/limits.js.map +0 -1
- package/dist/record-id.d.ts +0 -70
- package/dist/record-id.d.ts.map +0 -1
- package/dist/record-id.js +0 -127
- package/dist/record-id.js.map +0 -1
- package/dist/scoped-stack.d.ts +0 -532
- package/dist/scoped-stack.d.ts.map +0 -1
- package/dist/scoped-stack.js +0 -1219
- package/dist/scoped-stack.js.map +0 -1
- package/dist/sort.d.ts.map +0 -1
- package/dist/sort.js.map +0 -1
- package/dist/stack-reads.d.ts.map +0 -1
- package/dist/stack-reads.js.map +0 -1
- package/dist/stack.d.ts +0 -971
- package/dist/stack.d.ts.map +0 -1
- package/dist/stack.js +0 -2012
- package/dist/stack.js.map +0 -1
- package/dist/types.d.ts +0 -1250
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -49
- package/dist/types.js.map +0 -1
- package/dist/wire-body.d.ts.map +0 -1
- package/dist/wire-body.js.map +0 -1
- package/dist/wire-entry.d.ts.map +0 -1
- package/dist/wire-entry.js.map +0 -1
- package/dist/wire-record.d.ts.map +0 -1
- package/dist/wire-record.js.map +0 -1
- package/dist/wire-request.d.ts.map +0 -1
- package/dist/wire-request.js.map +0 -1
- /package/dist/{did.d.ts → did/did.d.ts} +0 -0
- /package/dist/{identity-bindings.d.ts → stack/identity-bindings.d.ts} +0 -0
package/dist/stack.d.ts
DELETED
|
@@ -1,971 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stack — Core Stack Class
|
|
3
|
-
* -------------------------------------------------------
|
|
4
|
-
* The Stack class is the primary interface for apps. It sits
|
|
5
|
-
* on top of a StackAdapter and adds:
|
|
6
|
-
*
|
|
7
|
-
* - ID generation
|
|
8
|
-
* - Type definition and schema hashing
|
|
9
|
-
* - Content validation on write
|
|
10
|
-
* - Migration registry and explicit, owner-driven migrateAll()
|
|
11
|
-
* - Version snapshotting on update
|
|
12
|
-
* - Soft delete and purge
|
|
13
|
-
*
|
|
14
|
-
* Apps should never talk to a StackAdapter directly.
|
|
15
|
-
*/
|
|
16
|
-
import type { StackRecord, StackType, TypeSchema, TypeId, BaseId, StackAdapter, StackQuery, QueryResult, AssociationEdit, AuthorityAssociation, DataAssociation, Migration, RecordVersion, StackCapabilities, IfVersionOptions, GrantContent, TypeGrant, PutAttachmentOptions, AttachmentContent, FileId, EntityId, AppId, RecordId, Actor, ActorOptions, RecordChange, RecordChangeSet, SubscribeOptions, Unsubscribe, JournalQuery, VersionsQuery, RecordJournalEntry } from './types.js';
|
|
17
|
-
import type { GrantQuery } from './grants.js';
|
|
18
|
-
import { ScopedStack } from './scoped-stack.js';
|
|
19
|
-
import type { ContentOf, PatchOf, ReadonlyTypeSchema, TypedChange, TypedChangeSet, TypedQuery, TypedSubscribeOptions, TypedRecord, TypeHandle } from './type-handle.js';
|
|
20
|
-
/**
|
|
21
|
-
* An Actor in the one form `Stack` stores: a `principalId` equal to the
|
|
22
|
-
* subject is dropped, so "acted as itself" has a single spelling, and an
|
|
23
|
-
* empty id is refused rather than stored as a name for nobody.
|
|
24
|
-
* See docs/spec/data-model.md § Actor.
|
|
25
|
-
*/
|
|
26
|
-
export declare function normalizeActor(actor: Actor | undefined): Actor | undefined;
|
|
27
|
-
export type CreateRecordOptions = {
|
|
28
|
-
/**
|
|
29
|
-
* Client-minted record ID. Must be 12 lowercase Crockford base-32
|
|
30
|
-
* characters and may not use the reserved `_` prefix. Omit to let the
|
|
31
|
-
* library generate one. See Stack.create() and ScopedStack.create()
|
|
32
|
-
* for the validation each applies.
|
|
33
|
-
*/
|
|
34
|
-
id?: RecordId;
|
|
35
|
-
parentId?: RecordId;
|
|
36
|
-
/**
|
|
37
|
-
* The author. ScopedStack sets this from its own identities; callers of
|
|
38
|
-
* plain Stack supply it only when reconstructing an attributed write.
|
|
39
|
-
* See StackRecord.createdBy.
|
|
40
|
-
*/
|
|
41
|
-
createdBy?: Actor;
|
|
42
|
-
/** Reverse-DNS identifier of the writing software — see AppId. */
|
|
43
|
-
appId?: AppId;
|
|
44
|
-
permissions?: AuthorityAssociation[];
|
|
45
|
-
associations?: DataAssociation[];
|
|
46
|
-
/**
|
|
47
|
-
* Create the record already unlisted, so the create event itself is
|
|
48
|
-
* withheld from the feed — there is no window where the record exists
|
|
49
|
-
* and is listed before a mutation catches up. See
|
|
50
|
-
* docs/spec/unlisted.md.
|
|
51
|
-
*/
|
|
52
|
-
unlisted?: boolean;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* CreateRecordOptions extended with createdAt/updatedAt, for backdating a
|
|
56
|
-
* record's clock fields on import. Unscoped Stack.create() accepts them
|
|
57
|
-
* unconditionally; ScopedStack.create() only from the stack owner acting
|
|
58
|
-
* alone, since a grantee or a delegated app could otherwise forge a sort
|
|
59
|
-
* position the same way a raw `id` could.
|
|
60
|
-
* See docs/spec/data-model.md § Record IDs.
|
|
61
|
-
*/
|
|
62
|
-
export type BackdatableCreateRecordOptions = CreateRecordOptions & {
|
|
63
|
-
/**
|
|
64
|
-
* The record's creation time. When `id` is also supplied, its embedded
|
|
65
|
-
* timestamp must agree with this within `idTimestampSkewMs` (default 24h;
|
|
66
|
-
* see StackOptions.idTimestampSkewMs) or the create throws
|
|
67
|
-
* StackValidationError. Omit `id` to have it derived from this timestamp
|
|
68
|
-
* instead. Defaults to now.
|
|
69
|
-
*/
|
|
70
|
-
createdAt?: Date;
|
|
71
|
-
/**
|
|
72
|
-
* The record's last-modified time. Defaults to `createdAt` (or now, if
|
|
73
|
-
* `createdAt` is omitted too) — never to the actual current time — so a
|
|
74
|
-
* plain import doesn't fabricate a fake edit. Must not precede
|
|
75
|
-
* `createdAt`.
|
|
76
|
-
*/
|
|
77
|
-
updatedAt?: Date;
|
|
78
|
-
};
|
|
79
|
-
export type StackOptions = {
|
|
80
|
-
/**
|
|
81
|
-
* Ensures the owner's own `_entity` profile record exists, creating it on
|
|
82
|
-
* first run. Idempotent — safe to pass on every open. See
|
|
83
|
-
* docs/spec/identity.md § Entity.
|
|
84
|
-
*/
|
|
85
|
-
ownerProfile?: {
|
|
86
|
-
name: string;
|
|
87
|
-
handle?: string;
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Clock-skew tolerance (ms) for two timestamp-prefix checks: the one
|
|
91
|
-
* ScopedStack.create() runs on a non-backdated create's client-supplied
|
|
92
|
-
* `id` against the current time, and the one Stack.create() runs between
|
|
93
|
-
* an explicit `id` and an explicit `createdAt` when both are supplied —
|
|
94
|
-
* reached directly when unscoped, or via ScopedStack.create() when the
|
|
95
|
-
* requester is the owner acting alone. Default: 24 hours; null disables
|
|
96
|
-
* both. See docs/spec/data-model.md § Record IDs.
|
|
97
|
-
*/
|
|
98
|
-
idTimestampSkewMs?: number | null;
|
|
99
|
-
};
|
|
100
|
-
export type CollectAttachmentGarbageOptions = {
|
|
101
|
-
/**
|
|
102
|
-
* How recent an unreferenced file must be to survive collection, covering
|
|
103
|
-
* the upload-then-associate window. Default: 24 hours. Pass 0 to collect
|
|
104
|
-
* anything unreferenced right now.
|
|
105
|
-
*/
|
|
106
|
-
graceMs?: number;
|
|
107
|
-
/** Compute what would be deleted without deleting anything. Default: false. */
|
|
108
|
-
dryRun?: boolean;
|
|
109
|
-
};
|
|
110
|
-
export type CollectAttachmentGarbageResult = {
|
|
111
|
-
/** The files collected — or, on a dry run, the ones that would be. */
|
|
112
|
-
deletedFileIds: FileId[];
|
|
113
|
-
reclaimedBytes: number;
|
|
114
|
-
};
|
|
115
|
-
export type GetRecordOptions = {
|
|
116
|
-
/**
|
|
117
|
-
* Records are returned exactly as stored by default. Pass "latest" to
|
|
118
|
-
* apply the registered migration chain in memory — never written back.
|
|
119
|
-
* See docs/spec/data-model.md § Type migrations.
|
|
120
|
-
*/
|
|
121
|
-
presentAt?: 'stored' | 'latest';
|
|
122
|
-
/**
|
|
123
|
-
* Soft-deleted records are hidden by default, as query() hides them: a
|
|
124
|
-
* tombstone reads as `null`. Pass true to read it back.
|
|
125
|
-
* See docs/spec/versioning.md § Deletion.
|
|
126
|
-
*/
|
|
127
|
-
includeDeleted?: boolean;
|
|
128
|
-
};
|
|
129
|
-
export type DeleteRecordOptions = IfVersionOptions & {
|
|
130
|
-
/** If true, permanently remove the record and all its history. Default: false */
|
|
131
|
-
purge?: boolean;
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* What a delete reports back. Information, not action: a purge never
|
|
135
|
-
* touches the blob store, and nothing here is deleted by having been
|
|
136
|
-
* named. See docs/spec/attachments.md § A purge strands the bytes it
|
|
137
|
-
* referenced.
|
|
138
|
-
*/
|
|
139
|
-
export type DeleteResult = {
|
|
140
|
-
/**
|
|
141
|
-
* The files the purged record referenced — its attachment associations
|
|
142
|
-
* and its `file-ref` content fields, deduplicated. The purge removes the
|
|
143
|
-
* only rows naming them, so this is the caller's one chance to hold the
|
|
144
|
-
* argument `deleteAttachment()` takes. Empty on a soft delete, which
|
|
145
|
-
* strands nothing: a tombstone's references stand.
|
|
146
|
-
*/
|
|
147
|
-
referencedFileIds: FileId[];
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* What deleteAndReturn() reports back — DeleteResult plus the record itself,
|
|
151
|
-
* captured inside the same atomic operation as the destroy rather than a
|
|
152
|
-
* read beforehand. See Stack.deleteAndReturn().
|
|
153
|
-
*/
|
|
154
|
-
export type DeleteAndReturnResult = DeleteResult & {
|
|
155
|
-
/**
|
|
156
|
-
* The record as it stood at the moment of deletion: immediately before
|
|
157
|
-
* destruction for a purge, or the resulting tombstone for a soft
|
|
158
|
-
* delete. Null only for the purge no-op — there was nothing to
|
|
159
|
-
* delete, and nothing to report; every other outcome throws instead of
|
|
160
|
-
* returning null (see Stack.delete()'s own no-op cases).
|
|
161
|
-
*/
|
|
162
|
-
record: StackRecord | null;
|
|
163
|
-
};
|
|
164
|
-
/** The argument to Stack.defineType(). */
|
|
165
|
-
export type DefineTypeOptions = {
|
|
166
|
-
id: TypeId;
|
|
167
|
-
name: string;
|
|
168
|
-
/** A handle's `schema` is accepted as written, readonly members and all. */
|
|
169
|
-
schema: ReadonlyTypeSchema;
|
|
170
|
-
migratesFrom?: TypeId;
|
|
171
|
-
};
|
|
172
|
-
/**
|
|
173
|
-
* The app-facing record API, implemented by both Stack and ScopedStack.
|
|
174
|
-
* Accept this type in plugin or extension code to remain adapter-agnostic
|
|
175
|
-
* and work equally well with a full Stack or a permission-scoped view.
|
|
176
|
-
*/
|
|
177
|
-
export interface StackClient {
|
|
178
|
-
readonly capabilities: StackCapabilities;
|
|
179
|
-
create<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, content: ContentOf<S>, opts?: CreateRecordOptions): Promise<TypedRecord<S>>;
|
|
180
|
-
create<T extends Record<string, unknown> = Record<string, unknown>>(typeId: TypeId, content: T, opts?: CreateRecordOptions): Promise<StackRecord & {
|
|
181
|
-
content: T;
|
|
182
|
-
}>;
|
|
183
|
-
/**
|
|
184
|
-
* Typed read: the record at `presentAt: 'latest'`, checked to be exactly
|
|
185
|
-
* the handle's Type with every enum field holding a value the handle
|
|
186
|
-
* lists, else it throws. Live records only — a tombstone reads as `null`,
|
|
187
|
-
* and there is no `includeDeleted`.
|
|
188
|
-
* See docs/spec/data-model.md § Type handles.
|
|
189
|
-
*/
|
|
190
|
-
get<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId): Promise<TypedRecord<S> | null>;
|
|
191
|
-
get(id: RecordId, opts?: GetRecordOptions): Promise<StackRecord | null>;
|
|
192
|
-
/** Typed read of the handle's whole family — see the typed `get()`. */
|
|
193
|
-
query<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, query?: TypedQuery): Promise<{
|
|
194
|
-
records: TypedRecord<S>[];
|
|
195
|
-
cursor: string | null;
|
|
196
|
-
}>;
|
|
197
|
-
query(query?: StackQuery): Promise<QueryResult>;
|
|
198
|
-
/**
|
|
199
|
-
* Resolve a DID to its `_entity` card — family-wide and soft-deleted
|
|
200
|
-
* inclusive, per docs/spec/identity.md § DID bindings. No caching.
|
|
201
|
-
*
|
|
202
|
-
* Under `ScopedStack`, `null` covers missing, unreadable, and (unless the
|
|
203
|
-
* owner is acting alone) unlisted — never evidence the card is absent.
|
|
204
|
-
*/
|
|
205
|
-
getEntityByDid(did: EntityId): Promise<StackRecord | null>;
|
|
206
|
-
/** getEntityByDid() for the one DID every stack reserves: its own owner. */
|
|
207
|
-
getOwnerEntity(): Promise<StackRecord | null>;
|
|
208
|
-
/**
|
|
209
|
-
* Apply a change set: any combination of content patch, `parentId`,
|
|
210
|
-
* `permissions`, `associations` and `unlisted`, in one atomic write —
|
|
211
|
-
* producing one version where it names `contentPatch`, and none where it
|
|
212
|
-
* doesn't. Keys are read for presence, so `unlisted: false`
|
|
213
|
-
* and `parentId: null` are changes; a change set naming no key at all is
|
|
214
|
-
* a StackBadRequestError. Under ScopedStack each key carries its own gate and
|
|
215
|
-
* one refused key refuses the call.
|
|
216
|
-
* See docs/spec/data-model.md § Mutations.
|
|
217
|
-
*/
|
|
218
|
-
mutate<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, changes: TypedChangeSet<S>, opts?: IfVersionOptions): Promise<TypedRecord<S>>;
|
|
219
|
-
mutate(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
220
|
-
/** mutate() with `contentPatch` alone — the common case, named for it. */
|
|
221
|
-
patchContent<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, patch: PatchOf<S>, opts?: IfVersionOptions): Promise<TypedRecord<S>>;
|
|
222
|
-
patchContent(id: RecordId, patch: Record<string, unknown | null>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
223
|
-
/**
|
|
224
|
-
* Add associations in one atomic write and one journal entry. Never bumps
|
|
225
|
-
* `version`/`updatedAt` and takes no `ifVersion` — a set-add composes
|
|
226
|
-
* regardless of write order. See docs/spec/data-model.md § Mutations and
|
|
227
|
-
* docs/spec/versioning.md § Version history.
|
|
228
|
-
*/
|
|
229
|
-
associate(id: RecordId, associations: DataAssociation[]): Promise<StackRecord>;
|
|
230
|
-
/** Remove associations, matched by identity — see associate(). */
|
|
231
|
-
dissociate(id: RecordId, associations: DataAssociation[]): Promise<StackRecord>;
|
|
232
|
-
/**
|
|
233
|
-
* Apply a list of adds and removes to a record's data associations as one
|
|
234
|
-
* atomic write — the cover swap. associate() and dissociate() are this with
|
|
235
|
-
* one half each; `mutate({ associations })` is the only whole-set write.
|
|
236
|
-
* `repoint` is not a request: an add naming an attachment the record
|
|
237
|
-
* already holds re-points it. See docs/spec/data-model.md § Mutations.
|
|
238
|
-
*/
|
|
239
|
-
amendAssociations(id: RecordId, changes: AssociationEdit[]): Promise<StackRecord>;
|
|
240
|
-
/**
|
|
241
|
-
* Extend who reaches a record — the record-level mirror of the type-level
|
|
242
|
-
* `grantType()`, and the amending spelling of the `permissions` key, which
|
|
243
|
-
* replaces the whole set. `write` never implies `read`: grant both,
|
|
244
|
-
* `grantAccess(id, [read, write])`. No-bump, like associate().
|
|
245
|
-
* See docs/spec/access-control.md § Write implies read.
|
|
246
|
-
*/
|
|
247
|
-
grantAccess(id: RecordId, permissions: AuthorityAssociation[]): Promise<StackRecord>;
|
|
248
|
-
/** Withdraw elements of who reaches a record — see grantAccess(). */
|
|
249
|
-
revokeAccess(id: RecordId, permissions: AuthorityAssociation[]): Promise<StackRecord>;
|
|
250
|
-
/**
|
|
251
|
-
* amendAssociations() for permissions: adds and removes in one atomic
|
|
252
|
-
* write, so a downgrade (remove `write`, keep `read`) is one change.
|
|
253
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
254
|
-
*/
|
|
255
|
-
amendAccess(id: RecordId, changes: AssociationEdit[]): Promise<StackRecord>;
|
|
256
|
-
delete(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteResult>;
|
|
257
|
-
/**
|
|
258
|
-
* delete(), plus the record it acted on — read and destroyed as one
|
|
259
|
-
* atomic operation, so a caller that needs the record for its own
|
|
260
|
-
* response (e.g. a server building a purge's body) never opens a
|
|
261
|
-
* gap between reading it and destroying it. See Stack.deleteAndReturn().
|
|
262
|
-
*/
|
|
263
|
-
deleteAndReturn(id: RecordId, opts?: DeleteRecordOptions): Promise<DeleteAndReturnResult>;
|
|
264
|
-
undelete(id: RecordId, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
265
|
-
getVersions(id: RecordId, query?: VersionsQuery): Promise<RecordVersion[]>;
|
|
266
|
-
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
267
|
-
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
268
|
-
/**
|
|
269
|
-
* A record's change journal, oldest first. On the mutate surface, on the
|
|
270
|
-
* same footing as getVersions() — a plain reader is refused.
|
|
271
|
-
*
|
|
272
|
-
* Required of every adapter rather than optional, which is why it sits
|
|
273
|
-
* here beside the rest: an empty log has to mean "nothing changed"
|
|
274
|
-
* unconditionally, so an adapter with nothing to read refuses and names
|
|
275
|
-
* why instead. See docs/spec/journal.md § Reading it.
|
|
276
|
-
*/
|
|
277
|
-
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
278
|
-
/**
|
|
279
|
-
* Commit a per-record migration: change `typeId` and `content` together,
|
|
280
|
-
* validated against `toTypeId`'s schema. The only way a record's typeId
|
|
281
|
-
* changes after creation — see docs/spec/wire-format.md § Migration
|
|
282
|
-
* commit. Takes `ifVersion` like every other mutation that bumps a
|
|
283
|
-
* record's version (see docs/spec/versioning.md § Optimistic
|
|
284
|
-
* concurrency); over the wire that is `If-Match`.
|
|
285
|
-
*/
|
|
286
|
-
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions): Promise<StackRecord>;
|
|
287
|
-
getAttachment(fileId: FileId): Promise<Uint8Array>;
|
|
288
|
-
putAttachment(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord & {
|
|
289
|
-
content: AttachmentContent;
|
|
290
|
-
}>;
|
|
291
|
-
deleteAttachment(fileId: FileId): Promise<void>;
|
|
292
|
-
collectAttachmentGarbage(opts?: CollectAttachmentGarbageOptions): Promise<CollectAttachmentGarbageResult>;
|
|
293
|
-
/**
|
|
294
|
-
* Typed subscription: delivers only changes to records of exactly the
|
|
295
|
-
* handle's Type, each `record` typed as its content. See
|
|
296
|
-
* docs/spec/data-model.md § Type handles.
|
|
297
|
-
*/
|
|
298
|
-
subscribe<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, handler: (change: TypedChange<S>) => void, opts?: TypedSubscribeOptions): Promise<Unsubscribe>;
|
|
299
|
-
subscribe(handler: (change: RecordChange) => void, opts?: SubscribeOptions): Promise<Unsubscribe>;
|
|
300
|
-
}
|
|
301
|
-
export declare class Stack implements StackClient {
|
|
302
|
-
private readonly adapter;
|
|
303
|
-
private readonly idTimestampSkewMsValue;
|
|
304
|
-
private readonly migrations;
|
|
305
|
-
/**
|
|
306
|
-
* Highest version this instance has defineType()'d, per baseId — what
|
|
307
|
-
* this app process understands, as distinct from what exists in shared
|
|
308
|
-
* storage. Used to detect the stale-writer case in presentAtLatest().
|
|
309
|
-
*/
|
|
310
|
-
private readonly maxDefinedVersion;
|
|
311
|
-
/**
|
|
312
|
-
* Types this instance has fetched or defined, keyed by versioned id. A
|
|
313
|
-
* Type's schema is immutable once defined, so entries are never
|
|
314
|
-
* invalidated, only added; listTypes() refreshes wholesale. See
|
|
315
|
-
* docs/spec/data-model.md § Type cache.
|
|
316
|
-
*/
|
|
317
|
-
private readonly typeCache;
|
|
318
|
-
/** Set by close(). See docs/spec/adapters.md § Lifecycle. */
|
|
319
|
-
private closed;
|
|
320
|
-
/**
|
|
321
|
-
* Every change made through this Stack. `ScopedStack` filters this same
|
|
322
|
-
* stream rather than opening its own, so no scoped view can observe a
|
|
323
|
-
* change the stack did not emit. See docs/spec/events.md.
|
|
324
|
-
*/
|
|
325
|
-
private readonly changes;
|
|
326
|
-
private constructor();
|
|
327
|
-
/**
|
|
328
|
-
* Announce a mutation that has already been persisted. Called after the
|
|
329
|
-
* adapter write resolves and before the mutating method settles, so
|
|
330
|
-
* `await stack.mutate(...)` guarantees subscribers have been notified —
|
|
331
|
-
* and nothing about work they deferred. A handler cannot fail the write:
|
|
332
|
-
* there is nothing left to fail. See docs/spec/events.md § Handlers.
|
|
333
|
-
*/
|
|
334
|
-
private announce;
|
|
335
|
-
/**
|
|
336
|
-
* The actor for a `create` journal entry, read off the record as just
|
|
337
|
-
* built. Create is the one journaled write that stamps the requester
|
|
338
|
-
* onto the row itself, so the record in hand is authoritative — and it
|
|
339
|
-
* carries `appId`, which ActorOptions has no field for.
|
|
340
|
-
*/
|
|
341
|
-
private static createActor;
|
|
342
|
-
private getTypeCached;
|
|
343
|
-
/**
|
|
344
|
-
* Open a Stack over an adapter. Reads ownerEntityId and timezone from the adapter.
|
|
345
|
-
*/
|
|
346
|
-
static open(adapter: StackAdapter, opts?: StackOptions): Promise<Stack>;
|
|
347
|
-
/**
|
|
348
|
-
* Idempotent bootstrap for StackOptions.ownerProfile. Filters by family
|
|
349
|
-
* only (content filtering is capability-gated) and matches `content.did`
|
|
350
|
-
* in memory, cursor-walking so an owner card past page one isn't missed
|
|
351
|
-
* and duplicated. The probe must be blind to nothing the binding rules
|
|
352
|
-
* see, or it mints a card they then refuse and the stack won't open with
|
|
353
|
-
* `ownerProfile`: soft-deleted cards still reserve their `did`, and a card
|
|
354
|
-
* migrated to a later version still holds one.
|
|
355
|
-
* See docs/spec/identity.md § DID bindings.
|
|
356
|
-
*/
|
|
357
|
-
private ensureOwnerEntity;
|
|
358
|
-
get ownerEntityId(): EntityId;
|
|
359
|
-
getEntityByDid(did: EntityId): Promise<StackRecord | null>;
|
|
360
|
-
getOwnerEntity(): Promise<StackRecord | null>;
|
|
361
|
-
get timezone(): string | undefined;
|
|
362
|
-
get capabilities(): StackCapabilities;
|
|
363
|
-
/**
|
|
364
|
-
* Get a permission-scoped view of this Stack, as if requests came from
|
|
365
|
-
* the given entity acting as itself (null = anonymous). Plain Stack
|
|
366
|
-
* methods are unscoped; use asEntity() when one Stack serves multiple,
|
|
367
|
-
* possibly untrusted, entities. See
|
|
368
|
-
* docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
369
|
-
*/
|
|
370
|
-
asEntity(entityId: EntityId | null): ScopedStack;
|
|
371
|
-
/**
|
|
372
|
-
* Scope to an Actor — a delegated app acting for its user, or a
|
|
373
|
-
* TokenSession exactly as StackTokenStore.lookupToken() returns it, which
|
|
374
|
-
* is what a server should reach for at its request boundary. Authority is
|
|
375
|
-
* the intersection of both parties' grants, while authorship and `-own`
|
|
376
|
-
* resolve against the subject. Taking the pair whole leaves no order to
|
|
377
|
-
* swap. See docs/spec/access-control.md § Delegation: principal and subject.
|
|
378
|
-
*/
|
|
379
|
-
asActor(actor: Actor): ScopedStack;
|
|
380
|
-
private scope;
|
|
381
|
-
/**
|
|
382
|
-
* Define and persist a Type; call at app startup before creating records
|
|
383
|
-
* of the type. Redefining an existing typeId is checked against the
|
|
384
|
-
* stored schema: identical is a no-op, a name-only change persists, and
|
|
385
|
-
* anything beyond additive evolution throws StackSchemaDriftError. See
|
|
386
|
-
* docs/spec/data-model.md § Schema drift detection.
|
|
387
|
-
*/
|
|
388
|
-
defineType({ id, name, schema: declared, migratesFrom, }: DefineTypeOptions): Promise<StackType>;
|
|
389
|
-
getType(id: TypeId): Promise<StackType | null>;
|
|
390
|
-
/** Refreshes typeCache wholesale — the explicit way to see a rename made by another writer. */
|
|
391
|
-
listTypes(): Promise<StackType[]>;
|
|
392
|
-
/**
|
|
393
|
-
* Check whether a record's type is compatible with a required schema.
|
|
394
|
-
* Useful for duck-typed consumption across types.
|
|
395
|
-
*/
|
|
396
|
-
typeIsCompatible(typeId: TypeId, requiredSchema: TypeSchema): Promise<boolean>;
|
|
397
|
-
/**
|
|
398
|
-
* Register a migration function between two adjacent Type versions; call
|
|
399
|
-
* at app startup after defineType(). Runs in-memory — nothing is written
|
|
400
|
-
* until migrateAll(). Adjacent migrations are composed into chains
|
|
401
|
-
* automatically.
|
|
402
|
-
*/
|
|
403
|
-
registerMigration(migration: Migration): void;
|
|
404
|
-
/**
|
|
405
|
-
* Find and compose a migration path from one TypeId to another.
|
|
406
|
-
* Returns null if no path exists.
|
|
407
|
-
*/
|
|
408
|
-
private resolveMigrationPath;
|
|
409
|
-
/**
|
|
410
|
-
* Find the latest registered version of a type family.
|
|
411
|
-
* Follows the migration chain from the given typeId to the end.
|
|
412
|
-
*/
|
|
413
|
-
private latestTypeId;
|
|
414
|
-
/**
|
|
415
|
-
* Eagerly migrate all records of a type family to the latest version —
|
|
416
|
-
* the only way disk state changes version. Sweeps soft-deleted records
|
|
417
|
-
* too, validates each result before writing, and aborts on the first
|
|
418
|
-
* validation failure. See docs/spec/data-model.md § Type migrations.
|
|
419
|
-
*/
|
|
420
|
-
migrateAll(baseId: BaseId): Promise<{
|
|
421
|
-
migrated: number;
|
|
422
|
-
}>;
|
|
423
|
-
/**
|
|
424
|
-
* Create a new record. Validates content against the type's schema.
|
|
425
|
-
* `_group` records get their author stamped as the first `admin` roster
|
|
426
|
-
* association here — the single stamping site for both Stack.create()
|
|
427
|
-
* and ScopedStack.create(). `opts.createdAt`/`updatedAt` let a caller
|
|
428
|
-
* backdate an imported record's clock fields — unconditionally here;
|
|
429
|
-
* ScopedStack.create() forwards to this same method, but only reaches
|
|
430
|
-
* this far with them when the requester is the stack owner acting alone
|
|
431
|
-
* — see BackdatableCreateRecordOptions and docs/spec/data-model.md §
|
|
432
|
-
* Record IDs.
|
|
433
|
-
*/
|
|
434
|
-
create<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, content: ContentOf<S>, opts?: BackdatableCreateRecordOptions): Promise<TypedRecord<S>>;
|
|
435
|
-
create<T extends Record<string, unknown> = Record<string, unknown>>(typeId: TypeId, content: T, opts?: BackdatableCreateRecordOptions): Promise<StackRecord & {
|
|
436
|
-
content: T;
|
|
437
|
-
}>;
|
|
438
|
-
/**
|
|
439
|
-
* Apply the registered migration chain in memory, for presentAt:
|
|
440
|
-
* 'latest'. Never writes back. Throws StackMigrationError when the
|
|
441
|
-
* record's version can't be reconciled with what this instance has
|
|
442
|
-
* registered — the stale-writer case. See docs/spec/data-model.md
|
|
443
|
-
* § Type migrations.
|
|
444
|
-
*/
|
|
445
|
-
private presentAtLatest;
|
|
446
|
-
/**
|
|
447
|
-
* Get a record by ID, exactly as stored — no implicit migration. Pass
|
|
448
|
-
* { presentAt: 'latest' } to migrate in memory; only migrateAll()
|
|
449
|
-
* commits migrations to disk. A soft-deleted record answers `null` unless
|
|
450
|
-
* { includeDeleted: true } is passed.
|
|
451
|
-
*/
|
|
452
|
-
get<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId): Promise<TypedRecord<S> | null>;
|
|
453
|
-
get(id: RecordId, opts?: GetRecordOptions): Promise<StackRecord | null>;
|
|
454
|
-
/**
|
|
455
|
-
* Apply a change set as one atomic write — see the StackClient
|
|
456
|
-
* declaration above for what it accepts. Atomicity is what it is for: a
|
|
457
|
-
* publish is one act, so nothing it names may half-land.
|
|
458
|
-
*
|
|
459
|
-
* Every key present is checked against the record as it stands, and a set
|
|
460
|
-
* already satisfied in all of them writes nothing. Content is validated
|
|
461
|
-
* against the record's *current* stored type; `typeId` never changes here.
|
|
462
|
-
* See docs/spec/data-model.md § Mutations.
|
|
463
|
-
*/
|
|
464
|
-
mutate<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, changes: TypedChangeSet<S>, opts?: IfVersionOptions & ActorOptions): Promise<TypedRecord<S>>;
|
|
465
|
-
mutate(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
466
|
-
/**
|
|
467
|
-
* mutate() with `contentPatch` alone. The common case by a wide margin,
|
|
468
|
-
* and named for what it does rather than for a symmetry with create()
|
|
469
|
-
* that a patch does not have.
|
|
470
|
-
*/
|
|
471
|
-
patchContent<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, id: RecordId, patch: PatchOf<S>, opts?: IfVersionOptions & ActorOptions): Promise<TypedRecord<S>>;
|
|
472
|
-
patchContent(id: RecordId, patch: Record<string, unknown | null>, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
473
|
-
/**
|
|
474
|
-
* Every check a change set owes before anything is written, in one pass:
|
|
475
|
-
* one refused key refuses the call, so none of them may run after a
|
|
476
|
-
* partial write. Returns the merged content when the set carries a
|
|
477
|
-
* content patch, since the caller needs it to decide whether content
|
|
478
|
-
* actually moved.
|
|
479
|
-
*
|
|
480
|
-
* Parent existence and acyclicity are asked only when the destination
|
|
481
|
-
* differs from where the record already sits — a move to where it
|
|
482
|
-
* already is names no new edge, and would otherwise cost a read apiece.
|
|
483
|
-
*/
|
|
484
|
-
private validateChangeSet;
|
|
485
|
-
/**
|
|
486
|
-
* Refuse a write that would leave a `_group` Record with no `admin` on its
|
|
487
|
-
* roster. Asked of the roster the write would *produce*, which is the
|
|
488
|
-
* whole of the self-removal question: an admin removing themselves passes
|
|
489
|
-
* while another remains and is refused when they are the last, without
|
|
490
|
-
* either case naming who is going.
|
|
491
|
-
*
|
|
492
|
-
* An integrity constraint on the Record, not a permission question, so it
|
|
493
|
-
* lives here rather than in `ScopedStack` and binds every requester — the
|
|
494
|
-
* stack owner included. See docs/spec/identity.md § Group.
|
|
495
|
-
*/
|
|
496
|
-
private assertGroupAdminRemains;
|
|
497
|
-
/**
|
|
498
|
-
* Add associations to a record — no-bump and no snapshot, per the
|
|
499
|
-
* StackClient declaration above.
|
|
500
|
-
*
|
|
501
|
-
* An association the record already holds, saying the same thing, is a
|
|
502
|
-
* no-op; one matching an existing association's identity but naming a
|
|
503
|
-
* different `attachmentRecordId` — or none, which clears the one stored —
|
|
504
|
-
* re-points it in place rather than adding a second reference to the same
|
|
505
|
-
* file. What a re-point overwrote is kept only by the journal, on that
|
|
506
|
-
* entry's `repoint`. See docs/spec/journal.md § The entry.
|
|
507
|
-
*/
|
|
508
|
-
associate(id: RecordId, associations: DataAssociation[], opts?: ActorOptions): Promise<StackRecord>;
|
|
509
|
-
/**
|
|
510
|
-
* Remove associations from a record — see associate(). Matched by kind,
|
|
511
|
-
* label and payload; an element not found is a no-op. The emitted event
|
|
512
|
-
* names each association by identity only, since an attachment's
|
|
513
|
-
* `attachmentRecordId` describes nothing current once it is gone; the
|
|
514
|
-
* journal is where it survives.
|
|
515
|
-
*/
|
|
516
|
-
dissociate(id: RecordId, associations: DataAssociation[], opts?: ActorOptions): Promise<StackRecord>;
|
|
517
|
-
/**
|
|
518
|
-
* The atomic form of associate() and dissociate(): one list of adds and
|
|
519
|
-
* removes, one adapter write, one journal entry. The journal records each
|
|
520
|
-
* element in full — a remove with its annotation, a re-point with what it
|
|
521
|
-
* overwrote — so the entry is as undoable as a single-element one.
|
|
522
|
-
* See docs/spec/data-model.md § Mutations.
|
|
523
|
-
*/
|
|
524
|
-
amendAssociations(id: RecordId, changes: AssociationEdit[], opts?: ActorOptions, surface?: string): Promise<StackRecord>;
|
|
525
|
-
/**
|
|
526
|
-
* Extend who reaches a record. The spelling that survives two admins
|
|
527
|
-
* sharing a record at once: a `permissions` key write replaces the whole
|
|
528
|
-
* set, so the later of two concurrent ones drops what the earlier
|
|
529
|
-
* granted. No-bump, like associate(); an element the record already
|
|
530
|
-
* carries is a no-op. `write` never implies `read` — name both.
|
|
531
|
-
*/
|
|
532
|
-
grantAccess(id: RecordId, permissions: AuthorityAssociation[], opts?: ActorOptions): Promise<StackRecord>;
|
|
533
|
-
/**
|
|
534
|
-
* Withdraw elements of who reaches a record — see grantAccess() for why
|
|
535
|
-
* this is a verb rather than a key write. An element the record does not
|
|
536
|
-
* carry is a no-op. Returns the record as it now stands.
|
|
537
|
-
*/
|
|
538
|
-
revokeAccess(id: RecordId, permissions: AuthorityAssociation[], opts?: ActorOptions): Promise<StackRecord>;
|
|
539
|
-
/**
|
|
540
|
-
* The atomic form of grantAccess() and revokeAccess(). The
|
|
541
|
-
* write-implies-read invariant is asked once, of the set the whole list
|
|
542
|
-
* produces. See docs/spec/access-control.md § Write implies read.
|
|
543
|
-
*/
|
|
544
|
-
amendAccess(id: RecordId, changes: AssociationEdit[], opts?: ActorOptions, surface?: string): Promise<StackRecord>;
|
|
545
|
-
/**
|
|
546
|
-
* Hold a permission set to the cross-element invariant — see
|
|
547
|
-
* validatePermissions() in access.ts for why it reads the post-state.
|
|
548
|
-
*/
|
|
549
|
-
private assertPermissionSet;
|
|
550
|
-
/**
|
|
551
|
-
* A soft-deleted record has no current state to edit, so the verbs that
|
|
552
|
-
* edit one refuse it; undelete() and commitMigration() do not call this.
|
|
553
|
-
* Asked after the record is found and, under ScopedStack, after the
|
|
554
|
-
* authority decision. See docs/spec/versioning.md § Mutations are refused,
|
|
555
|
-
* not applied to a tombstone.
|
|
556
|
-
*/
|
|
557
|
-
private refuseIfDeleted;
|
|
558
|
-
/** The record, or the not-found refusal every mutating verb owes. */
|
|
559
|
-
private requireRecord;
|
|
560
|
-
/**
|
|
561
|
-
* The checks a *caller-named* destination owes, before the cycle walk:
|
|
562
|
-
* `parentId` is a real, well-formed record id. Format first, so a
|
|
563
|
-
* malformed one is a 400 naming the problem rather than a read that
|
|
564
|
-
* cannot match. Existence closes the gap between the owner path and a
|
|
565
|
-
* non-owner's, where canReadReferent() already refuses a parent that
|
|
566
|
-
* isn't there.
|
|
567
|
-
*
|
|
568
|
-
* restoreVersion() deliberately does not call this — see its own comment.
|
|
569
|
-
* See docs/spec/data-model.md § Reparenting.
|
|
570
|
-
*/
|
|
571
|
-
private assertParentExists;
|
|
572
|
-
/**
|
|
573
|
-
* Refuse an edge that would make a record its own ancestor — asked at
|
|
574
|
-
* every site that adds one. Nothing downstream (a generator deriving a
|
|
575
|
-
* page path, a folder view) is written to survive a cycle.
|
|
576
|
-
*
|
|
577
|
-
* Walks with the unscoped adapter: a walk that skipped the links a
|
|
578
|
-
* requester cannot read would let a cycle be assembled through them and
|
|
579
|
-
* break the invariant for every reader.
|
|
580
|
-
*
|
|
581
|
-
* Read-then-write, so two moves racing on opposite ends of one chain can
|
|
582
|
-
* both pass — the same deferral as checkBindingUnique() above, since
|
|
583
|
-
* closing it would put a graph constraint in the storage contract.
|
|
584
|
-
* Consumers walking `parentId` should carry a visited set rather than
|
|
585
|
-
* trust this alone. See docs/spec/data-model.md § Reparenting.
|
|
586
|
-
*/
|
|
587
|
-
private assertNoParentCycle;
|
|
588
|
-
/**
|
|
589
|
-
* Soft-delete a record (default) or purge it permanently, removing
|
|
590
|
-
* the record and its version history. Soft delete snapshots and bumps
|
|
591
|
-
* version; a no-op if already deleted. `_config` is never deletable
|
|
592
|
-
* (docs/spec.md § The `_config` record). See docs/spec/versioning.md
|
|
593
|
-
* § Deletion.
|
|
594
|
-
*
|
|
595
|
-
* A purge reports the files the record referenced. It deletes none of
|
|
596
|
-
* them — byte lifetime is not the purged record's to decide — but it
|
|
597
|
-
* destroys the only rows naming them, so a caller who means to erase the
|
|
598
|
-
* bytes too has nowhere else to read the argument from afterwards. See
|
|
599
|
-
* docs/spec/attachments.md § A purge strands the bytes it referenced.
|
|
600
|
-
*
|
|
601
|
-
* deleteAndReturn() is this plus the record itself; reach for that
|
|
602
|
-
* instead when the caller needs the record too — building a response
|
|
603
|
-
* body from a separate read beforehand is exactly the race and the extra
|
|
604
|
-
* round trip it exists to remove.
|
|
605
|
-
*/
|
|
606
|
-
delete(id: RecordId, opts?: DeleteRecordOptions & ActorOptions): Promise<DeleteResult>;
|
|
607
|
-
/**
|
|
608
|
-
* delete(), reporting the record it acted on alongside the files it
|
|
609
|
-
* stranded: as it stood immediately before destruction for a
|
|
610
|
-
* purge, or as the resulting tombstone for a soft delete. Both are
|
|
611
|
-
* captured inside the same write that destroys or tombstones the record,
|
|
612
|
-
* never a read beforehand — a read-then-delete would leave a window
|
|
613
|
-
* where a concurrent write can land, get destroyed or overwritten by
|
|
614
|
-
* this call, and never appear in the record this returns.
|
|
615
|
-
*/
|
|
616
|
-
deleteAndReturn(id: RecordId, opts?: DeleteRecordOptions & ActorOptions): Promise<DeleteAndReturnResult>;
|
|
617
|
-
/**
|
|
618
|
-
* The files a record references, by the same definition
|
|
619
|
-
* deleteAttachment() and the garbage sweep use: attachment associations
|
|
620
|
-
* and top-level `file-ref` content fields. An `_attachment` record's own
|
|
621
|
-
* `fileId` is a plain string by design and is not one, which is why
|
|
622
|
-
* purging a metadata record reports nothing — see initSystemTypes().
|
|
623
|
-
*/
|
|
624
|
-
private referencedFileIds;
|
|
625
|
-
/**
|
|
626
|
-
* Reverse a soft delete. Idempotent — undeleting a record that isn't
|
|
627
|
-
* deleted returns it unchanged. Purged records are gone, so this
|
|
628
|
-
* throws StackNotFoundError for them just like any other missing record.
|
|
629
|
-
* Snapshots and bumps version, same as delete().
|
|
630
|
-
*/
|
|
631
|
-
undelete(id: RecordId, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
632
|
-
/**
|
|
633
|
-
* Query records. filter.baseId matches every version of a type family,
|
|
634
|
-
* resolved against registered Types. Results come back exactly as
|
|
635
|
-
* stored; pass presentAt: 'latest' to migrate in memory. See
|
|
636
|
-
* docs/spec/data-model.md § Queries.
|
|
637
|
-
*/
|
|
638
|
-
query<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, query?: TypedQuery): Promise<{
|
|
639
|
-
records: TypedRecord<S>[];
|
|
640
|
-
cursor: string | null;
|
|
641
|
-
}>;
|
|
642
|
-
query(query?: StackQuery): Promise<QueryResult>;
|
|
643
|
-
/**
|
|
644
|
-
* Resolve filter.baseId into a concrete typeId set (intersected with
|
|
645
|
-
* filter.typeId when both are given), so adapters never need their own
|
|
646
|
-
* baseId concept. Returns EMPTY_FAMILY when the resolved set is empty so
|
|
647
|
-
* the caller can short-circuit without an adapter round trip.
|
|
648
|
-
*/
|
|
649
|
-
private resolveBaseIdFilter;
|
|
650
|
-
getVersions(id: RecordId, query?: VersionsQuery): Promise<RecordVersion[]>;
|
|
651
|
-
/**
|
|
652
|
-
* A record's change journal, oldest first — what moved, who moved it, and
|
|
653
|
-
* the association deltas nothing else retains. `ScopedStack` applies the
|
|
654
|
-
* mutate-surface gate; this layer is unscoped and trusted by definition.
|
|
655
|
-
*
|
|
656
|
-
* A record that isn't there is StackNotFoundError, a purged one included:
|
|
657
|
-
* a destroyed log and an empty one are not the same answer.
|
|
658
|
-
* See docs/spec/journal.md § Reading it.
|
|
659
|
-
*/
|
|
660
|
-
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
661
|
-
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
662
|
-
/**
|
|
663
|
-
* Restore a record to a previous version by creating a new version —
|
|
664
|
-
* never rewrites history. The snapshot is validated against its own
|
|
665
|
-
* stored typeId, and puts back `content` and `typeId` alone: a snapshot
|
|
666
|
-
* carries nothing else. See docs/spec/versioning.md § Restore semantics.
|
|
667
|
-
*/
|
|
668
|
-
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
669
|
-
/**
|
|
670
|
-
* Commit a per-record migration — the single-record counterpart to
|
|
671
|
-
* migrateAll(), with `content` supplied by the caller rather than by a
|
|
672
|
-
* registered Migration function. See docs/spec/wire-format.md § Migration
|
|
673
|
-
* commit.
|
|
674
|
-
*
|
|
675
|
-
* Because `content` is a full replacement written under a new `typeId`,
|
|
676
|
-
* this is create-shaped at the destination *and* update-shaped over the
|
|
677
|
-
* record as it stands, so it owes both sets of integrity checks. Missing
|
|
678
|
-
* either half would make migrate a second, unguarded write path to a
|
|
679
|
-
* state create()/mutate() refuse to reach.
|
|
680
|
-
*/
|
|
681
|
-
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions & ActorOptions): Promise<StackRecord>;
|
|
682
|
-
/**
|
|
683
|
-
* The checked migration write, shared by commitMigration() and
|
|
684
|
-
* migrateAll(). Takes the record already in hand rather than an id: a
|
|
685
|
-
* batch pass holds each record from its own query page, and re-fetching
|
|
686
|
-
* per record would cost a read apiece for nothing.
|
|
687
|
-
*
|
|
688
|
-
* Both callers owe the same checks. migrateAll()'s content comes from a
|
|
689
|
-
* registered Migration function rather than a request body, but "app
|
|
690
|
-
* code" is not a trust boundary here — the app calling commitMigration()
|
|
691
|
-
* is the same app that registered the function, and neither may move a
|
|
692
|
-
* DID binding or repoint an attachment. registerMigration() also places
|
|
693
|
-
* no constraint on `from` and `to` sharing a baseId, so a migration path
|
|
694
|
-
* can cross type families; family-crossing is exactly what the checks
|
|
695
|
-
* below care about.
|
|
696
|
-
*/
|
|
697
|
-
private commitMigrationChecked;
|
|
698
|
-
/** Uniqueness for every unique binding field a newly created card claims. */
|
|
699
|
-
private checkBindingsOnCreate;
|
|
700
|
-
/**
|
|
701
|
-
* Immutability for every binding field a patch touches, then uniqueness
|
|
702
|
-
* for the subset that carries it. Fields absent from the patch carry no
|
|
703
|
-
* new claim — a content patch is a merge, so an untouched binding is the one the
|
|
704
|
-
* card already holds.
|
|
705
|
-
*/
|
|
706
|
-
private checkBindingsOnUpdate;
|
|
707
|
-
/**
|
|
708
|
-
* Bindings across a migration. `content` is a full replacement, so every
|
|
709
|
-
* binding field either keeps its value, moves to a new one, or is shed by
|
|
710
|
-
* omission — and immutability refuses the last two. Asked across the
|
|
711
|
-
* union of both families' binding fields, so a card can neither shed its
|
|
712
|
-
* DID by migrating out of `_entity`/`_app` nor pick one up on the way in.
|
|
713
|
-
*
|
|
714
|
-
* Uniqueness is asked only of the destination family, excluding the
|
|
715
|
-
* record itself. See docs/spec/identity.md § DID bindings.
|
|
716
|
-
*/
|
|
717
|
-
private checkBindingsOnMigrate;
|
|
718
|
-
/**
|
|
719
|
-
* A unique binding field is what a lookup resolves *by* — an Actor's
|
|
720
|
-
* `principalId` by `_app.did`, its `subjectId` by `_entity.did`. Two cards
|
|
721
|
-
* claiming one value would leave that lookup without a single answer, and
|
|
722
|
-
* ambiguity is all an impersonating card needs. Enforced here rather than
|
|
723
|
-
* by schema, since uniqueness is a property of the set, not of the value.
|
|
724
|
-
*
|
|
725
|
-
* Read-then-write, so two creates racing on one value can both pass:
|
|
726
|
-
* closing that means a unique index over a JSON field, which is a
|
|
727
|
-
* decision about where uniqueness lives rather than a local fix.
|
|
728
|
-
* See docs/spec/identity.md § DID bindings.
|
|
729
|
-
*/
|
|
730
|
-
private checkBindingUnique;
|
|
731
|
-
/**
|
|
732
|
-
* A binding is permanent once made: uniqueness stops a second card
|
|
733
|
-
* claiming a value, but only immutability stops an existing card being
|
|
734
|
-
* moved onto one, which reaches the same impersonation by another route.
|
|
735
|
-
* Adopting a value is therefore a one-way step, and a subject whose key
|
|
736
|
-
* changes gets a new card — matching identity.md's deferral of key
|
|
737
|
-
* rotation, where a new key is a new identity rather than the same one
|
|
738
|
-
* relabelled. See docs/spec/identity.md § DID bindings.
|
|
739
|
-
*/
|
|
740
|
-
private checkBindingImmutable;
|
|
741
|
-
/**
|
|
742
|
-
* mimeType is a property of the fileId, not the uploader's perspective:
|
|
743
|
-
* the first metadata record for a fileId fixes it, and a conflicting
|
|
744
|
-
* later upload is rejected. See docs/spec/attachments.md § The
|
|
745
|
-
* `_attachment` record type.
|
|
746
|
-
*
|
|
747
|
-
* Best-effort by construction — check-then-create with no storage-level
|
|
748
|
-
* uniqueness behind it, so two racing first uploads can both land on a
|
|
749
|
-
* concurrent server. What survives that race is the *resolution*:
|
|
750
|
-
* getAttachmentRecords() returns the candidates in the same total order
|
|
751
|
-
* a server serving Content-Type applies, so both sides name the same
|
|
752
|
-
* winner however many records exist.
|
|
753
|
-
*/
|
|
754
|
-
private checkAttachmentMimeTypeOnCreate;
|
|
755
|
-
/**
|
|
756
|
-
* An attachment association's `attachmentRecordId` names an `_attachment`
|
|
757
|
-
* record for the same `fileId` — checked here so a reference can't be
|
|
758
|
-
* annotated with an unrelated record's filename.
|
|
759
|
-
*
|
|
760
|
-
* Best-effort, like the mimeType check above: the named record can be
|
|
761
|
-
* deleted afterwards, so every reader of the field falls back rather than
|
|
762
|
-
* trusting it. `stored` is what the record already holds, asked so a
|
|
763
|
-
* change set restating an association is never refused for a pointer the
|
|
764
|
-
* record has carried since before the named record was deleted.
|
|
765
|
-
* See docs/spec/attachments.md § Naming the upload a reference came from.
|
|
766
|
-
*/
|
|
767
|
-
private checkAttachmentAssociationPointers;
|
|
768
|
-
/**
|
|
769
|
-
* filename is the only mutable field on an `_attachment@1` record; fileId,
|
|
770
|
-
* size and mimeType are immutable, and the correction flow is delete +
|
|
771
|
-
* re-upload. `violates` decides what counts as touching one, because the
|
|
772
|
-
* two write shapes disagree: a patch names only what it changes, while a
|
|
773
|
-
* migration replaces content wholesale and necessarily re-sends all three.
|
|
774
|
-
*
|
|
775
|
-
* Repointing `fileId` is the one that matters most: an `_attachment@1`
|
|
776
|
-
* record naming a fileId is what canAccessFile()'s uploader clause reads,
|
|
777
|
-
* so moving an existing record onto another file's hash is a route to
|
|
778
|
-
* bytes the record's author never uploaded.
|
|
779
|
-
* See docs/spec/attachments.md § The `_attachment` record type.
|
|
780
|
-
*/
|
|
781
|
-
private assertAttachmentImmutable;
|
|
782
|
-
/**
|
|
783
|
-
* `_config.entityId` defines stack ownership; neither patchContent() nor
|
|
784
|
-
* restoreVersion() may change it. A conflict with stack integrity, not a
|
|
785
|
-
* schema violation — hence StackConflictError. See docs/spec.md § The
|
|
786
|
-
* `_config` record.
|
|
787
|
-
*/
|
|
788
|
-
private checkConfigEntityIdUnchanged;
|
|
789
|
-
/**
|
|
790
|
-
* Store bytes and create an _attachment@1 metadata record (owner-
|
|
791
|
-
* attributed, no createdBy), returning that record — `content.fileId`
|
|
792
|
-
* addresses the bytes, `id` addresses the metadata. Delegates to the
|
|
793
|
-
* adapter's atomic putAttachmentWithMetadata() when implemented, trusting
|
|
794
|
-
* the returned record as backend-authoritative; otherwise falls back to
|
|
795
|
-
* bytes-then-create(). See docs/spec/wire-format.md § Attachments.
|
|
796
|
-
*/
|
|
797
|
-
putAttachment(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord & {
|
|
798
|
-
content: AttachmentContent;
|
|
799
|
-
}>;
|
|
800
|
-
getAttachment(fileId: FileId): Promise<Uint8Array>;
|
|
801
|
-
/**
|
|
802
|
-
* Every `_attachment` record describing `fileId`, earliest-recorded
|
|
803
|
-
* first — so `records[0]` is the one that establishes the file's
|
|
804
|
-
* mimeType, and firstRecordedAttachment() is only needed by a caller
|
|
805
|
-
* narrowing the set further. See docs/spec/attachments.md § Finding a
|
|
806
|
-
* `fileId`'s metadata records.
|
|
807
|
-
*
|
|
808
|
-
* On `Stack` and not `StackClient`: the lookup answers a presentation
|
|
809
|
-
* question about an access decision already made, so a scoped version
|
|
810
|
-
* would impose a second, different permission check rather than a
|
|
811
|
-
* narrower correct answer.
|
|
812
|
-
*/
|
|
813
|
-
getAttachmentRecords(fileId: FileId): Promise<(StackRecord & {
|
|
814
|
-
content: AttachmentContent;
|
|
815
|
-
})[]>;
|
|
816
|
-
/**
|
|
817
|
-
* The `_attachment` family as concrete typeIds. Resolved here rather
|
|
818
|
-
* than in the adapter, which has no baseId concept of its own — see
|
|
819
|
-
* resolveBaseIdFilter().
|
|
820
|
-
*/
|
|
821
|
-
private attachmentTypeIds;
|
|
822
|
-
/**
|
|
823
|
-
* Delete an attachment's bytes and every _attachment metadata record for
|
|
824
|
-
* it, family-wide. Throws StackConflictError if any record in the stack
|
|
825
|
-
* still references the file, StackNotFoundError if neither metadata
|
|
826
|
-
* records nor bytes exist.
|
|
827
|
-
*/
|
|
828
|
-
deleteAttachment(fileId: FileId, opts?: ActorOptions): Promise<void>;
|
|
829
|
-
/**
|
|
830
|
-
* Non-atomic fallback for adapters that don't implement
|
|
831
|
-
* deleteUnreferencedAttachmentRecords(): a concurrent associate() can
|
|
832
|
-
* race between the reference check below and the deletes it guards.
|
|
833
|
-
*/
|
|
834
|
-
private deleteUnreferencedAttachmentRecordsFallback;
|
|
835
|
-
/**
|
|
836
|
-
* Sweep for attachment bytes unreachable from any record — live or
|
|
837
|
-
* soft-deleted — and delete bytes + metadata. Deletion goes through
|
|
838
|
-
* deleteAttachment(), so a file re-referenced by sweep time is skipped,
|
|
839
|
-
* not a failure. See docs/spec/attachments.md § Garbage collection.
|
|
840
|
-
*/
|
|
841
|
-
collectAttachmentGarbage(opts?: CollectAttachmentGarbageOptions & ActorOptions): Promise<CollectAttachmentGarbageResult>;
|
|
842
|
-
/**
|
|
843
|
-
* Observe every change made through this Stack. Unscoped, so no
|
|
844
|
-
* permission filter applies — a caller holding a `Stack` already reaches
|
|
845
|
-
* every record by other means; `ScopedStack.subscribe()` is the filtered
|
|
846
|
-
* view. See docs/spec/events.md.
|
|
847
|
-
*
|
|
848
|
-
* Async so that a remote stack can resolve once its feed is live, which
|
|
849
|
-
* makes subscribe-then-query the gap-free startup order everywhere. A
|
|
850
|
-
* local stack is live immediately.
|
|
851
|
-
*/
|
|
852
|
-
subscribe<S extends ReadonlyTypeSchema>(handle: TypeHandle<S>, handler: (change: TypedChange<S>) => void, opts?: TypedSubscribeOptions): Promise<Unsubscribe>;
|
|
853
|
-
subscribe(handler: (change: RecordChange) => void, opts?: SubscribeOptions): Promise<Unsubscribe>;
|
|
854
|
-
/**
|
|
855
|
-
* Ask the adapter to relay changes that originated elsewhere. Absent on
|
|
856
|
-
* every local adapter, where one process owns the storage and there is
|
|
857
|
-
* no third party whose writes could have been missed.
|
|
858
|
-
*
|
|
859
|
-
* The subscription's own filter goes to the relay rather than being
|
|
860
|
-
* applied on the way back: the emitter at the far end holds the record,
|
|
861
|
-
* so it can answer `createdBy` and `parentId`, which the envelope
|
|
862
|
-
* deliberately does not carry. That is also why a relay is opened per
|
|
863
|
-
* subscription rather than shared.
|
|
864
|
-
*/
|
|
865
|
-
private openRelay;
|
|
866
|
-
/** Whether changes reach this stack from elsewhere. */
|
|
867
|
-
private get relaysChanges();
|
|
868
|
-
/**
|
|
869
|
-
* Flush pending writes to the underlying storage. A no-op for adapters
|
|
870
|
-
* that commit on every call (SQLite, the API adapter); meaningful for
|
|
871
|
-
* ones that buffer, and for checkpointing a stack that stays open —
|
|
872
|
-
* close() covers the teardown case on its own.
|
|
873
|
-
*/
|
|
874
|
-
flush(): Promise<void>;
|
|
875
|
-
/**
|
|
876
|
-
* Flush, then release any resources the adapter holds (connections, file
|
|
877
|
-
* handles, lock files). A failed flush still releases them before it
|
|
878
|
-
* propagates: an unwritable stack must not also leak a lock file.
|
|
879
|
-
* See docs/spec/adapters.md § Lifecycle.
|
|
880
|
-
*/
|
|
881
|
-
close(): Promise<void>;
|
|
882
|
-
/** Throws once close() has run. */
|
|
883
|
-
private assertOpen;
|
|
884
|
-
/**
|
|
885
|
-
* Create a _grant record authorizing `grantee` to take `actions` on
|
|
886
|
-
* records of `typeId`: `{ kind: 'entity' }` for one DID, `{ kind: 'group' }`
|
|
887
|
-
* for a `_group` Record's roster at a role, `{ kind: 'authenticated' }` for
|
|
888
|
-
* any authenticated entity. The type-level mirror of grantAccess() —
|
|
889
|
-
* subject first, grantee inside the element.
|
|
890
|
-
*
|
|
891
|
-
* Granting an **app** a `-own` action does not contain it the way the
|
|
892
|
-
* suffix suggests: when that app acts for someone, `-own` is read as the
|
|
893
|
-
* bare verb and the subject decides which records are in reach, so in a
|
|
894
|
-
* personal stack — where nearly every record is owner-authored — a
|
|
895
|
-
* delegated `read-own` is close to `read-any`. Grant an app the types it
|
|
896
|
-
* needs, not the suffix that looks narrowest. See
|
|
897
|
-
* docs/spec/access-control.md § Delegation: principal and subject.
|
|
898
|
-
*
|
|
899
|
-
* `baseId` names the whole family and is refused when it carries an
|
|
900
|
-
* `@version` suffix. See docs/spec/access-control.md § Type-level grants.
|
|
901
|
-
*/
|
|
902
|
-
grantType(baseId: BaseId, grant: TypeGrant): Promise<StackRecord & {
|
|
903
|
-
content: GrantContent;
|
|
904
|
-
}>;
|
|
905
|
-
/**
|
|
906
|
-
* List _grant records. Omit `query` for all grants;
|
|
907
|
-
* `{ kind: 'authenticated' }` for only default grants;
|
|
908
|
-
* `{ kind: 'group' }` for grants naming that exact group and role, or
|
|
909
|
-
* `role: 'any'` for every grant naming the group;
|
|
910
|
-
* `{ kind: 'entity' }` for the grants that currently apply to that entity
|
|
911
|
-
* (ones naming them, ones naming a group they belong to at a role they
|
|
912
|
-
* hold, plus every default grant) — the same resolution hasGrant() uses.
|
|
913
|
-
*
|
|
914
|
-
* Every arm but `entity` answers identity — what `grantType()` would have
|
|
915
|
-
* written with the same argument. The `entity` arm answers coverage, so
|
|
916
|
-
* its result is not a preview of what `revokeType()` would withdraw.
|
|
917
|
-
* See docs/spec/access-control.md § Type-level grants.
|
|
918
|
-
*/
|
|
919
|
-
listTypeGrants(query?: GrantQuery): Promise<(StackRecord & {
|
|
920
|
-
content: GrantContent;
|
|
921
|
-
})[]>;
|
|
922
|
-
/**
|
|
923
|
-
* The inverse of grantType(): soft-deletes the _grant records on
|
|
924
|
-
* `baseId`'s family matching `grant`, at the same granularity
|
|
925
|
-
* grantType() writes — the grantee is matched whole, role included, and
|
|
926
|
-
* the actions exactly. A soft delete like any other — the owner can
|
|
927
|
-
* undelete a revocation.
|
|
928
|
-
*
|
|
929
|
-
* Returns the grants it withdrew, as they stood: an array, where
|
|
930
|
-
* revokeAccess() returns one Record, because one target can match several
|
|
931
|
-
* _grant records. An empty result is not an error — re-running a
|
|
932
|
-
* revocation has to stay safe. See
|
|
933
|
-
* docs/spec/access-control.md § Listing and revoking.
|
|
934
|
-
*/
|
|
935
|
-
revokeType(baseId: BaseId, grant: TypeGrant): Promise<(StackRecord & {
|
|
936
|
-
content: GrantContent;
|
|
937
|
-
})[]>;
|
|
938
|
-
/**
|
|
939
|
-
* Actions must be known GrantAction values; the target is held to the
|
|
940
|
-
* same rule every `_grant` write meets — see validateGrantBaseId().
|
|
941
|
-
*/
|
|
942
|
-
private checkGrantValid;
|
|
943
|
-
private seedSystemTypes;
|
|
944
|
-
/**
|
|
945
|
-
* Fast-fail for the ifVersion precondition using the already-fetched
|
|
946
|
-
* record. The adapter re-checks atomically at write time (the source of
|
|
947
|
-
* truth for concurrent writers) — this just skips validation and
|
|
948
|
-
* snapshotting work when the mismatch is already visible.
|
|
949
|
-
*/
|
|
950
|
-
private checkIfVersion;
|
|
951
|
-
/**
|
|
952
|
-
* The options every version-bumping adapter write carries: the `ifVersion`
|
|
953
|
-
* precondition, the prior-state snapshot that has to land in the same
|
|
954
|
-
* atomic write, and who to attribute the change to. Taken together so a
|
|
955
|
-
* new mutating verb cannot quietly omit one — the actor's `principalId`
|
|
956
|
-
* most of all, whose absence reads as an undelegated write.
|
|
957
|
-
* See docs/spec/versioning.md § Version history.
|
|
958
|
-
*/
|
|
959
|
-
private writeOptions;
|
|
960
|
-
/**
|
|
961
|
-
* Snapshot of a record's prior state, passed with the mutating adapter
|
|
962
|
-
* call so snapshot and mutation land in one atomic write. Carries what
|
|
963
|
-
* only a snapshot preserves: `content` and the `typeId` it is read
|
|
964
|
-
* under. Containment, listing and associations — the authority ones
|
|
965
|
-
* among them — are all kept by the journal instead, so no version ever
|
|
966
|
-
* snapshots them and there is nothing for a restore to roll them back
|
|
967
|
-
* to. See docs/spec/versioning.md § Version history.
|
|
968
|
-
*/
|
|
969
|
-
private buildVersionSnapshot;
|
|
970
|
-
}
|
|
971
|
-
//# sourceMappingURL=stack.d.ts.map
|