@haverstack/core 0.43.0 → 0.45.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 +1 -2
- package/dist/access.d.ts +7 -3
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +11 -2
- package/dist/access.js.map +1 -1
- package/dist/adapter/blobs.d.ts +18 -0
- package/dist/adapter/blobs.d.ts.map +1 -0
- package/dist/adapter/blobs.js +27 -0
- package/dist/adapter/blobs.js.map +1 -0
- package/dist/adapter/combine.d.ts.map +1 -1
- package/dist/adapter/combine.js +15 -8
- package/dist/adapter/combine.js.map +1 -1
- package/dist/adapter/copy.d.ts +31 -0
- package/dist/adapter/copy.d.ts.map +1 -0
- package/dist/adapter/copy.js +131 -0
- package/dist/adapter/copy.js.map +1 -0
- package/dist/adapter/head.d.ts +38 -0
- package/dist/adapter/head.d.ts.map +1 -0
- package/dist/adapter/head.js +85 -0
- package/dist/adapter/head.js.map +1 -0
- package/dist/adapter/index.d.ts +9 -2
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +6 -1
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/seed.d.ts +13 -0
- package/dist/adapter/seed.d.ts.map +1 -0
- package/dist/adapter/seed.js +26 -0
- package/dist/adapter/seed.js.map +1 -0
- package/dist/errors.d.ts +18 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +28 -6
- package/dist/errors.js.map +1 -1
- package/dist/grants.d.ts +16 -4
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +44 -16
- package/dist/grants.js.map +1 -1
- package/dist/hash.d.ts +8 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +14 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +29 -5
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +69 -44
- package/dist/install.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -5
- package/dist/schema.js.map +1 -1
- package/dist/scoped-stack/authority.d.ts +19 -14
- package/dist/scoped-stack/authority.d.ts.map +1 -1
- package/dist/scoped-stack/authority.js +30 -18
- package/dist/scoped-stack/authority.js.map +1 -1
- package/dist/scoped-stack/family-policy.js +1 -1
- package/dist/scoped-stack/family-policy.js.map +1 -1
- package/dist/scoped-stack/scoped-stack.d.ts +12 -5
- package/dist/scoped-stack/scoped-stack.d.ts.map +1 -1
- package/dist/scoped-stack/scoped-stack.js +52 -29
- package/dist/scoped-stack/scoped-stack.js.map +1 -1
- package/dist/stack/field-rules.d.ts +27 -0
- package/dist/stack/field-rules.d.ts.map +1 -0
- package/dist/stack/field-rules.js +50 -0
- package/dist/stack/field-rules.js.map +1 -0
- package/dist/stack/install-app.d.ts +2 -2
- package/dist/stack/install-app.d.ts.map +1 -1
- package/dist/stack/install-app.js +9 -9
- package/dist/stack/install-app.js.map +1 -1
- package/dist/stack/integrity.d.ts +9 -53
- package/dist/stack/integrity.d.ts.map +1 -1
- package/dist/stack/integrity.js +45 -105
- package/dist/stack/integrity.js.map +1 -1
- package/dist/stack/stack.d.ts +10 -11
- package/dist/stack/stack.d.ts.map +1 -1
- package/dist/stack/stack.js +35 -71
- package/dist/stack/stack.js.map +1 -1
- package/dist/stack/system-types.d.ts.map +1 -1
- package/dist/stack/system-types.js +1 -3
- package/dist/stack/system-types.js.map +1 -1
- package/dist/stack/type-grants.d.ts.map +1 -1
- package/dist/stack/type-grants.js +5 -2
- package/dist/stack/type-grants.js.map +1 -1
- package/dist/testing.d.ts +18 -17
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +43 -41
- package/dist/testing.js.map +1 -1
- package/dist/types/adapter.d.ts +71 -15
- package/dist/types/adapter.d.ts.map +1 -1
- package/dist/types/system.d.ts +1 -7
- package/dist/types/system.d.ts.map +1 -1
- package/dist/types/system.js.map +1 -1
- package/dist/validate.d.ts +2 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +2 -2
- package/dist/validate.js.map +1 -1
- package/dist/wire/index.d.ts +1 -1
- package/dist/wire/index.d.ts.map +1 -1
- package/dist/wire/index.js +1 -1
- package/dist/wire/index.js.map +1 -1
- package/dist/wire/request.d.ts +8 -1
- package/dist/wire/request.d.ts.map +1 -1
- package/dist/wire/request.js +20 -0
- package/dist/wire/request.js.map +1 -1
- package/package.json +1 -1
- package/dist/stack/identity-bindings.d.ts +0 -13
- package/dist/stack/identity-bindings.d.ts.map +0 -1
- package/dist/stack/identity-bindings.js +0 -36
- package/dist/stack/identity-bindings.js.map +0 -1
package/dist/stack/integrity.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Write invariants
|
|
3
3
|
* -------------------------------------------------------
|
|
4
|
-
* The integrity rules a Stack write owes whoever makes it —
|
|
5
|
-
* bindings, containment, attachment metadata
|
|
4
|
+
* The integrity rules a Stack write owes whoever makes it — immutable
|
|
5
|
+
* fields, DID and appId bindings, containment, attachment metadata and a
|
|
6
6
|
* group's admin roster. They bind every requester, the stack owner
|
|
7
7
|
* included, which is why they live beneath `ScopedStack`'s permission
|
|
8
8
|
* gates rather than among them. Each reads unscoped: through the Stack it
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { hasGroupAdmin, isGroupRecord } from '../access.js';
|
|
12
12
|
import { ARGUMENTS_INVALID, StackConflictError, StackValidationError } from '../errors.js';
|
|
13
|
-
import {
|
|
13
|
+
import { bindingsOf, immutableFieldsOf, isUnset } from './field-rules.js';
|
|
14
14
|
import { filtersContent } from '../query-validation.js';
|
|
15
15
|
import { associationIdentical } from '../associations/identity.js';
|
|
16
16
|
import { validateRecordId } from './record-id.js';
|
|
@@ -18,63 +18,59 @@ import { baseIdOf } from '../schema.js';
|
|
|
18
18
|
import { findFirstMatch } from './reads.js';
|
|
19
19
|
import { SYSTEM_TYPES } from '../types/index.js';
|
|
20
20
|
// -------------------------------------------------------
|
|
21
|
-
//
|
|
21
|
+
// Content writes
|
|
22
22
|
// -------------------------------------------------------
|
|
23
|
-
/** Uniqueness for every unique binding field a newly created card claims. */
|
|
24
|
-
export async function checkBindingsOnCreate(stack, typeId, content) {
|
|
25
|
-
const family = baseIdOf(typeId);
|
|
26
|
-
for (const field of uniqueBindingFieldsOf(family)) {
|
|
27
|
-
await checkBindingUnique(stack, family, field, content[field]);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
23
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
24
|
+
* Every content integrity check create, patch, restore and migrate owe: a
|
|
25
|
+
* change, judged against `prior` (absent on create), then claims, judged
|
|
26
|
+
* against other records. A claim is asked only of a value not already held
|
|
27
|
+
* in the destination family, so a claim check never finds the record itself.
|
|
28
|
+
* See docs/spec/data-model.md § Immutable fields.
|
|
35
29
|
*/
|
|
36
|
-
export async function
|
|
30
|
+
export async function checkContentWrite(stack, typeId, content, prior) {
|
|
31
|
+
if (prior)
|
|
32
|
+
checkImmutableFields(prior, content);
|
|
37
33
|
const family = baseIdOf(typeId);
|
|
38
|
-
const
|
|
39
|
-
for (const field of
|
|
40
|
-
if (!
|
|
34
|
+
const held = prior && baseIdOf(prior.typeId) === family ? prior.content : {};
|
|
35
|
+
for (const { field, unique } of bindingsOf(family)) {
|
|
36
|
+
if (!unique || content[field] === held[field])
|
|
41
37
|
continue;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
await checkBindingUnique(stack, family, field, content[field]);
|
|
39
|
+
}
|
|
40
|
+
if (family === SYSTEM_TYPES.ATTACHMENT &&
|
|
41
|
+
(content.fileId !== held.fileId || content.mimeType !== held.mimeType)) {
|
|
42
|
+
await checkAttachmentMimeType(stack, content);
|
|
46
43
|
}
|
|
47
44
|
}
|
|
45
|
+
// -------------------------------------------------------
|
|
46
|
+
// Immutable fields
|
|
47
|
+
// -------------------------------------------------------
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* uniqueness, of the destination only. See docs/spec/identity.md § DID bindings.
|
|
49
|
+
* Refuse a write that moves or clears an immutable field the record holds.
|
|
50
|
+
* Only the family the record is in now is asked: a field of the family it
|
|
51
|
+
* enters was never held, and arriving with one is a claim, not a change.
|
|
53
52
|
*/
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
checked.add(field);
|
|
63
|
-
checkBindingImmutable(family, field, existing[field], content[field]);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
for (const field of uniqueBindingFieldsOf(toFamily)) {
|
|
67
|
-
await checkBindingUnique(stack, toFamily, field, content[field], id);
|
|
53
|
+
function checkImmutableFields(existing, next) {
|
|
54
|
+
const family = baseIdOf(existing.typeId);
|
|
55
|
+
const content = existing.content;
|
|
56
|
+
for (const field of immutableFieldsOf(family)) {
|
|
57
|
+
const held = content[field];
|
|
58
|
+
if (isUnset(held) || next[field] === held)
|
|
59
|
+
continue;
|
|
60
|
+
throw new StackConflictError(`Cannot change ${family}.${field}: it is immutable once set.`);
|
|
68
61
|
}
|
|
69
62
|
}
|
|
63
|
+
// -------------------------------------------------------
|
|
64
|
+
// Claims on stored values
|
|
65
|
+
// -------------------------------------------------------
|
|
70
66
|
/**
|
|
71
67
|
* Refuse a second card claiming a value an Actor is resolved by. A
|
|
72
68
|
* property of the set rather than the value, so no schema can say it.
|
|
73
69
|
* Read-then-write: two racing creates can both pass.
|
|
74
70
|
* See docs/spec/identity.md § DID bindings.
|
|
75
71
|
*/
|
|
76
|
-
async function checkBindingUnique(stack, family, field, value
|
|
77
|
-
if (
|
|
72
|
+
async function checkBindingUnique(stack, family, field, value) {
|
|
73
|
+
if (isUnset(value))
|
|
78
74
|
return;
|
|
79
75
|
const clash = await findFirstMatch((q) => stack.query(q), {
|
|
80
76
|
filter: {
|
|
@@ -83,29 +79,11 @@ async function checkBindingUnique(stack, family, field, value, excludeId) {
|
|
|
83
79
|
includeUnlisted: true,
|
|
84
80
|
...(filtersContent(stack.capabilities) && { content: { [field]: value } }),
|
|
85
81
|
},
|
|
86
|
-
}, (r) => r.
|
|
82
|
+
}, (r) => r.content[field] === value);
|
|
87
83
|
if (clash) {
|
|
88
84
|
throw new StackConflictError(`Another ${family} record already claims the ${field} "${value}"`);
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
|
-
/**
|
|
92
|
-
* A binding is permanent once made: uniqueness stops a second card claiming
|
|
93
|
-
* a value, but only immutability stops an existing card being moved onto
|
|
94
|
-
* one. A subject whose key changes gets a new card.
|
|
95
|
-
* See docs/spec/identity.md § DID bindings.
|
|
96
|
-
*/
|
|
97
|
-
export function checkBindingImmutable(family, field, existing, next) {
|
|
98
|
-
if (typeof existing !== 'string' || existing === '')
|
|
99
|
-
return;
|
|
100
|
-
if (next === existing)
|
|
101
|
-
return;
|
|
102
|
-
throw new StackValidationError([
|
|
103
|
-
{
|
|
104
|
-
path: field,
|
|
105
|
-
message: `${field} is immutable once set; register a new ${family} record instead`,
|
|
106
|
-
},
|
|
107
|
-
]);
|
|
108
|
-
}
|
|
109
87
|
// -------------------------------------------------------
|
|
110
88
|
// Containment
|
|
111
89
|
// -------------------------------------------------------
|
|
@@ -154,23 +132,14 @@ export async function assertNoParentCycle(read, id, parentId) {
|
|
|
154
132
|
// -------------------------------------------------------
|
|
155
133
|
// Attachments
|
|
156
134
|
// -------------------------------------------------------
|
|
157
|
-
/**
|
|
158
|
-
* The `_attachment@1` fields a write may not move, each with the message it
|
|
159
|
-
* is refused by. Ordered as reported. See docs/spec/attachments.md § The
|
|
160
|
-
* `_attachment` record type.
|
|
161
|
-
*/
|
|
162
|
-
const ATTACHMENT_IMMUTABLE_FIELDS = [
|
|
163
|
-
['mimeType', 'mimeType is immutable after creation; delete and re-upload to change it'],
|
|
164
|
-
['fileId', 'fileId is immutable'],
|
|
165
|
-
['size', 'size is immutable'],
|
|
166
|
-
];
|
|
167
135
|
/**
|
|
168
136
|
* mimeType belongs to the fileId: its first metadata record fixes it, and
|
|
169
|
-
* a conflicting later one is refused
|
|
137
|
+
* a conflicting later one is refused — a clash with stored state, as a
|
|
138
|
+
* binding's second claimant is. Best-effort against a racing first
|
|
170
139
|
* upload; what survives the race is a deterministic winner. See
|
|
171
140
|
* docs/spec/attachments.md § The `_attachment` record type.
|
|
172
141
|
*/
|
|
173
|
-
|
|
142
|
+
async function checkAttachmentMimeType(stack, content) {
|
|
174
143
|
const { fileId, mimeType } = content;
|
|
175
144
|
if (typeof fileId !== 'string')
|
|
176
145
|
return; // schema validation already rejected this
|
|
@@ -182,12 +151,7 @@ export async function checkAttachmentMimeTypeOnCreate(stack, content) {
|
|
|
182
151
|
// Deliberately does not name the established mimeType — that would
|
|
183
152
|
// confirm a guessed fileId's content type. See the anti-oracle rule
|
|
184
153
|
// in docs/spec/attachments.md.
|
|
185
|
-
throw new
|
|
186
|
-
{
|
|
187
|
-
path: 'mimeType',
|
|
188
|
-
message: 'mimeType conflicts with the mimeType already established for this fileId',
|
|
189
|
-
},
|
|
190
|
-
]);
|
|
154
|
+
throw new StackConflictError('mimeType conflicts with the mimeType already established for this fileId');
|
|
191
155
|
}
|
|
192
156
|
}
|
|
193
157
|
/**
|
|
@@ -224,33 +188,9 @@ export async function checkAttachmentAssociationPointers(read, associations, sto
|
|
|
224
188
|
], ARGUMENTS_INVALID);
|
|
225
189
|
});
|
|
226
190
|
}
|
|
227
|
-
/**
|
|
228
|
-
* Refuse a write that moves an `_attachment@1` record's fileId, size or
|
|
229
|
-
* mimeType. `violates` decides what counts as a move, since a patch names
|
|
230
|
-
* only what it changes while a migration re-sends all three.
|
|
231
|
-
* See docs/spec/attachments.md § The `_attachment` record type.
|
|
232
|
-
*/
|
|
233
|
-
export function assertAttachmentImmutable(violates) {
|
|
234
|
-
const errors = ATTACHMENT_IMMUTABLE_FIELDS.filter(([field]) => violates(field)).map(([path, message]) => ({ path, message }));
|
|
235
|
-
if (errors.length > 0) {
|
|
236
|
-
throw new StackValidationError(errors);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
191
|
// -------------------------------------------------------
|
|
240
|
-
//
|
|
192
|
+
// Groups
|
|
241
193
|
// -------------------------------------------------------
|
|
242
|
-
/**
|
|
243
|
-
* `_config.entityId` defines stack ownership; neither patchContent() nor
|
|
244
|
-
* restoreVersion() may change it. A conflict with stack integrity, not a
|
|
245
|
-
* schema violation — hence StackConflictError. See docs/spec.md § The
|
|
246
|
-
* `_config` record.
|
|
247
|
-
*/
|
|
248
|
-
export function checkConfigEntityIdUnchanged(existingEntityId, newEntityId) {
|
|
249
|
-
if (newEntityId !== existingEntityId) {
|
|
250
|
-
throw new StackConflictError('Cannot change _config.entityId: it defines stack ownership. ' +
|
|
251
|
-
'Ownership transfer is not a supported operation.');
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
194
|
/**
|
|
255
195
|
* Refuse a write that would leave a `_group` Record with no `admin`, asked
|
|
256
196
|
* of the roster the write would produce. An integrity rule, not a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/stack/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/stack/integrity.ts"],"names":[],"mappings":"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"}
|
package/dist/stack/stack.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { StackRecord, StackType, TypeSchema, TypeId, BaseId, StackAdapter, StackQuery, QueryResult, AssociationEdit, AuthorityAssociation, DataAssociation, RecordVersion, StackCapabilities, IfVersionOptions, GrantContent, TypeGrant, PutAttachmentOptions, AttachmentContent, FileId, EntityId, AppId, InstallContent, RecordId, Actor, ActorOptions, RecordChange, SubscribeOptions, Unsubscribe, JournalQuery, VersionsQuery, RecordJournalEntry } from '../types/index.js';
|
|
20
20
|
import type { GrantQuery } from '../grants.js';
|
|
21
|
-
import type { AppManifest, InstallPlan } from '../install.js';
|
|
21
|
+
import type { AppManifest, InstallAppOptions, InstallPlan } from '../install.js';
|
|
22
22
|
import { ScopedStack } from '../scoped-stack/scoped-stack.js';
|
|
23
23
|
import type { BackdatableCreateRecordOptions, CollectAttachmentGarbageOptions, CollectAttachmentGarbageResult, DefineTypeOptions, DeleteRecordOptions, DeleteResult, GetRecordOptions, MigrateAllOptions, StackClient, StackOptions } from './client.js';
|
|
24
24
|
import type { ExpectationOptions } from './write-expectation.js';
|
|
@@ -62,7 +62,7 @@ export declare class Stack implements StackClient {
|
|
|
62
62
|
private static createActor;
|
|
63
63
|
private getTypeCached;
|
|
64
64
|
/**
|
|
65
|
-
* Open a Stack over an adapter. Reads ownerEntityId
|
|
65
|
+
* Open a Stack over an adapter. Reads ownerEntityId from the adapter.
|
|
66
66
|
*/
|
|
67
67
|
static open(adapter: StackAdapter, opts?: StackOptions): Promise<Stack>;
|
|
68
68
|
/**
|
|
@@ -75,7 +75,6 @@ export declare class Stack implements StackClient {
|
|
|
75
75
|
get ownerEntityId(): EntityId;
|
|
76
76
|
getEntityByDid(did: EntityId): Promise<StackRecord | null>;
|
|
77
77
|
getOwnerEntity(): Promise<StackRecord | null>;
|
|
78
|
-
get timezone(): string | undefined;
|
|
79
78
|
get capabilities(): StackCapabilities;
|
|
80
79
|
/**
|
|
81
80
|
* Get a permission-scoped view of this Stack, as if requests came from
|
|
@@ -94,8 +93,8 @@ export declare class Stack implements StackClient {
|
|
|
94
93
|
asActor(actor: Actor): ScopedStack;
|
|
95
94
|
/**
|
|
96
95
|
* A scoped view needs a stack that owns its storage: one whose adapter
|
|
97
|
-
* queries within a reach and
|
|
98
|
-
*
|
|
96
|
+
* queries within a reach and is its store's only writer. A server-backed
|
|
97
|
+
* stack is scoped by the session that opened it instead.
|
|
99
98
|
* See docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
100
99
|
*/
|
|
101
100
|
private scope;
|
|
@@ -346,7 +345,7 @@ export declare class Stack implements StackClient {
|
|
|
346
345
|
* from.
|
|
347
346
|
*/
|
|
348
347
|
private openRelay;
|
|
349
|
-
/** Whether
|
|
348
|
+
/** Whether a relay can be opened; whether one is needed is `writers`. */
|
|
350
349
|
private get relaysChanges();
|
|
351
350
|
/**
|
|
352
351
|
* Flush pending writes to the underlying storage. A no-op for adapters
|
|
@@ -403,12 +402,12 @@ export declare class Stack implements StackClient {
|
|
|
403
402
|
did: EntityId;
|
|
404
403
|
}): Promise<InstallPlan>;
|
|
405
404
|
/**
|
|
406
|
-
* Apply an approved
|
|
407
|
-
* Record and every linked key's grants
|
|
408
|
-
*
|
|
409
|
-
* See docs/spec/apps.md § Plan, then apply.
|
|
405
|
+
* Apply an approved manifest: its types, the key's `_app` card, the
|
|
406
|
+
* `_install` Record and every linked key's grants — refused with
|
|
407
|
+
* StackConflictError unless it still plans to `opts.fingerprint`, the
|
|
408
|
+
* plan the owner approved. See docs/spec/apps.md § Plan, then apply.
|
|
410
409
|
*/
|
|
411
|
-
installApp(
|
|
410
|
+
installApp(manifest: AppManifest, opts: InstallAppOptions): Promise<StackRecord & {
|
|
412
411
|
content: InstallContent;
|
|
413
412
|
}>;
|
|
414
413
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA4BH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,MAAM,EACN,YAAY,EACZ,UAAU,EAEV,WAAW,EAEX,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,MAAM,
|
|
1
|
+
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack/stack.ts"],"names":[],"mappings":"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"}
|
package/dist/stack/stack.js
CHANGED
|
@@ -21,15 +21,14 @@ import { hashSchema, isCompatible, parseTypeId, baseIdOf, diffSchemas, fileRefFi
|
|
|
21
21
|
import { dropAbsentFields, validateContent, validateContentKeys, validatePatchValues, validateReservedKeys, validateSchemaFieldNames, validateSchemaReservedNames, validateSchemaShape, } from '../validate.js';
|
|
22
22
|
import { applyMergePatch } from '../merge.js';
|
|
23
23
|
import { compareRecordedAttachments } from '../attachment-records.js';
|
|
24
|
-
import {
|
|
24
|
+
import { createAssociations, validatePermissions } from '../access.js';
|
|
25
25
|
import { ChangeEmitter, RelayDelivery, PendingChange, assertSinceUsable } from './changes.js';
|
|
26
26
|
import { SYSTEM_TYPES } from '../types/index.js';
|
|
27
27
|
import { ElementSetMovedError, UseAfterCloseError, ScopeUnavailableError, InvalidAdapterError, StackConflictError, StackMigrationError, StackNotFoundError, StackBadRequestError, StackSchemaDriftError, StackValidationError, StackVersionConflictError, ARGUMENTS_INVALID, SCHEMA_INVALID, softDeletedRefusal, } from '../errors.js';
|
|
28
28
|
import { assertQueryCapabilities, assertValidBaseIdFilter, assertValidJournalQuery, assertValidVersionsQuery, resolveQuery, splitQuery, filtersContent, assertFamilyId, } from '../query-validation.js';
|
|
29
29
|
import { assertAssociationEdits, assertAuthorityAssociations, assertDataAssociations, validateAssociations, } from '../associations/validation.js';
|
|
30
30
|
import { applyAssociationEdits, associationDelta } from '../associations/identity.js';
|
|
31
|
-
import { validateGrantee, validateGrantBaseId } from '../grants.js';
|
|
32
|
-
import { bindingFieldsOf } from './identity-bindings.js';
|
|
31
|
+
import { validateGrantActions, validateGrantee, validateGrantBaseId } from '../grants.js';
|
|
33
32
|
import { validateInstall } from '../install.js';
|
|
34
33
|
import { assertAttachmentSize, assertContentSize } from './limits.js';
|
|
35
34
|
import { validateRecordId, validateClockField, validateIdTimestampSkew, DEFAULT_ID_TIMESTAMP_SKEW_MS, } from './record-id.js';
|
|
@@ -41,7 +40,7 @@ import { MigrationRegistry } from './migrations.js';
|
|
|
41
40
|
import * as apps from './install-app.js';
|
|
42
41
|
import * as typeGrants from './type-grants.js';
|
|
43
42
|
import * as attachments from './attachments.js';
|
|
44
|
-
import {
|
|
43
|
+
import { assertGroupAdminRemains, assertNoParentCycle, assertParentExists, checkAttachmentAssociationPointers, checkContentWrite, } from './integrity.js';
|
|
45
44
|
import { systemTypeDefinitions } from './system-types.js';
|
|
46
45
|
import { checkFamily, checkSnapshotFamily, checkStoredVersion, WRITE_EXPECTATION, } from './write-expectation.js';
|
|
47
46
|
import { WRITE_GATE } from './write-gate.js';
|
|
@@ -92,6 +91,7 @@ function typedContentErrors(typeId, content, schema) {
|
|
|
92
91
|
...validateContent(content, schema),
|
|
93
92
|
...validateGrantee(typeId, content),
|
|
94
93
|
...validateGrantBaseId(typeId, content),
|
|
94
|
+
...validateGrantActions(typeId, content),
|
|
95
95
|
...validateInstall(typeId, content),
|
|
96
96
|
];
|
|
97
97
|
}
|
|
@@ -153,7 +153,7 @@ export class Stack {
|
|
|
153
153
|
return type;
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
* Open a Stack over an adapter. Reads ownerEntityId
|
|
156
|
+
* Open a Stack over an adapter. Reads ownerEntityId from the adapter.
|
|
157
157
|
*/
|
|
158
158
|
static async open(adapter, opts = {}) {
|
|
159
159
|
if (!adapter.ownerEntityId) {
|
|
@@ -194,9 +194,6 @@ export class Stack {
|
|
|
194
194
|
async getOwnerEntity() {
|
|
195
195
|
return this.getEntityByDid(this.ownerEntityId);
|
|
196
196
|
}
|
|
197
|
-
get timezone() {
|
|
198
|
-
return this.adapter.timezone;
|
|
199
|
-
}
|
|
200
197
|
get capabilities() {
|
|
201
198
|
return this.adapter.capabilities;
|
|
202
199
|
}
|
|
@@ -222,8 +219,8 @@ export class Stack {
|
|
|
222
219
|
}
|
|
223
220
|
/**
|
|
224
221
|
* A scoped view needs a stack that owns its storage: one whose adapter
|
|
225
|
-
* queries within a reach and
|
|
226
|
-
*
|
|
222
|
+
* queries within a reach and is its store's only writer. A server-backed
|
|
223
|
+
* stack is scoped by the session that opened it instead.
|
|
227
224
|
* See docs/spec/access-control.md § Enforcement: Stack.asEntity().
|
|
228
225
|
*/
|
|
229
226
|
scope(principalId, subjectId) {
|
|
@@ -234,9 +231,10 @@ export class Stack {
|
|
|
234
231
|
"query could not be kept to the requester's reach. Every local adapter must; a " +
|
|
235
232
|
'server-backed stack is scoped by opening it with the session you mean.');
|
|
236
233
|
}
|
|
237
|
-
if (this.
|
|
238
|
-
throw new ScopeUnavailableError('This stack cannot be scoped:
|
|
239
|
-
'scoped by the session that opened the feed. Open it with the session
|
|
234
|
+
if (this.adapter.writers === 'shared') {
|
|
235
|
+
throw new ScopeUnavailableError('This stack cannot be scoped: others write its store, and their changes reach it ' +
|
|
236
|
+
'scoped by the session that opened the feed, if at all. Open it with the session ' +
|
|
237
|
+
'you mean.');
|
|
240
238
|
}
|
|
241
239
|
return new ScopedStack(scopeToken, {
|
|
242
240
|
stack: this,
|
|
@@ -443,11 +441,8 @@ export class Stack {
|
|
|
443
441
|
];
|
|
444
442
|
throwValidation(contentErrors, argumentErrors);
|
|
445
443
|
assertContentSize(content, this.capabilities.limits.contentBytes, 'Content');
|
|
446
|
-
|
|
447
|
-
await checkAttachmentMimeTypeOnCreate(this, content);
|
|
448
|
-
}
|
|
444
|
+
await checkContentWrite(this, typeId, content);
|
|
449
445
|
await checkAttachmentAssociationPointers(this.readRecord, opts.associations);
|
|
450
|
-
await checkBindingsOnCreate(this, typeId, content);
|
|
451
446
|
if (opts.id !== undefined) {
|
|
452
447
|
validateRecordId(opts.id);
|
|
453
448
|
// Only when both are explicit: an `id` alone is a pure position
|
|
@@ -464,9 +459,7 @@ export class Stack {
|
|
|
464
459
|
await assertNoParentCycle(this.readRecord, opts.id, opts.parentId);
|
|
465
460
|
}
|
|
466
461
|
const createdBy = normalizeActor(opts.createdBy);
|
|
467
|
-
const associations =
|
|
468
|
-
? stampGroupAdmin(opts.associations, createdBy?.subjectId ?? this.ownerEntityId)
|
|
469
|
-
: opts.associations;
|
|
462
|
+
const associations = createAssociations(typeId, opts.associations, createdBy, this.ownerEntityId);
|
|
470
463
|
// createdAt drives the id, so the two agree by construction rather than
|
|
471
464
|
// by coincidence. An explicit one mints via generateIdForTimestamp(),
|
|
472
465
|
// which never clamps to "now": generateId()'s monotonic floor would
|
|
@@ -534,7 +527,7 @@ export class Stack {
|
|
|
534
527
|
this.assertOpen();
|
|
535
528
|
assertContentPatch(patch);
|
|
536
529
|
const existing = await this.requireWritable(id, opts, true);
|
|
537
|
-
const merged = await this.validatePatch(
|
|
530
|
+
const merged = await this.validatePatch(existing, patch);
|
|
538
531
|
if (contentEqual(existing.content, merged))
|
|
539
532
|
return existing;
|
|
540
533
|
const change = new PendingChange('patch', { actor: normalizeActor(opts.actor) });
|
|
@@ -550,7 +543,7 @@ export class Stack {
|
|
|
550
543
|
* Returns the merged content, which the caller compares to decide whether
|
|
551
544
|
* content moved.
|
|
552
545
|
*/
|
|
553
|
-
async validatePatch(
|
|
546
|
+
async validatePatch(existing, patch) {
|
|
554
547
|
const patchErrors = [
|
|
555
548
|
...validateReservedKeys(patch),
|
|
556
549
|
...validatePatchValues(patch),
|
|
@@ -569,19 +562,7 @@ export class Stack {
|
|
|
569
562
|
const contentErrors = typedContentErrors(existing.typeId, merged, type.schema);
|
|
570
563
|
if (contentErrors.length > 0)
|
|
571
564
|
throw new StackValidationError(contentErrors);
|
|
572
|
-
|
|
573
|
-
// Presence decides mimeType and value decides the rest: re-sending
|
|
574
|
-
// the mimeType a record already holds is refused outright, while a
|
|
575
|
-
// client round-tripping fileId or size unchanged has claimed nothing.
|
|
576
|
-
assertAttachmentImmutable((field) => Object.prototype.hasOwnProperty.call(patch, field) &&
|
|
577
|
-
(field === 'mimeType' ||
|
|
578
|
-
merged[field] !==
|
|
579
|
-
existing.content[field]));
|
|
580
|
-
}
|
|
581
|
-
await checkBindingsOnUpdate(this, existing.typeId, id, patch, existing.content, merged);
|
|
582
|
-
if (id === SYSTEM_TYPES.CONFIG) {
|
|
583
|
-
checkConfigEntityIdUnchanged(existing.content.entityId, merged.entityId);
|
|
584
|
-
}
|
|
565
|
+
await checkContentWrite(this, existing.typeId, merged, existing);
|
|
585
566
|
return merged;
|
|
586
567
|
}
|
|
587
568
|
/**
|
|
@@ -945,17 +926,9 @@ export class Stack {
|
|
|
945
926
|
if (errors.length > 0) {
|
|
946
927
|
throw new StackValidationError(errors);
|
|
947
928
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
// Restoring is a write like any other, so it owes the same immutability
|
|
952
|
-
// check a content patch pays: a snapshot taken before a card claimed
|
|
953
|
-
// its DID would otherwise move the binding by rolling content back.
|
|
954
|
-
// Uniqueness needs none — a restore can only put back a value this same
|
|
955
|
-
// card already held.
|
|
956
|
-
for (const field of bindingFieldsOf(baseIdOf(target.typeId))) {
|
|
957
|
-
checkBindingImmutable(baseIdOf(target.typeId), field, existing.content[field], target.content[field]);
|
|
958
|
-
}
|
|
929
|
+
// Restoring is a write like any other, so it owes the checks every
|
|
930
|
+
// content write pays. See docs/spec/versioning.md § Restore semantics.
|
|
931
|
+
await checkContentWrite(this, target.typeId, target.content, existing);
|
|
959
932
|
// A restore adds no containment edge and takes none away, so there is
|
|
960
933
|
// no cycle for it to close and nothing for the destination checks to
|
|
961
934
|
// gate. See docs/spec/versioning.md § Restore semantics.
|
|
@@ -1005,7 +978,6 @@ export class Stack {
|
|
|
1005
978
|
assertContentSize(content, this.capabilities.limits.contentBytes, 'Content');
|
|
1006
979
|
const fromFamily = baseIdOf(existing.typeId);
|
|
1007
980
|
const toFamily = baseIdOf(toTypeId);
|
|
1008
|
-
const existingContent = existing.content;
|
|
1009
981
|
// Only create() stamps a group's first `admin`, so a record migrated
|
|
1010
982
|
// *into* `_group` would have an empty roster. Version-to-version within
|
|
1011
983
|
// the family keeps its roster. See docs/spec/data-model.md § Type migrations.
|
|
@@ -1013,21 +985,7 @@ export class Stack {
|
|
|
1013
985
|
throw new StackConflictError('Cannot migrate a record into _group: a group’s admin roster is stamped at creation. ' +
|
|
1014
986
|
'Create the group instead.');
|
|
1015
987
|
}
|
|
1016
|
-
|
|
1017
|
-
// Value-wise throughout: a migration re-sends all three required
|
|
1018
|
-
// fields, so presence would refuse every migration of the family.
|
|
1019
|
-
assertAttachmentImmutable((field) => content[field] !==
|
|
1020
|
-
existingContent[field]);
|
|
1021
|
-
}
|
|
1022
|
-
else if (toFamily === SYSTEM_TYPES.ATTACHMENT) {
|
|
1023
|
-
// A record arriving from outside the family stakes a fresh claim on
|
|
1024
|
-
// its fileId, exactly as create() does — so it owes create()'s check.
|
|
1025
|
-
await checkAttachmentMimeTypeOnCreate(this, content);
|
|
1026
|
-
}
|
|
1027
|
-
await checkBindingsOnMigrate(this, existing.typeId, toTypeId, id, existingContent, content);
|
|
1028
|
-
if (id === SYSTEM_TYPES.CONFIG) {
|
|
1029
|
-
checkConfigEntityIdUnchanged(existing.content.entityId, content.entityId);
|
|
1030
|
-
}
|
|
988
|
+
await checkContentWrite(this, toTypeId, content, existing);
|
|
1031
989
|
const change = new PendingChange('migrate', {
|
|
1032
990
|
actor: normalizeActor(opts.actor),
|
|
1033
991
|
previousTypeId: existing.typeId,
|
|
@@ -1056,8 +1014,8 @@ export class Stack {
|
|
|
1056
1014
|
// never sees it and this is the only place it can be announced.
|
|
1057
1015
|
const record = await this.adapter.putAttachmentWithMetadata(data, opts);
|
|
1058
1016
|
// The one emission with no journal half of its own: the far side
|
|
1059
|
-
// wrote the record, so it appended the entry in that same write
|
|
1060
|
-
// the
|
|
1017
|
+
// wrote the record, so it appended the entry in that same write: a
|
|
1018
|
+
// server is the only writer of its own durable tiers. See
|
|
1061
1019
|
// docs/spec/journal.md § The entry set is the event set.
|
|
1062
1020
|
this.announce(new PendingChange('create'), record);
|
|
1063
1021
|
return record;
|
|
@@ -1141,6 +1099,12 @@ export class Stack {
|
|
|
1141
1099
|
*/
|
|
1142
1100
|
async subscribe(handler, opts = {}) {
|
|
1143
1101
|
this.assertOpen();
|
|
1102
|
+
if (this.adapter.writers === 'shared' && !this.relaysChanges) {
|
|
1103
|
+
throw new StackBadRequestError('subscribe() cannot be served: others write this stack, and its adapter has no ' +
|
|
1104
|
+
"subscribeChanges() to relay their changes, so a stream of this client's own writes " +
|
|
1105
|
+
'would pass for the whole. Connect to a server that advertises a change feed, or ' +
|
|
1106
|
+
'poll query().');
|
|
1107
|
+
}
|
|
1144
1108
|
assertSinceUsable(opts.since, this.relaysChanges);
|
|
1145
1109
|
assertValidBaseIdFilter(opts.filter);
|
|
1146
1110
|
const unsubscribe = this.changes.subscribe(handler, opts);
|
|
@@ -1181,7 +1145,7 @@ export class Stack {
|
|
|
1181
1145
|
void stop();
|
|
1182
1146
|
};
|
|
1183
1147
|
}
|
|
1184
|
-
/** Whether
|
|
1148
|
+
/** Whether a relay can be opened; whether one is needed is `writers`. */
|
|
1185
1149
|
get relaysChanges() {
|
|
1186
1150
|
return typeof this.adapter.subscribeChanges === 'function';
|
|
1187
1151
|
}
|
|
@@ -1270,14 +1234,14 @@ export class Stack {
|
|
|
1270
1234
|
return apps.planInstall(this, submitted, opts);
|
|
1271
1235
|
}
|
|
1272
1236
|
/**
|
|
1273
|
-
* Apply an approved
|
|
1274
|
-
* Record and every linked key's grants
|
|
1275
|
-
*
|
|
1276
|
-
* See docs/spec/apps.md § Plan, then apply.
|
|
1237
|
+
* Apply an approved manifest: its types, the key's `_app` card, the
|
|
1238
|
+
* `_install` Record and every linked key's grants — refused with
|
|
1239
|
+
* StackConflictError unless it still plans to `opts.fingerprint`, the
|
|
1240
|
+
* plan the owner approved. See docs/spec/apps.md § Plan, then apply.
|
|
1277
1241
|
*/
|
|
1278
|
-
async installApp(
|
|
1242
|
+
async installApp(manifest, opts) {
|
|
1279
1243
|
this.assertOpen();
|
|
1280
|
-
return apps.installApp(this,
|
|
1244
|
+
return apps.installApp(this, manifest, opts);
|
|
1281
1245
|
}
|
|
1282
1246
|
/**
|
|
1283
1247
|
* Withdraw every grant an install produced and soft-delete it. The app's
|