@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/types.d.ts
DELETED
|
@@ -1,1250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stack — Core Type Definitions
|
|
3
|
-
* -------------------------------------------------------
|
|
4
|
-
* This file is the source of truth for all types in the
|
|
5
|
-
* Stack library. No logic lives here — just shapes.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Crockford base-32 encoded ID — time-sortable, unique within a stack.
|
|
9
|
-
* Format: 9-char timestamp prefix + 3-char random suffix = 12 chars total.
|
|
10
|
-
* Human-readable and URL-safe. Uniqueness is within-stack only;
|
|
11
|
-
* cross-stack references must include a stackUrl to disambiguate.
|
|
12
|
-
*/
|
|
13
|
-
export type RecordId = string;
|
|
14
|
-
/** Namespaced, versioned type identifier e.g. "com.example.myapp/note@2" */
|
|
15
|
-
export type TypeId = string;
|
|
16
|
-
/** A type family: a TypeId without its version, e.g. "com.example.myapp/note" */
|
|
17
|
-
export type BaseId = string;
|
|
18
|
-
/** Opaque file identifier returned by putBlob() */
|
|
19
|
-
export type FileId = string;
|
|
20
|
-
/**
|
|
21
|
-
* Reverse-DNS identifier for the software that wrote a Record, e.g.
|
|
22
|
-
* "com.example.myapp" — not a RecordId. Self-reported and never a
|
|
23
|
-
* permission input; `StackRecord.createdBy.principalId` is the verified
|
|
24
|
-
* counterpart.
|
|
25
|
-
* See docs/spec/identity.md § App.
|
|
26
|
-
*/
|
|
27
|
-
export type AppId = string;
|
|
28
|
-
/**
|
|
29
|
-
* Identifies a "who" — a DID string, e.g. "did:key:z6Mk...". A
|
|
30
|
-
* self-certifying identifier that means the same thing in every stack,
|
|
31
|
-
* unlike a RecordId. did:key is the mandatory floor method (see did.ts).
|
|
32
|
-
* See docs/spec/identity.md.
|
|
33
|
-
*/
|
|
34
|
-
export type EntityId = string;
|
|
35
|
-
/**
|
|
36
|
-
* Who did something, and through which principal. `subjectId` is who the
|
|
37
|
-
* act is attributed to; `principalId` is who authenticated, present only
|
|
38
|
-
* when it differs — a delegated app acting for its user. `Stack` stores
|
|
39
|
-
* a `principalId` equal to `subjectId` as absent, so the two spellings of
|
|
40
|
-
* "acted as itself" never diverge. See docs/spec/data-model.md § Actor.
|
|
41
|
-
*/
|
|
42
|
-
export type Actor = {
|
|
43
|
-
subjectId: EntityId;
|
|
44
|
-
principalId?: EntityId;
|
|
45
|
-
};
|
|
46
|
-
export type TagAssociation = {
|
|
47
|
-
kind: 'tag';
|
|
48
|
-
label: string;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* `attachmentRecordId` names the `_attachment` record whose upload
|
|
52
|
-
* established this reference — annotation, not identity, since `fileId`
|
|
53
|
-
* alone is what GC, the `referencesFileId` filter and file access ask
|
|
54
|
-
* about. See docs/spec/attachments.md § Naming the upload a reference came from.
|
|
55
|
-
*/
|
|
56
|
-
export type AttachmentAssociation = {
|
|
57
|
-
kind: 'attachment';
|
|
58
|
-
label: string;
|
|
59
|
-
fileId: FileId;
|
|
60
|
-
attachmentRecordId?: RecordId;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* A Record in this stack, or in another one. `stackUrl` is what makes a
|
|
64
|
-
* RecordId meaningful outside the stack that minted it — absent means this
|
|
65
|
-
* stack. See docs/spec/data-model.md § Associations.
|
|
66
|
-
*/
|
|
67
|
-
export type RecordTarget = {
|
|
68
|
-
kind: 'record';
|
|
69
|
-
recordId: RecordId;
|
|
70
|
-
stackUrl?: string;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* A "who" — a DID, which means the same thing in every stack. Group
|
|
74
|
-
* rosters are the canonical use: membership names identities, not records.
|
|
75
|
-
* See docs/spec/identity.md § Group.
|
|
76
|
-
*/
|
|
77
|
-
export type EntityTarget = {
|
|
78
|
-
kind: 'entity';
|
|
79
|
-
entityId: EntityId;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Something outside the stack entirely. `ns` names the scheme that
|
|
83
|
-
* interprets `id` — e.g. "atproto", "activitypub", "email", "url" — so an
|
|
84
|
-
* app selects on it rather than sniffing the identifier.
|
|
85
|
-
* See docs/spec/data-model.md § Relationship targets.
|
|
86
|
-
*/
|
|
87
|
-
export type ExternalTarget = {
|
|
88
|
-
kind: 'external';
|
|
89
|
-
ns: string;
|
|
90
|
-
id: string;
|
|
91
|
-
};
|
|
92
|
-
/** What a relationship association points at. */
|
|
93
|
-
export type RelationshipTarget = RecordTarget | EntityTarget | ExternalTarget;
|
|
94
|
-
export type RelationshipAssociation = {
|
|
95
|
-
kind: 'relationship';
|
|
96
|
-
label: string;
|
|
97
|
-
target: RelationshipTarget;
|
|
98
|
-
};
|
|
99
|
-
/**
|
|
100
|
-
* A grant of access to the Record carrying it. The bit is the label, so
|
|
101
|
-
* granting and revoking are a plain add and remove and the element's
|
|
102
|
-
* identity carries its whole meaning. Its grantee shape is its own rather
|
|
103
|
-
* than a `RelationshipTarget`: a target names no role and has no group
|
|
104
|
-
* arm. See docs/spec/access-control.md § Record-level permissions.
|
|
105
|
-
*/
|
|
106
|
-
export type PermissionAssociation = {
|
|
107
|
-
kind: 'permission';
|
|
108
|
-
label: 'read' | 'write';
|
|
109
|
-
grantee: Grantee;
|
|
110
|
-
};
|
|
111
|
-
/** An entity's standing within a `_group` Record's roster. `admin` implies `member` for ACL purposes. */
|
|
112
|
-
export type GroupRole = 'member' | 'admin';
|
|
113
|
-
/**
|
|
114
|
-
* The grantee arms both permission layers share, spelled identically so a
|
|
115
|
-
* value built for one is valid for the other. `role` is required — `member`
|
|
116
|
-
* is the wider set, `admin` the narrower, matching the roster labels where
|
|
117
|
-
* admin implies member. See docs/spec/access-control.md § Who a grant reaches.
|
|
118
|
-
*/
|
|
119
|
-
export type Grantee = {
|
|
120
|
-
kind: 'entity';
|
|
121
|
-
entityId: EntityId;
|
|
122
|
-
} | {
|
|
123
|
-
kind: 'group';
|
|
124
|
-
groupId: RecordId;
|
|
125
|
-
role: GroupRole;
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Reach to the world, spelled affirmatively: it names no grantee and
|
|
129
|
-
* carries no bit beyond `read`, so no dropped field on a
|
|
130
|
-
* `PermissionAssociation` can produce it.
|
|
131
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
132
|
-
*/
|
|
133
|
-
export type AnyoneAssociation = {
|
|
134
|
-
kind: 'anyone';
|
|
135
|
-
label: 'read';
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* The authority half of the association table — what the `permissions`
|
|
139
|
-
* field projects. See docs/spec/access-control.md § Record-level
|
|
140
|
-
* permissions.
|
|
141
|
-
*/
|
|
142
|
-
export type AuthorityAssociation = PermissionAssociation | AnyoneAssociation;
|
|
143
|
-
/**
|
|
144
|
-
* The data half — what the `associations` field projects, and the only
|
|
145
|
-
* kinds `associate()`/`dissociate()` accept.
|
|
146
|
-
* See docs/spec/data-model.md § Associations.
|
|
147
|
-
*/
|
|
148
|
-
export type DataAssociation = TagAssociation | AttachmentAssociation | RelationshipAssociation;
|
|
149
|
-
/**
|
|
150
|
-
* Every edge a Record carries, authority and data alike. One shape, one
|
|
151
|
-
* delta and one durability tier; the two halves stay separate call
|
|
152
|
-
* surfaces because they carry different authority.
|
|
153
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
154
|
-
*/
|
|
155
|
-
export type Association = DataAssociation | AuthorityAssociation;
|
|
156
|
-
/**
|
|
157
|
-
* One association a write moved, and what it moved from. Every inverse is
|
|
158
|
-
* local to one element — there is no join back to a sibling list, so there
|
|
159
|
-
* is no join key to get wrong. `previous` is carried in full, annotation
|
|
160
|
-
* included, which is what makes a `repoint` undoable; a `remove` names the
|
|
161
|
-
* element it took away in `association`, in full.
|
|
162
|
-
* See docs/spec/journal.md § The entry.
|
|
163
|
-
*/
|
|
164
|
-
export type AssociationChange = {
|
|
165
|
-
op: 'add';
|
|
166
|
-
association: Association;
|
|
167
|
-
} | {
|
|
168
|
-
op: 'repoint';
|
|
169
|
-
association: Association;
|
|
170
|
-
previous: Association;
|
|
171
|
-
} | {
|
|
172
|
-
op: 'remove';
|
|
173
|
-
association: Association;
|
|
174
|
-
};
|
|
175
|
-
/**
|
|
176
|
-
* What a caller sends: the journal's shape without `repoint`, which the
|
|
177
|
-
* journal records and no caller requests. See docs/spec/journal.md § The entry.
|
|
178
|
-
*/
|
|
179
|
-
export type AssociationEdit = Exclude<AssociationChange, {
|
|
180
|
-
op: 'repoint';
|
|
181
|
-
}>;
|
|
182
|
-
/**
|
|
183
|
-
* The aspects of an existing record one mutate() call may move, in any
|
|
184
|
-
* combination. Every key replaces the aspect it names except
|
|
185
|
-
* `contentPatch`, which merges at the top level — omitted keeps, `null`
|
|
186
|
-
* removes. Keys are read for presence, so `unlisted: false` and
|
|
187
|
-
* `parentId: null` are changes; an omitted key is untouched.
|
|
188
|
-
*
|
|
189
|
-
* `associations` replaces the whole set. associate()/dissociate() amend it
|
|
190
|
-
* instead, which is the spelling that survives two writers touching one
|
|
191
|
-
* record, so they stay their own verbs rather than folding in here.
|
|
192
|
-
* See docs/spec/data-model.md § Mutations.
|
|
193
|
-
*/
|
|
194
|
-
export type RecordChangeSet = {
|
|
195
|
-
contentPatch?: Record<string, unknown | null>;
|
|
196
|
-
parentId?: RecordId | null;
|
|
197
|
-
permissions?: AuthorityAssociation[];
|
|
198
|
-
associations?: DataAssociation[];
|
|
199
|
-
unlisted?: boolean;
|
|
200
|
-
};
|
|
201
|
-
/** The keys of a change set, for presence checks that must not miss one. */
|
|
202
|
-
export declare const RECORD_CHANGE_SET_KEYS: readonly ["contentPatch", "parentId", "permissions", "associations", "unlisted"];
|
|
203
|
-
export type StackRecord = {
|
|
204
|
-
id: RecordId;
|
|
205
|
-
typeId: TypeId;
|
|
206
|
-
createdAt: Date;
|
|
207
|
-
updatedAt: Date;
|
|
208
|
-
content: Record<string, unknown>;
|
|
209
|
-
/**
|
|
210
|
-
* Ordinal of the snapshot history, not a count of changes: associations,
|
|
211
|
-
* permissions, parent and listing moves leave it alone. See
|
|
212
|
-
* docs/spec/versioning.md § Version history.
|
|
213
|
-
*/
|
|
214
|
-
version: number;
|
|
215
|
-
parentId?: RecordId;
|
|
216
|
-
appId?: AppId;
|
|
217
|
-
/**
|
|
218
|
-
* The record's author, stamped once by the create. A `principalId` here
|
|
219
|
-
* is what lets `appId` be checked against the `_app` record naming that
|
|
220
|
-
* DID; without one, `appId` is an unverifiable self-report.
|
|
221
|
-
* See docs/spec/data-model.md § Authorship and attribution.
|
|
222
|
-
*/
|
|
223
|
-
createdBy?: Actor;
|
|
224
|
-
/**
|
|
225
|
-
* Who performed the mutation this version records — unlike `createdBy`,
|
|
226
|
-
* it moves with every write. Absent means an unscoped `Stack` wrote it,
|
|
227
|
-
* which names no requester.
|
|
228
|
-
* See docs/spec/data-model.md § Authorship and attribution.
|
|
229
|
-
*/
|
|
230
|
-
updatedBy?: Actor;
|
|
231
|
-
deletedAt?: Date;
|
|
232
|
-
/**
|
|
233
|
-
* Present when the record is withheld from enumeration — absent from
|
|
234
|
-
* `query()` and the change feed by default, but still reachable by
|
|
235
|
-
* `get()` for anyone who may read it. Orthogonal to `permissions`: it
|
|
236
|
-
* says nothing about who may read the record, only whether its
|
|
237
|
-
* existence is discoverable without already holding its ID. See
|
|
238
|
-
* docs/spec/unlisted.md.
|
|
239
|
-
*/
|
|
240
|
-
unlistedAt?: Date;
|
|
241
|
-
/**
|
|
242
|
-
* Who reaches this Record, projected from the association table's
|
|
243
|
-
* authority kinds. Absent or empty means private — readable only by the
|
|
244
|
-
* stack owner. Declarative intent; enforcement is `ScopedStack`'s.
|
|
245
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
246
|
-
*/
|
|
247
|
-
permissions?: AuthorityAssociation[];
|
|
248
|
-
associations?: DataAssociation[];
|
|
249
|
-
};
|
|
250
|
-
export type RecordVersion = {
|
|
251
|
-
version: number;
|
|
252
|
-
/** The record's typeId at the moment this version was snapshotted. */
|
|
253
|
-
typeId: TypeId;
|
|
254
|
-
content: Record<string, unknown>;
|
|
255
|
-
updatedAt: Date;
|
|
256
|
-
/**
|
|
257
|
-
* The record's author, carried through from `record.createdBy` — not the
|
|
258
|
-
* actor of the change this version records.
|
|
259
|
-
* See docs/spec/versioning.md § Version history.
|
|
260
|
-
*/
|
|
261
|
-
createdBy?: Actor;
|
|
262
|
-
/** Who performed the mutation that produced this version. */
|
|
263
|
-
updatedBy?: Actor;
|
|
264
|
-
};
|
|
265
|
-
export type ScalarFieldKind = 'string' | 'number' | 'boolean' | 'date' | 'text' | 'record-ref' | 'file-ref';
|
|
266
|
-
/**
|
|
267
|
-
* `enum` is a non-empty, duplicate-free list of the strings the field may
|
|
268
|
-
* hold. See docs/spec/data-model.md § Types.
|
|
269
|
-
*/
|
|
270
|
-
export type StringFieldDef = {
|
|
271
|
-
kind: 'string';
|
|
272
|
-
enum?: string[];
|
|
273
|
-
required?: boolean;
|
|
274
|
-
};
|
|
275
|
-
export type ScalarFieldDef = StringFieldDef | {
|
|
276
|
-
kind: Exclude<ScalarFieldKind, 'string'>;
|
|
277
|
-
required?: boolean;
|
|
278
|
-
};
|
|
279
|
-
/**
|
|
280
|
-
* A list. `open: true` leaves its elements unvalidated,
|
|
281
|
-
* which is how a heterogeneous or null-bearing list is spelled. Opacity is
|
|
282
|
-
* declared rather than inferred from a missing `items`, so a schema that
|
|
283
|
-
* forgets to describe its elements is a type error rather than a silently
|
|
284
|
-
* unchecked field. See docs/spec/data-model.md § Undeclared content fields.
|
|
285
|
-
*/
|
|
286
|
-
export type ArrayFieldDef = {
|
|
287
|
-
kind: 'array';
|
|
288
|
-
items: FieldDef;
|
|
289
|
-
open?: false;
|
|
290
|
-
required?: boolean;
|
|
291
|
-
} | {
|
|
292
|
-
kind: 'array';
|
|
293
|
-
open: true;
|
|
294
|
-
items?: undefined;
|
|
295
|
-
required?: boolean;
|
|
296
|
-
};
|
|
297
|
-
/**
|
|
298
|
-
* An object. `open: true` leaves its keys unvalidated,
|
|
299
|
-
* which is the one way to store a shape a schema does not describe. Same
|
|
300
|
-
* reason as ArrayFieldDef for making it a declaration rather than an
|
|
301
|
-
* omission. See docs/spec/data-model.md § Undeclared content fields.
|
|
302
|
-
*/
|
|
303
|
-
export type ObjectFieldDef = {
|
|
304
|
-
kind: 'object';
|
|
305
|
-
properties: TypeSchema;
|
|
306
|
-
open?: false;
|
|
307
|
-
required?: boolean;
|
|
308
|
-
} | {
|
|
309
|
-
kind: 'object';
|
|
310
|
-
open: true;
|
|
311
|
-
properties?: undefined;
|
|
312
|
-
required?: boolean;
|
|
313
|
-
};
|
|
314
|
-
/**
|
|
315
|
-
* A field definition in a Type schema. Supports scalars, arrays, and nested
|
|
316
|
-
* objects. Arrays and nested objects are schema-validated on write but are
|
|
317
|
-
* opaque to the query engine in v1 — only top-level scalar fields support
|
|
318
|
-
* exact-match content filtering in queries.
|
|
319
|
-
*/
|
|
320
|
-
export type FieldDef = ScalarFieldDef | ArrayFieldDef | ObjectFieldDef;
|
|
321
|
-
export type TypeSchema = {
|
|
322
|
-
[fieldName: string]: FieldDef;
|
|
323
|
-
};
|
|
324
|
-
export type StackType = {
|
|
325
|
-
id: TypeId;
|
|
326
|
-
baseId: BaseId;
|
|
327
|
-
version: number;
|
|
328
|
-
name: string;
|
|
329
|
-
schema: TypeSchema;
|
|
330
|
-
schemaHash: string;
|
|
331
|
-
migratesFrom?: TypeId;
|
|
332
|
-
createdAt: Date;
|
|
333
|
-
};
|
|
334
|
-
/**
|
|
335
|
-
* Content for _entity records: a stack-local profile card *about* a DID,
|
|
336
|
-
* not the identity itself. `name`/`handle` are this owner's local labels
|
|
337
|
-
* for that DID (the petname pattern), so two stacks holding different
|
|
338
|
-
* names for the same DID is correct. See docs/spec/identity.md § Entity.
|
|
339
|
-
*/
|
|
340
|
-
export type EntityContent = {
|
|
341
|
-
/**
|
|
342
|
-
* The identity this profile is about. e.g. "did:key:z6Mk...". A binding,
|
|
343
|
-
* not a value — an Actor's `subjectId` resolves through it to the name
|
|
344
|
-
* this card carries, so it is unique per stack and immutable once set.
|
|
345
|
-
* See docs/spec/identity.md § DID bindings.
|
|
346
|
-
*/
|
|
347
|
-
did: string;
|
|
348
|
-
/** Display name — human-friendly, not necessarily unique. May contain spaces and punctuation. e.g. "Jane Smith" */
|
|
349
|
-
name: string;
|
|
350
|
-
/**
|
|
351
|
-
* Short, conventionally URL-safe label. e.g. "janesmith". A label, not a
|
|
352
|
-
* key: duplicates are legitimate and `did` is what identifies this
|
|
353
|
-
* profile. See docs/spec/identity.md § Entity.
|
|
354
|
-
*/
|
|
355
|
-
handle?: string;
|
|
356
|
-
};
|
|
357
|
-
/** Content for _app records */
|
|
358
|
-
export type AppContent = {
|
|
359
|
-
/**
|
|
360
|
-
* The software this card is about, in reverse-DNS form — the value a
|
|
361
|
-
* Record's `appId` is checked against. Distinct from the card Record's
|
|
362
|
-
* own `appId`, which names whatever wrote the card (an admin console
|
|
363
|
-
* registering a third-party app is the ordinary case, and the two differ
|
|
364
|
-
* there). See docs/spec/identity.md § App.
|
|
365
|
-
*/
|
|
366
|
-
appId: AppId;
|
|
367
|
-
/** Display name of the app e.g. "My Notes App" */
|
|
368
|
-
name: string;
|
|
369
|
-
/** Semver string e.g. "1.0.0". `appId` is the machine-readable identity, so no handle is needed here. */
|
|
370
|
-
version?: string;
|
|
371
|
-
/**
|
|
372
|
-
* The DID this app authenticates with, when it holds a key of its own.
|
|
373
|
-
* Lets an attribution UI resolve an Actor's `principalId` to this card,
|
|
374
|
-
* and a server check a self-reported `appId` against the principal that
|
|
375
|
-
* wrote it. Absent for apps that ride their user's identity. Unique per
|
|
376
|
-
* stack and immutable once set, like `appId` above — see
|
|
377
|
-
* docs/spec/identity.md § DID bindings.
|
|
378
|
-
*/
|
|
379
|
-
did?: string;
|
|
380
|
-
};
|
|
381
|
-
/** Content for _group records */
|
|
382
|
-
export type GroupContent = {
|
|
383
|
-
/** Display name — human-friendly, not necessarily unique. May contain spaces and punctuation. e.g. "Jane's Book Club" */
|
|
384
|
-
name: string;
|
|
385
|
-
/**
|
|
386
|
-
* Short, conventionally URL-safe label. e.g. "janes-book-club". A label,
|
|
387
|
-
* not a key: duplicates are legitimate, and a group is addressed by
|
|
388
|
-
* `stackUrl` when it has one and by its record id otherwise. See
|
|
389
|
-
* docs/spec/identity.md § Group.
|
|
390
|
-
*/
|
|
391
|
-
handle?: string;
|
|
392
|
-
/** If present, this group owns a shared collaborative stack at this URL. Absent = permission-only group. */
|
|
393
|
-
stackUrl?: string;
|
|
394
|
-
};
|
|
395
|
-
/**
|
|
396
|
-
* Actions that can be granted via a _grant record. The array is the source
|
|
397
|
-
* of truth — GrantAction is derived from it so runtime validation (see
|
|
398
|
-
* Stack.grantType()) can't drift from the type.
|
|
399
|
-
*/
|
|
400
|
-
export declare const GRANT_ACTIONS: readonly ["create", "read-own", "read-any", "update-own", "update-any", "delete-own", "delete-any"];
|
|
401
|
-
export type GrantAction = (typeof GRANT_ACTIONS)[number];
|
|
402
|
-
/**
|
|
403
|
-
* Who a Grant reaches, spelled affirmatively. Each tier names itself, so
|
|
404
|
-
* no dropped field turns one into another: a `_grant` Record that lost its
|
|
405
|
-
* grantee names nobody rather than everybody.
|
|
406
|
-
*
|
|
407
|
-
* `{ kind: 'authenticated' }` reaches any authenticated entity — narrower
|
|
408
|
-
* than a Record permission's `{ kind: 'anyone' }`, which reaches anonymous
|
|
409
|
-
* requesters too. The two tiers deliberately share no word.
|
|
410
|
-
*
|
|
411
|
-
* `role` is required on the group arm — `member` is the wider set, `admin`
|
|
412
|
-
* the narrower, matching the roster labels where admin implies member (see
|
|
413
|
-
* docs/spec/identity.md § Group). A group grantee never satisfies the
|
|
414
|
-
* principal half of a delegated request.
|
|
415
|
-
* See docs/spec/access-control.md § Type-level grants.
|
|
416
|
-
*/
|
|
417
|
-
export type GrantGrantee = Grantee | {
|
|
418
|
-
kind: 'authenticated';
|
|
419
|
-
};
|
|
420
|
-
/**
|
|
421
|
-
* What `Stack.grantType()` and `Stack.revokeType()` take beside the type they act
|
|
422
|
-
* on — the type-level counterpart of the `AuthorityAssociation`
|
|
423
|
-
* `grantAccess()` takes beside a record id.
|
|
424
|
-
*/
|
|
425
|
-
export type TypeGrant = {
|
|
426
|
-
actions: GrantAction[];
|
|
427
|
-
grantee: GrantGrantee;
|
|
428
|
-
};
|
|
429
|
-
/** Content for _grant records */
|
|
430
|
-
export type GrantContent = {
|
|
431
|
-
/** The type family the grant applies to: a bare baseId, never a versioned TypeId. */
|
|
432
|
-
baseId: BaseId;
|
|
433
|
-
/** Which actions are permitted. */
|
|
434
|
-
actions: GrantAction[];
|
|
435
|
-
/** Who the grant reaches. Required — see GrantGrantee. */
|
|
436
|
-
grantee: GrantGrantee;
|
|
437
|
-
};
|
|
438
|
-
/** The metadata an upload's `_attachment@1` record carries beside its bytes. */
|
|
439
|
-
export type PutAttachmentOptions = {
|
|
440
|
-
mimeType: string;
|
|
441
|
-
filename?: string;
|
|
442
|
-
/** Attribution for the metadata record, as create()'s `appId`. */
|
|
443
|
-
appId?: AppId;
|
|
444
|
-
};
|
|
445
|
-
/** Content for _attachment records — one per upload, tracks file metadata. */
|
|
446
|
-
export type AttachmentContent = {
|
|
447
|
-
/** Content-addressed file identifier (SHA-256 hex). */
|
|
448
|
-
fileId: FileId;
|
|
449
|
-
/** MIME type of the file. */
|
|
450
|
-
mimeType: string;
|
|
451
|
-
/** File size in bytes. */
|
|
452
|
-
size: number;
|
|
453
|
-
/** Original filename, if provided at upload time. */
|
|
454
|
-
filename?: string;
|
|
455
|
-
};
|
|
456
|
-
/** Content for _config records — one singleton per stack, created on initialization. */
|
|
457
|
-
export type ConfigContent = {
|
|
458
|
-
/**
|
|
459
|
-
* DID of the stack owner. Immutable — see docs/spec.md § The `_config`
|
|
460
|
-
* record for why ownership transfer isn't a field write.
|
|
461
|
-
*/
|
|
462
|
-
entityId: EntityId;
|
|
463
|
-
/**
|
|
464
|
-
* IANA timezone string e.g. "America/New_York". Optional passthrough app
|
|
465
|
-
* metadata — nothing in core reads it for behavior, and there is no
|
|
466
|
-
* default. See docs/spec.md § The `_config` record.
|
|
467
|
-
*/
|
|
468
|
-
timezone?: string;
|
|
469
|
-
};
|
|
470
|
-
/** Reserved system type IDs */
|
|
471
|
-
export declare const SYSTEM_TYPES: {
|
|
472
|
-
readonly ENTITY: "_entity";
|
|
473
|
-
readonly APP: "_app";
|
|
474
|
-
readonly GROUP: "_group";
|
|
475
|
-
/** Creation-permission grants. See GrantContent. */
|
|
476
|
-
readonly GRANT: "_grant";
|
|
477
|
-
/** Attachment metadata records. See AttachmentContent. */
|
|
478
|
-
readonly ATTACHMENT: "_attachment";
|
|
479
|
-
/** Stack-level configuration singleton. See ConfigContent. */
|
|
480
|
-
readonly CONFIG: "_config";
|
|
481
|
-
};
|
|
482
|
-
/**
|
|
483
|
-
* A target pattern in `RecordFilter.relatedTo` — the association shape with
|
|
484
|
-
* the parts a query may leave open: an `external` target without `id`
|
|
485
|
-
* matches its whole namespace.
|
|
486
|
-
*/
|
|
487
|
-
export type RelationshipTargetPattern = {
|
|
488
|
-
kind: 'record';
|
|
489
|
-
recordId: RecordId;
|
|
490
|
-
stackUrl?: string;
|
|
491
|
-
} | {
|
|
492
|
-
kind: 'entity';
|
|
493
|
-
entityId: EntityId;
|
|
494
|
-
} | {
|
|
495
|
-
kind: 'external';
|
|
496
|
-
ns: string;
|
|
497
|
-
id?: string;
|
|
498
|
-
};
|
|
499
|
-
/**
|
|
500
|
-
* A relationship query names a label, a target, or both — never neither.
|
|
501
|
-
* "Carries any relationship at all" is deliberately not expressible, in
|
|
502
|
-
* line with `tags` and `attachment`, which likewise have no match-any
|
|
503
|
-
* form. See docs/spec/data-model.md § Filter.
|
|
504
|
-
*/
|
|
505
|
-
export type RelatedToFilter = {
|
|
506
|
-
label: string;
|
|
507
|
-
target?: RelationshipTargetPattern;
|
|
508
|
-
} | {
|
|
509
|
-
label?: string;
|
|
510
|
-
target: RelationshipTargetPattern;
|
|
511
|
-
};
|
|
512
|
-
/**
|
|
513
|
-
* An attachment query names a label, a file, or both — never neither —
|
|
514
|
-
* and both halves together match one association. See
|
|
515
|
-
* docs/spec/data-model.md § Filter.
|
|
516
|
-
*/
|
|
517
|
-
export type AttachmentFilter = {
|
|
518
|
-
label: string;
|
|
519
|
-
fileId?: FileId;
|
|
520
|
-
} | {
|
|
521
|
-
label?: string;
|
|
522
|
-
fileId: FileId;
|
|
523
|
-
};
|
|
524
|
-
export type DateRange = {
|
|
525
|
-
before?: Date;
|
|
526
|
-
after?: Date;
|
|
527
|
-
};
|
|
528
|
-
export type RecordFilter = {
|
|
529
|
-
typeId?: TypeId | TypeId[];
|
|
530
|
-
/**
|
|
531
|
-
* Match every version of a type family — e.g. baseId: "com.example/note"
|
|
532
|
-
* matches both "com.example/note@1" and "com.example/note@2" records.
|
|
533
|
-
* Resolved against registered Types, not parsed from typeId strings, so
|
|
534
|
-
* it works regardless of which versions happen to exist. Combined with
|
|
535
|
-
* typeId (if both given) as an intersection. A value carrying an
|
|
536
|
-
* `@version` suffix is refused with StackValidationError.
|
|
537
|
-
*/
|
|
538
|
-
baseId?: BaseId | BaseId[];
|
|
539
|
-
parentId?: RecordId | null;
|
|
540
|
-
appId?: AppId | AppId[];
|
|
541
|
-
/** Matches the record's author — never the latest actor, which isn't filterable. */
|
|
542
|
-
createdBy?: {
|
|
543
|
-
subjectId?: EntityId | EntityId[];
|
|
544
|
-
principalId?: EntityId | EntityId[];
|
|
545
|
-
};
|
|
546
|
-
createdAt?: DateRange;
|
|
547
|
-
updatedAt?: DateRange;
|
|
548
|
-
tags?: string[];
|
|
549
|
-
/** Records carrying a matching attachment association. See docs/spec/data-model.md § Filter. */
|
|
550
|
-
attachment?: AttachmentFilter;
|
|
551
|
-
/**
|
|
552
|
-
* Records carrying a matching relationship association. Either half may
|
|
553
|
-
* be given alone and each is a pattern: a bare `label` matches every
|
|
554
|
-
* target under it, and an `external` target with no `id` matches the
|
|
555
|
-
* whole namespace. An absent `stackUrl` on a `record` target matches
|
|
556
|
-
* only local targets. See docs/spec/data-model.md § Filter.
|
|
557
|
-
*/
|
|
558
|
-
relatedTo?: RelatedToFilter;
|
|
559
|
-
/**
|
|
560
|
-
* Records that reference this file, through an attachment association
|
|
561
|
-
* or a top-level `file-ref` content field — the question GC and
|
|
562
|
-
* `deleteAttachment()` ask. See docs/spec/attachments.md § Deleting attachments.
|
|
563
|
-
*/
|
|
564
|
-
referencesFileId?: FileId;
|
|
565
|
-
/**
|
|
566
|
-
* Exact match on content fields, keyed by a dot-separated path
|
|
567
|
-
* (`'emails.value'`). An array anywhere along the path is matched
|
|
568
|
-
* element-wise, so the motivating question — which contact holds this
|
|
569
|
-
* email address — is one filter. A multi-segment key needs the
|
|
570
|
-
* `filter.content: 'path'` capability. POST /records/query only.
|
|
571
|
-
* See docs/spec/data-model.md § Filter.
|
|
572
|
-
*/
|
|
573
|
-
content?: Record<string, unknown>;
|
|
574
|
-
/**
|
|
575
|
-
* Paths that must hold a value: the question `content` cannot ask,
|
|
576
|
-
* since a filter value matches what is there rather than whether
|
|
577
|
-
* anything is. Element-wise like `content`, so a path holds a value
|
|
578
|
-
* when at least one non-null value is reachable at it. Needs the
|
|
579
|
-
* filter.contentPresent capability. POST /records/query only.
|
|
580
|
-
* See docs/spec/data-model.md § Filter.
|
|
581
|
-
*/
|
|
582
|
-
contentPresent?: string[];
|
|
583
|
-
search?: string;
|
|
584
|
-
includeDeleted?: boolean;
|
|
585
|
-
/**
|
|
586
|
-
* Unlisted records are excluded by default, like soft-deleted ones.
|
|
587
|
-
* Owner-only under `ScopedStack` — enumeration standing rests on nothing
|
|
588
|
-
* but ownership, so a grant or delegation never carries it. See
|
|
589
|
-
* docs/spec/unlisted.md.
|
|
590
|
-
*/
|
|
591
|
-
includeUnlisted?: boolean;
|
|
592
|
-
};
|
|
593
|
-
/**
|
|
594
|
-
* The Record columns every adapter stores natively, and can order by. The
|
|
595
|
-
* array is the source of truth — NativeSortField is derived from it so the
|
|
596
|
-
* runtime checks that narrow a wire value or a cursor to this set (see
|
|
597
|
-
* parseQuery(), normalizeCapabilities(), and the SQLite adapters' cursor
|
|
598
|
-
* decoding) can't drift from the type.
|
|
599
|
-
*/
|
|
600
|
-
export declare const NATIVE_SORT_FIELDS: readonly ["createdAt", "updatedAt", "version"];
|
|
601
|
-
export type NativeSortField = (typeof NATIVE_SORT_FIELDS)[number];
|
|
602
|
-
/**
|
|
603
|
-
* Order by a native column or by a top-level content field — two members
|
|
604
|
-
* rather than one widened `field`, because a content field named
|
|
605
|
-
* `version` would otherwise be indistinguishable from the native column.
|
|
606
|
-
* A `'content.'` prefix can't carry the distinction either: `.` is the
|
|
607
|
-
* path separator `parseContentFilterKey()` splits on.
|
|
608
|
-
* `direction` defaults to `asc` for any named sort, native or content, as
|
|
609
|
-
* `ORDER BY` does; a query with no sort is `createdAt`, newest first.
|
|
610
|
-
* See docs/spec/data-model.md § Sorting by a content field and
|
|
611
|
-
* § Sorting and pagination.
|
|
612
|
-
*/
|
|
613
|
-
export type QuerySort = {
|
|
614
|
-
field: NativeSortField;
|
|
615
|
-
contentField?: never;
|
|
616
|
-
direction?: 'asc' | 'desc';
|
|
617
|
-
} | {
|
|
618
|
-
field?: never;
|
|
619
|
-
contentField: string;
|
|
620
|
-
direction?: 'asc' | 'desc';
|
|
621
|
-
};
|
|
622
|
-
export type StackQuery = {
|
|
623
|
-
filter?: RecordFilter;
|
|
624
|
-
sort?: QuerySort;
|
|
625
|
-
limit?: number;
|
|
626
|
-
cursor?: string;
|
|
627
|
-
/**
|
|
628
|
-
* Records are returned exactly as stored by default ("stored"). Pass
|
|
629
|
-
* "latest" to apply the registered migration chain in memory before
|
|
630
|
-
* returning — never written back. Throws StackMigrationError if any
|
|
631
|
-
* matched record has no registered path to the latest version.
|
|
632
|
-
*/
|
|
633
|
-
presentAt?: 'stored' | 'latest';
|
|
634
|
-
};
|
|
635
|
-
/**
|
|
636
|
-
* A page of results and where the next one resumes. There is no count of
|
|
637
|
-
* the whole match: see docs/spec/data-model.md § Sorting and pagination.
|
|
638
|
-
*/
|
|
639
|
-
export type QueryResult = {
|
|
640
|
-
records: StackRecord[];
|
|
641
|
-
cursor: string | null;
|
|
642
|
-
};
|
|
643
|
-
export type MigrationFn = (content: Record<string, unknown>) => Record<string, unknown>;
|
|
644
|
-
export type Migration = {
|
|
645
|
-
from: TypeId;
|
|
646
|
-
to: TypeId;
|
|
647
|
-
migrate: MigrationFn;
|
|
648
|
-
};
|
|
649
|
-
/**
|
|
650
|
-
* How far into `content` a filter key may reach. The rungs nest —
|
|
651
|
-
* `'path'` is `'field'` plus traversal — so they are one ordered value
|
|
652
|
-
* rather than a pair of booleans that can spell a state no adapter can be
|
|
653
|
-
* in. A value a client does not recognize reads as `'none'`: refusing a
|
|
654
|
-
* query is recoverable, answering it with an unfiltered superset presented
|
|
655
|
-
* as a filtered result is not.
|
|
656
|
-
* See docs/spec/adapters.md § Adapter capabilities.
|
|
657
|
-
*/
|
|
658
|
-
export type ContentFilterReach =
|
|
659
|
-
/** No `filter.content` and no `filter.contentPresent` at all. */
|
|
660
|
-
'none'
|
|
661
|
-
/** Single-segment field names only (`'did'`). */
|
|
662
|
-
| 'field'
|
|
663
|
-
/** Multi-segment paths too (`'emails.value'`). */
|
|
664
|
-
| 'path';
|
|
665
|
-
/**
|
|
666
|
-
* What a Stack — and the adapter under it — honors, grouped by the query surface each entry gates:
|
|
667
|
-
* every flag under `filter`/`sort` is named for the query key it answers
|
|
668
|
-
* for, so the capability a query needs is derivable from the query rather
|
|
669
|
-
* than memorized. `limits` sits apart because a byte ceiling is not a
|
|
670
|
-
* feature to gate on but a number to pre-check against.
|
|
671
|
-
* See docs/spec/adapters.md § Adapter capabilities.
|
|
672
|
-
*/
|
|
673
|
-
export type StackCapabilities = {
|
|
674
|
-
filter: {
|
|
675
|
-
/**
|
|
676
|
-
* Required `'path'` for local/in-process adapters; a wire adapter may
|
|
677
|
-
* report a shallower rung, driven by the server's discovery response.
|
|
678
|
-
* Stack.query() throws StackBadRequestError rather than silently widening.
|
|
679
|
-
*/
|
|
680
|
-
content: ContentFilterReach;
|
|
681
|
-
/**
|
|
682
|
-
* Whether `filter.contentPresent` is honored. Beside the reach ladder
|
|
683
|
-
* rather than a rung on it: a server promising to match a content
|
|
684
|
-
* value has not thereby promised to answer whether one is there at
|
|
685
|
-
* all, and reading it as such hands a client the unfiltered superset
|
|
686
|
-
* that ignoring the filter produces. Meaningful only where `content`
|
|
687
|
-
* is not `'none'` — presence travels in the `POST /records/query`
|
|
688
|
-
* body, which a server reaching no content does not expose.
|
|
689
|
-
*/
|
|
690
|
-
contentPresent: boolean;
|
|
691
|
-
/**
|
|
692
|
-
* Whether `filter.search` is honored. Not a rung on the ladder: a
|
|
693
|
-
* full-text index is a different mechanism from field matching, and
|
|
694
|
-
* neither implies the other. Local adapters may decline it.
|
|
695
|
-
*/
|
|
696
|
-
search: boolean;
|
|
697
|
-
};
|
|
698
|
-
sort: {
|
|
699
|
-
/** Which native columns this adapter can order by; see NativeSortField. */
|
|
700
|
-
fields: NativeSortField[];
|
|
701
|
-
/**
|
|
702
|
-
* Whether `sort.contentField` is honored. A boolean rather than names
|
|
703
|
-
* in `fields`: content fields are app-defined and unbounded, and an
|
|
704
|
-
* adapter that indexes content for sorting indexes every top-level
|
|
705
|
-
* scalar, so there is nothing per-field left to declare. Independent
|
|
706
|
-
* of `filter.content` — a server may order by a content field without
|
|
707
|
-
* offering to filter on one, and filtering is a scan where ordering
|
|
708
|
-
* wants an index.
|
|
709
|
-
*/
|
|
710
|
-
contentField: boolean;
|
|
711
|
-
};
|
|
712
|
-
/**
|
|
713
|
-
* Ceilings a client can check before spending a request, never a
|
|
714
|
-
* substitute for the server's own limit, which stays authoritative.
|
|
715
|
-
* `null` means this client cannot pre-check, not that nothing is
|
|
716
|
-
* enforced. Local adapters declare `null` for both: nothing at the
|
|
717
|
-
* storage layer imposes a ceiling, and a caller with in-process access
|
|
718
|
-
* to the database can spend its own memory however it likes.
|
|
719
|
-
* See docs/spec/adapters.md § Adapter capabilities.
|
|
720
|
-
*/
|
|
721
|
-
limits: {
|
|
722
|
-
/** Maximum attachment upload size in bytes. */
|
|
723
|
-
attachmentBytes: number | null;
|
|
724
|
-
/**
|
|
725
|
-
* Maximum serialized size in bytes of a Record's content — a create
|
|
726
|
-
* body or a merge patch. Stack.create()/Stack.mutate() pre-check
|
|
727
|
-
* against it and throw StackPayloadTooLargeError before sending.
|
|
728
|
-
*/
|
|
729
|
-
contentBytes: number | null;
|
|
730
|
-
};
|
|
731
|
-
};
|
|
732
|
-
/**
|
|
733
|
-
* A capability a query can be refused for, as its path into
|
|
734
|
-
* StackCapabilities — the same name the spec and a discovery response
|
|
735
|
-
* use, so an error says which key to look at. `limits` never appears: a
|
|
736
|
-
* ceiling is not something a query can lack.
|
|
737
|
-
*/
|
|
738
|
-
export type MissingCapability = 'filter.content' | 'filter.contentPresent' | 'filter.search' | 'sort.fields' | 'sort.contentField';
|
|
739
|
-
/**
|
|
740
|
-
* Opt-in optimistic-concurrency precondition, accepted by every mutation
|
|
741
|
-
* that bumps a record's version. On mismatch the mutation throws
|
|
742
|
-
* StackVersionConflictError and changes nothing; omit to keep
|
|
743
|
-
* last-writer-wins. An adapter checks it atomically inside its write, never
|
|
744
|
-
* as a read-then-write. See docs/spec/versioning.md § Optimistic
|
|
745
|
-
* concurrency (`ifVersion`).
|
|
746
|
-
*/
|
|
747
|
-
export type IfVersionOptions = {
|
|
748
|
-
ifVersion?: number;
|
|
749
|
-
};
|
|
750
|
-
/**
|
|
751
|
-
* Accepted by every mutating StackRecordAdapter method. The adapter
|
|
752
|
-
* persists this prior-state snapshot as part of the SAME atomic write as
|
|
753
|
-
* the mutation, so a crash between the two can't leave an orphan versions
|
|
754
|
-
* row. Server-backed adapters (already atomic per-request) can ignore it.
|
|
755
|
-
*/
|
|
756
|
-
export type SnapshotOptions = {
|
|
757
|
-
snapshot?: RecordVersion;
|
|
758
|
-
};
|
|
759
|
-
/**
|
|
760
|
-
* Whether a mutateRecord() call advances `version`/`updatedAt` at all.
|
|
761
|
-
* `Stack` computes this from which aspects a change set actually moves — a
|
|
762
|
-
* change set touching only `associations`, `parentId` and/or `unlisted`
|
|
763
|
-
* doesn't bump, the same rule StackRecordAdapter.amendAssociations()
|
|
764
|
-
* follows unconditionally. Absent means `true`; every other mutating method
|
|
765
|
-
* bumps every time, so only mutateRecord() takes this. See
|
|
766
|
-
* docs/spec/versioning.md § Version history.
|
|
767
|
-
*/
|
|
768
|
-
export type BumpVersionOptions = {
|
|
769
|
-
bumpsVersion?: boolean;
|
|
770
|
-
};
|
|
771
|
-
/**
|
|
772
|
-
* Who is performing a mutation, stamped onto the record in the same write.
|
|
773
|
-
* `ScopedStack` supplies it from the request's identities; a caller of
|
|
774
|
-
* plain `Stack` supplies it only when reconstructing an attributed write.
|
|
775
|
-
* See docs/spec/data-model.md § Authorship and attribution.
|
|
776
|
-
*/
|
|
777
|
-
export type ActorOptions = {
|
|
778
|
-
actor?: Actor;
|
|
779
|
-
};
|
|
780
|
-
/**
|
|
781
|
-
* The part of a change that the record cannot report once the write has
|
|
782
|
-
* landed: which aspects moved, who moved them, and what an association
|
|
783
|
-
* mutation added, removed or overwrote. Everything else a journal entry
|
|
784
|
-
* carries — `seq`, `at`, `version`, `typeId`, `parentId` — the adapter
|
|
785
|
-
* stamps from the row it just wrote, so the two can never drift.
|
|
786
|
-
*
|
|
787
|
-
* That split is the whole argument for the tier: content's prior state is
|
|
788
|
-
* recoverable from a snapshot, and nothing else's is recoverable from
|
|
789
|
-
* anything but this. See docs/spec/journal.md.
|
|
790
|
-
*/
|
|
791
|
-
export type JournalEntryInput = {
|
|
792
|
-
ops: ChangeOp[];
|
|
793
|
-
kind: ChangeKind;
|
|
794
|
-
actor?: ChangeActor;
|
|
795
|
-
/** The container a move took the record out of, `null` for the root. */
|
|
796
|
-
previousParentId?: RecordId | null;
|
|
797
|
-
/**
|
|
798
|
-
* What an association mutation moved, one tagged edit per association.
|
|
799
|
-
* The journal's own shape, not the feed's two flat lists: a log whose
|
|
800
|
-
* whole argument is prior state carries `previous` beside the thing that
|
|
801
|
-
* displaced it, rather than leaving a consumer to re-derive which entry
|
|
802
|
-
* of one list overwrote which entry of another. See
|
|
803
|
-
* docs/spec/journal.md § The entry.
|
|
804
|
-
*/
|
|
805
|
-
associations?: AssociationChange[];
|
|
806
|
-
};
|
|
807
|
-
/**
|
|
808
|
-
* One durable entry in a record's change journal.
|
|
809
|
-
*
|
|
810
|
-
* Envelope-level by design — `content` lives on a RecordVersion, and
|
|
811
|
-
* duplicating it here would make the journal the larger of the two stores
|
|
812
|
-
* for no recovery anyone asked for.
|
|
813
|
-
* See docs/spec/journal.md § Ordering for why `seq` is the only ordering.
|
|
814
|
-
*/
|
|
815
|
-
export type RecordJournalEntry = JournalEntryInput & {
|
|
816
|
-
seq: number;
|
|
817
|
-
/** When the entry was appended — not the record's `updatedAt`, which an association change leaves alone. */
|
|
818
|
-
at: Date;
|
|
819
|
-
/**
|
|
820
|
-
* The version this change produced; unchanged from before on
|
|
821
|
-
* associate/dissociate, reparent, unlist and list.
|
|
822
|
-
*/
|
|
823
|
-
version: number;
|
|
824
|
-
typeId: TypeId;
|
|
825
|
-
/** Where the record sat after the change, absent for the root. */
|
|
826
|
-
parentId?: RecordId;
|
|
827
|
-
};
|
|
828
|
-
/**
|
|
829
|
-
* Accepted by every mutating StackRecordAdapter method, and by
|
|
830
|
-
* amendAssociations(), which takes no other options. The adapter
|
|
831
|
-
* appends the entry inside the SAME write as the mutation, so a crash
|
|
832
|
-
* between the two cannot leave a change unjournaled.
|
|
833
|
-
*
|
|
834
|
-
* Unlike SnapshotOptions there is no collision to heal: `seq` is
|
|
835
|
-
* allocated by the adapter inside that write rather than computed by
|
|
836
|
-
* `Stack` from a value it read earlier.
|
|
837
|
-
*/
|
|
838
|
-
export type JournalOptions = {
|
|
839
|
-
journal?: JournalEntryInput;
|
|
840
|
-
};
|
|
841
|
-
/** Window into a record's journal. Omitting both reads the whole log, oldest first. */
|
|
842
|
-
export type JournalQuery = {
|
|
843
|
-
/** Entries after this seq, exclusive. */
|
|
844
|
-
afterSeq?: number;
|
|
845
|
-
limit?: number;
|
|
846
|
-
};
|
|
847
|
-
/**
|
|
848
|
-
* Window into a record's version history. Newest first, the reverse of
|
|
849
|
-
* JournalQuery; omitting both reads every version.
|
|
850
|
-
* See docs/spec/versioning.md § Version history.
|
|
851
|
-
*/
|
|
852
|
-
export type VersionsQuery = {
|
|
853
|
-
/** Versions strictly older than this, exclusive. */
|
|
854
|
-
beforeVersion?: number;
|
|
855
|
-
limit?: number;
|
|
856
|
-
};
|
|
857
|
-
/**
|
|
858
|
-
* The coarse branch every subscriber makes, closed at four values. A
|
|
859
|
-
* handler covering exactly these is complete, not merely adequate:
|
|
860
|
-
* `changed` is an upsert signal carrying nine distinct verbs.
|
|
861
|
-
* See docs/spec/events.md § The event shape.
|
|
862
|
-
*/
|
|
863
|
-
export type ChangeKind = 'created' | 'changed' | 'removed' | 'purged';
|
|
864
|
-
/**
|
|
865
|
-
* The precise verb behind a ChangeKind, for consumers that distinguish a
|
|
866
|
-
* reshare from an edit. Each is named after the call that produced it; see
|
|
867
|
-
* docs/spec/events.md § The event shape for the three that aren't a method
|
|
868
|
-
* name. `associate`, `dissociate`, `reshare`, `reparent`, `unlist` and
|
|
869
|
-
* `list` don't bump; see docs/spec/versioning.md § Version history.
|
|
870
|
-
*/
|
|
871
|
-
export type ChangeOp = 'create' | 'patch' | 'associate' | 'dissociate' | 'reshare' | 'migrate' | 'restore' | 'delete' | 'undelete' | 'purge'
|
|
872
|
-
/**
|
|
873
|
-
* Emitted even though the record's post-change state (`unlistedAt` now
|
|
874
|
-
* set) would otherwise be excluded by the same filter it announces —
|
|
875
|
-
* subscribers who already know the record need telling to drop it. See
|
|
876
|
-
* docs/spec/events.md § The unlisted transition.
|
|
877
|
-
*/
|
|
878
|
-
| 'unlist'
|
|
879
|
-
/** The publish moment — mechanically an upsert, like `undelete`. */
|
|
880
|
-
| 'list'
|
|
881
|
-
/**
|
|
882
|
-
* A move between containers. Matched by a `parentId` filter naming
|
|
883
|
-
* *either* side of the move, so a subscriber watching the old container
|
|
884
|
-
* learns the record left it — the record's post-change state alone
|
|
885
|
-
* would answer only for the destination. See docs/spec/events.md
|
|
886
|
-
* § The reparent transition.
|
|
887
|
-
*/
|
|
888
|
-
| 'reparent';
|
|
889
|
-
/**
|
|
890
|
-
* Who performed a change — never who authored the record. Absent from a
|
|
891
|
-
* RecordChange entirely when unknown, which means a write by an unscoped
|
|
892
|
-
* `Stack`: absence is a fact of its own and never stands in for the
|
|
893
|
-
* author. See docs/spec/events.md § Attribution.
|
|
894
|
-
*/
|
|
895
|
-
export type ChangeActor = Actor & {
|
|
896
|
-
/** Self-reported at create, never a trust input. See AppId. */
|
|
897
|
-
appId?: AppId;
|
|
898
|
-
};
|
|
899
|
-
/**
|
|
900
|
-
* One change to one record. The envelope describes the change; the record
|
|
901
|
-
* describes the record, so nothing of the record's own provenance appears
|
|
902
|
-
* here — a consumer that wants it asks for `record`.
|
|
903
|
-
* See docs/spec/events.md § The event shape.
|
|
904
|
-
*/
|
|
905
|
-
export type RecordChange = {
|
|
906
|
-
kind: ChangeKind;
|
|
907
|
-
/**
|
|
908
|
-
* Every aspect this version moved, derived by diffing the record against
|
|
909
|
-
* its prior state rather than read off the request — a change set that
|
|
910
|
-
* names an aspect without moving it is not reported as moving it. Never
|
|
911
|
-
* empty; multi-entry only for a mutate() change set, since every other op
|
|
912
|
-
* names a whole-record transition and is emitted alone.
|
|
913
|
-
* See docs/spec/events.md § The event shape.
|
|
914
|
-
*/
|
|
915
|
-
ops: ChangeOp[];
|
|
916
|
-
recordId: RecordId;
|
|
917
|
-
/** As stored at the moment of the change. */
|
|
918
|
-
typeId: TypeId;
|
|
919
|
-
/**
|
|
920
|
-
* The version this change produced; on `purged`, the version destroyed.
|
|
921
|
-
* Unchanged from the record's prior version on every op that doesn't
|
|
922
|
-
* bump — see ChangeOp.
|
|
923
|
-
*/
|
|
924
|
-
version: number;
|
|
925
|
-
/**
|
|
926
|
-
* As persisted by this change; on `purged`, when the delete ran.
|
|
927
|
-
* Unchanged from the record's prior `updatedAt` on every op that
|
|
928
|
-
* doesn't bump.
|
|
929
|
-
*/
|
|
930
|
-
updatedAt: Date;
|
|
931
|
-
parentId?: RecordId;
|
|
932
|
-
actor?: ChangeActor;
|
|
933
|
-
/**
|
|
934
|
-
* Associations now present that weren't before — current annotation
|
|
935
|
-
* included, so a re-point appears here under its new
|
|
936
|
-
* `attachmentRecordId`. Present whenever `ops` includes `associate`, on
|
|
937
|
-
* the same "as of this change" convention as every other field here.
|
|
938
|
-
*/
|
|
939
|
-
associationsAdded?: DataAssociation[];
|
|
940
|
-
/**
|
|
941
|
-
* Associations no longer present, identity only — kind and label, plus
|
|
942
|
-
* `fileId` for an attachment — present whenever `ops` includes
|
|
943
|
-
* `dissociate`. An attachment's `attachmentRecordId` is never repeated
|
|
944
|
-
* here, the same way a `purged` frame never carries what it destroyed.
|
|
945
|
-
*/
|
|
946
|
-
associationsRemoved?: DataAssociation[];
|
|
947
|
-
/**
|
|
948
|
-
* The record as of this change — present only when asked for and
|
|
949
|
-
* available, never on `purged`. Shared with every other subscriber on
|
|
950
|
-
* this emission, so a handler that needs to alter it copies first.
|
|
951
|
-
*/
|
|
952
|
-
record?: StackRecord;
|
|
953
|
-
/**
|
|
954
|
-
* Resume cursor, minted by a server. Local changes carry none, this
|
|
955
|
-
* stack's own writes included — so a consumer holding a cursor keeps
|
|
956
|
-
* the last one that was present rather than the last change's.
|
|
957
|
-
*/
|
|
958
|
-
cursor?: string;
|
|
959
|
-
};
|
|
960
|
-
/**
|
|
961
|
-
* Applied by the emitter, exactly: a filtered subscription never receives
|
|
962
|
-
* an event outside its filter, so filtering again is redundant rather than
|
|
963
|
-
* defensive. Every key means what it means on `RecordFilter`, so one value
|
|
964
|
-
* can drive both `query()` and `subscribe()`. See docs/spec/events.md
|
|
965
|
-
* § Subscribing.
|
|
966
|
-
*/
|
|
967
|
-
export type ChangeFilter = Pick<RecordFilter, 'typeId' | 'baseId' | 'parentId' | 'createdBy'> & {
|
|
968
|
-
kinds?: ChangeKind[];
|
|
969
|
-
};
|
|
970
|
-
/** Ends a subscription. Safe to call more than once. */
|
|
971
|
-
export type Unsubscribe = () => void;
|
|
972
|
-
export type SubscribeOptions = {
|
|
973
|
-
filter?: ChangeFilter;
|
|
974
|
-
/** Ask the emitter to include `record`. Honored when it can; never assume it. */
|
|
975
|
-
includeRecords?: boolean;
|
|
976
|
-
/**
|
|
977
|
-
* Receive events for unlisted records too. Owner-only under
|
|
978
|
-
* `ScopedStack`, same authority as `RecordFilter.includeUnlisted` — the
|
|
979
|
-
* feed excludes unlisted records by default so it never delivers more
|
|
980
|
-
* than an equivalent `query()` would return. See
|
|
981
|
-
* docs/spec/unlisted.md.
|
|
982
|
-
*/
|
|
983
|
-
includeUnlisted?: boolean;
|
|
984
|
-
/**
|
|
985
|
-
* Resume from this cursor rather than the present — the last `cursor`
|
|
986
|
-
* that was present on a delivered `RecordChange`. A relaying stack delivers
|
|
987
|
-
* its own local writes through the same handler and those carry none, so
|
|
988
|
-
* a consumer that stores every change's `cursor` unconditionally erases its
|
|
989
|
-
* own cursor on its next write.
|
|
990
|
-
*
|
|
991
|
-
* Forwarded to the adapter as `SubscribeChangesOptions.since`, so it
|
|
992
|
-
* only means something where a relay exists: a stack with none has no
|
|
993
|
-
* third-party writes to have missed, and therefore no cursor it could
|
|
994
|
-
* ever have minted. Passing `since` there throws `StackBadRequestError`
|
|
995
|
-
* rather than silently starting from the present, which would let the
|
|
996
|
-
* caller believe it resumed when it did not. A cursor outside the
|
|
997
|
-
* framable charset is refused the same way, so a malformed one reports
|
|
998
|
-
* identically whatever adapter is underneath. See
|
|
999
|
-
* docs/spec/events.md § Subscribing.
|
|
1000
|
-
*/
|
|
1001
|
-
since?: string;
|
|
1002
|
-
/**
|
|
1003
|
-
* Where a throwing handler's error goes. Without one the error is
|
|
1004
|
-
* rethrown asynchronously rather than swallowed; either way it never
|
|
1005
|
-
* reaches the caller of the mutation that produced the event.
|
|
1006
|
-
*/
|
|
1007
|
-
onError?: (err: unknown) => void;
|
|
1008
|
-
/**
|
|
1009
|
-
* A gap opened that resumption could not close: reconcile by query.
|
|
1010
|
-
* Never fires on a local stack, which has no gap to open. Can fire on
|
|
1011
|
-
* the very first connection when `since` names a cursor the far end
|
|
1012
|
-
* will not honor — that is a gap too, and the one an app most needs to
|
|
1013
|
-
* hear about.
|
|
1014
|
-
*/
|
|
1015
|
-
onReset?: () => void;
|
|
1016
|
-
};
|
|
1017
|
-
/**
|
|
1018
|
-
* What a relay is asked for. The subscriber's options minus the ones only
|
|
1019
|
-
* a local emitter answers: a relay reports changes it is told about and
|
|
1020
|
-
* decides nothing, so there is no handler of its own to route errors from.
|
|
1021
|
-
* `onError` here is the relay's own trouble — a connection it could not
|
|
1022
|
-
* restore — and `onReset` the gap that leaves.
|
|
1023
|
-
* See docs/spec/events.md § Where events come from.
|
|
1024
|
-
*/
|
|
1025
|
-
export type SubscribeChangesOptions = {
|
|
1026
|
-
filter?: ChangeFilter;
|
|
1027
|
-
/** Resume from this cursor. A relay with none starts from the present. */
|
|
1028
|
-
since?: string;
|
|
1029
|
-
includeRecords?: boolean;
|
|
1030
|
-
/** See SubscribeOptions.includeUnlisted. */
|
|
1031
|
-
includeUnlisted?: boolean;
|
|
1032
|
-
onError?: (err: unknown) => void;
|
|
1033
|
-
onReset?: () => void;
|
|
1034
|
-
};
|
|
1035
|
-
/**
|
|
1036
|
-
* The record-storage half of an adapter: structured data, queries,
|
|
1037
|
-
* associations, versioning, type definitions, and stack identity.
|
|
1038
|
-
*/
|
|
1039
|
-
export interface StackRecordAdapter {
|
|
1040
|
-
readonly capabilities: StackCapabilities;
|
|
1041
|
-
/** DID of the stack owner. Set during adapter initialization. */
|
|
1042
|
-
readonly ownerEntityId: EntityId;
|
|
1043
|
-
/**
|
|
1044
|
-
* IANA timezone string for this stack, or undefined if never set.
|
|
1045
|
-
* Passthrough app metadata with no default — see docs/spec.md § The
|
|
1046
|
-
* `_config` record.
|
|
1047
|
-
*/
|
|
1048
|
-
readonly timezone: string | undefined;
|
|
1049
|
-
/**
|
|
1050
|
-
* Throws StackConflictError if `record.id` already exists — never a
|
|
1051
|
-
* silent overwrite. The check must be atomic with the write (a PK/unique
|
|
1052
|
-
* constraint or equivalent); Stack itself doesn't pre-check, so a raw
|
|
1053
|
-
* adapter that skips this enforces nothing.
|
|
1054
|
-
*/
|
|
1055
|
-
createRecord(record: StackRecord, opts?: JournalOptions): Promise<StackRecord>;
|
|
1056
|
-
getRecord(id: RecordId): Promise<StackRecord | null>;
|
|
1057
|
-
/**
|
|
1058
|
-
* Apply a change set — any combination of content patch, `parentId`,
|
|
1059
|
-
* `permissions`, `associations` and `unlisted` — in one write. It is the
|
|
1060
|
-
* only multi-aspect atomic write a record has: a publish is one act, so
|
|
1061
|
-
* separate per-aspect methods would leave it able to half-land.
|
|
1062
|
-
*
|
|
1063
|
-
* The content patch merges at the top level only — each key it names is
|
|
1064
|
-
* replaced whole. Never touches `typeId`; a type change goes through
|
|
1065
|
-
* commitMigration() instead. `associations` replaces the stored set,
|
|
1066
|
-
* where amendAssociations() amends it.
|
|
1067
|
-
*
|
|
1068
|
-
* `opts.bumpsVersion` says whether this call advances `version`/
|
|
1069
|
-
* `updatedAt` and stores the snapshot — `false` for a change set that
|
|
1070
|
-
* touches only association sets, `permissions` among them, matching
|
|
1071
|
-
* amendAssociations() below, which never bumps. `Stack` computes it; an adapter never has to infer it
|
|
1072
|
-
* from the change set's own keys.
|
|
1073
|
-
*
|
|
1074
|
-
* `Stack` owns everything above storage: validation, the acyclicity
|
|
1075
|
-
* walk, the per-key gates, and deciding there is anything to write at
|
|
1076
|
-
* all — an adapter is never handed a change set that changes nothing.
|
|
1077
|
-
* See docs/spec/data-model.md § Mutations and docs/spec/versioning.md
|
|
1078
|
-
* § Version history.
|
|
1079
|
-
*/
|
|
1080
|
-
mutateRecord(id: RecordId, changes: RecordChangeSet, opts?: IfVersionOptions & SnapshotOptions & BumpVersionOptions & ActorOptions & JournalOptions): Promise<StackRecord>;
|
|
1081
|
-
/**
|
|
1082
|
-
* Returns the record this call acted on: as it now stands after a soft
|
|
1083
|
-
* delete, and as it stood immediately before destruction after a
|
|
1084
|
-
* purge — captured inside the same write, so nothing can observe or alter
|
|
1085
|
-
* it in between. Null when there was no record to delete, which is the
|
|
1086
|
-
* only case that mutates nothing.
|
|
1087
|
-
*/
|
|
1088
|
-
deleteRecord(id: RecordId, opts?: {
|
|
1089
|
-
purge?: boolean;
|
|
1090
|
-
} & IfVersionOptions & SnapshotOptions & ActorOptions & JournalOptions): Promise<StackRecord | null>;
|
|
1091
|
-
/** Reverse a soft delete. Returns the record as it now stands. */
|
|
1092
|
-
undeleteRecord(id: RecordId, opts?: IfVersionOptions & SnapshotOptions & ActorOptions & JournalOptions): Promise<StackRecord>;
|
|
1093
|
-
/**
|
|
1094
|
-
* `query.sort`, when present, always carries a `direction`: `Stack`
|
|
1095
|
-
* resolves the defaults before any adapter sees the query.
|
|
1096
|
-
*/
|
|
1097
|
-
queryRecords(query: StackQuery): Promise<QueryResult>;
|
|
1098
|
-
/**
|
|
1099
|
-
* Apply a list of adds and removes as one write, all or none, removes
|
|
1100
|
-
* before adds. Never bumps `version`/`updatedAt` and never snapshots — a
|
|
1101
|
-
* set-add composes regardless of write order. A list mixing authority
|
|
1102
|
-
* and data elements is refused.
|
|
1103
|
-
* See docs/spec/adapters.md § Amending associations.
|
|
1104
|
-
*/
|
|
1105
|
-
amendAssociations(id: RecordId, changes: AssociationEdit[], opts?: JournalOptions): Promise<StackRecord>;
|
|
1106
|
-
/**
|
|
1107
|
-
* Snapshots newest first; omitting `query` reads every version.
|
|
1108
|
-
* See docs/spec/versioning.md § Version history.
|
|
1109
|
-
*/
|
|
1110
|
-
getVersions(id: RecordId, query?: VersionsQuery): Promise<RecordVersion[]>;
|
|
1111
|
-
getVersion(id: RecordId, version: number): Promise<RecordVersion | null>;
|
|
1112
|
-
/**
|
|
1113
|
-
* Standalone snapshot write, outside of a mutation's own atomic path.
|
|
1114
|
-
* Mutating methods above take a `snapshot` option instead, so the
|
|
1115
|
-
* snapshot and the mutation land in one write — see SnapshotOptions.
|
|
1116
|
-
*/
|
|
1117
|
-
saveVersion(id: RecordId, version: RecordVersion): Promise<void>;
|
|
1118
|
-
/**
|
|
1119
|
-
* Read a record's change journal, oldest first — required, on the same
|
|
1120
|
-
* footing as getVersions(). A recovery mechanism an app cannot rely on is
|
|
1121
|
-
* most of the way to no mechanism at all, so an adapter with no journal
|
|
1122
|
-
* refuses the call rather than declining to have the method.
|
|
1123
|
-
* See docs/spec/journal.md § Reading it.
|
|
1124
|
-
*/
|
|
1125
|
-
getJournal(id: RecordId, query?: JournalQuery): Promise<RecordJournalEntry[]>;
|
|
1126
|
-
/**
|
|
1127
|
-
* Restore a record to a previous version's `content` and `typeId` —
|
|
1128
|
-
* everything a snapshot carries. Containment, listing and associations
|
|
1129
|
-
* are left where they stand, there being nothing to restore them *from*.
|
|
1130
|
-
* Bumps version internally; throws StackNotFoundError if the version
|
|
1131
|
-
* doesn't exist.
|
|
1132
|
-
*/
|
|
1133
|
-
restoreVersion(id: RecordId, version: number, opts?: IfVersionOptions & SnapshotOptions & ActorOptions & JournalOptions): Promise<StackRecord>;
|
|
1134
|
-
/**
|
|
1135
|
-
* Commit a migration: write new content under a new typeId in one step.
|
|
1136
|
-
* This is the only way a record's typeId changes after creation — used by
|
|
1137
|
-
* Stack.commitMigration() and Stack.migrateAll(); Stack.mutate() never
|
|
1138
|
-
* changes typeId as a side effect. Bumps version internally.
|
|
1139
|
-
*/
|
|
1140
|
-
commitMigration(id: RecordId, toTypeId: TypeId, content: Record<string, unknown>, opts?: IfVersionOptions & SnapshotOptions & ActorOptions & JournalOptions): Promise<StackRecord>;
|
|
1141
|
-
saveType(type: StackType): Promise<void>;
|
|
1142
|
-
getType(id: TypeId): Promise<StackType | null>;
|
|
1143
|
-
listTypes(): Promise<StackType[]>;
|
|
1144
|
-
/**
|
|
1145
|
-
* Atomically verify fileId is unreferenced, then purge its
|
|
1146
|
-
* metadata records in the same adapter call, returning the deleted records.
|
|
1147
|
-
* Throws StackConflictError if still referenced. Optional —
|
|
1148
|
-
* Stack.deleteAttachment() has a non-atomic fallback. See
|
|
1149
|
-
* docs/spec/attachments.md § Deleting attachments.
|
|
1150
|
-
*
|
|
1151
|
-
* `metadataTypeIds` is the resolved `_attachment` family, passed as
|
|
1152
|
-
* concrete typeIds so an adapter never needs a baseId concept of its
|
|
1153
|
-
* own — the same split Stack.query() makes for `filter.baseId`.
|
|
1154
|
-
*/
|
|
1155
|
-
deleteUnreferencedAttachmentRecords?(fileId: FileId, metadataTypeIds: TypeId[]): Promise<StackRecord[]>;
|
|
1156
|
-
/**
|
|
1157
|
-
* Relay changes that originated elsewhere — the inverse direction from
|
|
1158
|
-
* `Stack`, which emits every change made through it. Optional, and
|
|
1159
|
-
* absent on every local adapter: exactly one process owns a stack's
|
|
1160
|
-
* storage, so locally there is no third party whose writes could have
|
|
1161
|
-
* been missed. See docs/spec/events.md § Where events come from.
|
|
1162
|
-
*/
|
|
1163
|
-
subscribeChanges?(opts: SubscribeChangesOptions, handler: (change: RecordChange) => void): Promise<Unsubscribe>;
|
|
1164
|
-
flush?(): Promise<void>;
|
|
1165
|
-
close?(): Promise<void>;
|
|
1166
|
-
}
|
|
1167
|
-
/** One stored blob, as reported by StackBlobAdapter.listBlobs(). */
|
|
1168
|
-
export type BlobInfo = {
|
|
1169
|
-
fileId: FileId;
|
|
1170
|
-
size: number;
|
|
1171
|
-
/** When the blob was written. Used to apply a GC grace period to fresh, not-yet-associated uploads. */
|
|
1172
|
-
modifiedAt: Date;
|
|
1173
|
-
};
|
|
1174
|
-
/**
|
|
1175
|
-
* The blob-storage half of an adapter. Handles raw binary data only;
|
|
1176
|
-
* attachment metadata lives on _attachment@1 records in the record adapter.
|
|
1177
|
-
*/
|
|
1178
|
-
export interface StackBlobAdapter {
|
|
1179
|
-
putBlob(data: Uint8Array): Promise<FileId>;
|
|
1180
|
-
/**
|
|
1181
|
-
* Returns a plain `Uint8Array` (never a subclass such as `Buffer`) that the
|
|
1182
|
-
* caller owns: changing it never changes the stored bytes.
|
|
1183
|
-
*/
|
|
1184
|
-
getBlob(fileId: FileId): Promise<Uint8Array>;
|
|
1185
|
-
deleteBlob(fileId: FileId): Promise<void>;
|
|
1186
|
-
/**
|
|
1187
|
-
* Enumerate every blob currently in storage. Optional — without it,
|
|
1188
|
-
* garbage collection can't find bare-bytes orphans (bytes with no
|
|
1189
|
-
* metadata record at all). See docs/spec/attachments.md § Garbage
|
|
1190
|
-
* collection.
|
|
1191
|
-
*/
|
|
1192
|
-
listBlobs?(): Promise<BlobInfo[]>;
|
|
1193
|
-
flush?(): Promise<void>;
|
|
1194
|
-
close?(): Promise<void>;
|
|
1195
|
-
}
|
|
1196
|
-
/**
|
|
1197
|
-
* A complete adapter: record storage and blob storage combined.
|
|
1198
|
-
* Pass this to Stack.open(). Build one with combineAdapters() when you
|
|
1199
|
-
* want different backends for records and blobs (e.g. SQLite + S3).
|
|
1200
|
-
*/
|
|
1201
|
-
export type StackAdapter = StackRecordAdapter & StackBlobAdapter & {
|
|
1202
|
-
/**
|
|
1203
|
-
* Store bytes and create the accompanying _attachment@1 record as one
|
|
1204
|
-
* atomic operation. Optional; implement only when bytes and records
|
|
1205
|
-
* live behind a single boundary (today: APIAdapter alone), and never
|
|
1206
|
-
* synthesized by combineAdapters(). A security boundary, not an
|
|
1207
|
-
* efficiency shortcut — see docs/spec/adapters.md § Interface split.
|
|
1208
|
-
*/
|
|
1209
|
-
putAttachmentWithMetadata?(data: Uint8Array, opts: PutAttachmentOptions): Promise<StackRecord>;
|
|
1210
|
-
};
|
|
1211
|
-
/**
|
|
1212
|
-
* The two identities a token establishes — an Actor whose `principalId` is
|
|
1213
|
-
* always populated, equal to `subjectId` on an undelegated token, so a
|
|
1214
|
-
* server reading one never has to default it. Passes to `Stack.asActor()`
|
|
1215
|
-
* as is. See docs/spec/access-control.md § Delegation: principal and subject.
|
|
1216
|
-
*/
|
|
1217
|
-
export type TokenSession = Actor & {
|
|
1218
|
-
principalId: EntityId;
|
|
1219
|
-
};
|
|
1220
|
-
export type TokenInfo = TokenSession & {
|
|
1221
|
-
id: string;
|
|
1222
|
-
label?: string;
|
|
1223
|
-
createdAt: Date;
|
|
1224
|
-
expiresAt?: Date;
|
|
1225
|
-
};
|
|
1226
|
-
/**
|
|
1227
|
-
* Bearer-token issuance and lookup for server implementations — a
|
|
1228
|
-
* standalone interface, not a slot on StackAdapter. createToken() trusts
|
|
1229
|
-
* its caller: DID verification happens first, via the challenge-response
|
|
1230
|
-
* handshake. Tokens SHOULD be stored outside the portable stack file.
|
|
1231
|
-
* See docs/spec/wire-format.md § Authentication.
|
|
1232
|
-
*
|
|
1233
|
-
* The actor's `subjectId`, where it differs from `principalId`, is the
|
|
1234
|
-
* delegation binding, and no handshake can establish it — proving key
|
|
1235
|
-
* possession proves the principal and nothing about whom it may act for. It is asserted by the owner out of band, which is safe
|
|
1236
|
-
* because effective authority is the intersection of both parties' grants.
|
|
1237
|
-
*/
|
|
1238
|
-
export interface StackTokenStore {
|
|
1239
|
-
createToken(actor: Actor, opts?: {
|
|
1240
|
-
label?: string;
|
|
1241
|
-
expiresAt?: Date;
|
|
1242
|
-
}): Promise<{
|
|
1243
|
-
id: string;
|
|
1244
|
-
token: string;
|
|
1245
|
-
}>;
|
|
1246
|
-
lookupToken(token: string): Promise<TokenSession | null>;
|
|
1247
|
-
listTokens(): Promise<TokenInfo[]>;
|
|
1248
|
-
revokeToken(id: string): Promise<void>;
|
|
1249
|
-
}
|
|
1250
|
-
//# sourceMappingURL=types.d.ts.map
|