@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/record-changes.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* -------------------------------------------------------
|
|
4
4
|
* Two jobs that share one question — what does this Record actually say?
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
6
|
+
* The change-set helpers answer it against a proposed write, so the no-op
|
|
7
7
|
* decision and a change event's `ops` are the same comparison and can never
|
|
8
8
|
* disagree. The projections answer it against a reader: a soft-deleted
|
|
9
9
|
* Record is its tombstone, and a journal entry names the ACL it moved
|
|
@@ -12,93 +12,7 @@
|
|
|
12
12
|
* See docs/spec/events.md § The event shape and docs/spec/versioning.md
|
|
13
13
|
* § The tombstone is literal.
|
|
14
14
|
*/
|
|
15
|
-
import type {
|
|
16
|
-
/**
|
|
17
|
-
* Association identity — what dissociate() matches and a second associate()
|
|
18
|
-
* of the same reference is a repeat of. Matches the SQLite adapter's
|
|
19
|
-
* association primary key (kind, label, file_id, related_scope, related_id,
|
|
20
|
-
* related_ns, related_stack, related_role), which is why an attachment's
|
|
21
|
-
* `attachmentRecordId` is absent here: it annotates a reference rather than
|
|
22
|
-
* naming one. `related_role` is in both because member and admin name two
|
|
23
|
-
* different sets of people, so two group grantees differing only by role
|
|
24
|
-
* are two elements. See docs/spec/data-model.md § Associations.
|
|
25
|
-
*/
|
|
26
|
-
export declare function associationEqual(a: Association, b: Association): boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Structural equality per grantee arm. `role` is required, so there is no
|
|
29
|
-
* absent-means-any spelling to normalize.
|
|
30
|
-
*/
|
|
31
|
-
export declare function granteeEqual(a: Grantee, b: Grantee): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Whether an association carries authority rather than data — the partition
|
|
34
|
-
* `StackRecord.permissions` and `StackRecord.associations` project, and the
|
|
35
|
-
* line `associate()`/`dissociate()` refuse to cross.
|
|
36
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
37
|
-
*/
|
|
38
|
-
export declare function isAuthorityAssociation(a: Association): a is AuthorityAssociation;
|
|
39
|
-
/**
|
|
40
|
-
* One stored association set split into the two the record presents. An app
|
|
41
|
-
* editing tags never sees the authority half, so it cannot drop it.
|
|
42
|
-
*/
|
|
43
|
-
export declare function partitionAssociations(associations: Association[]): {
|
|
44
|
-
associations: DataAssociation[];
|
|
45
|
-
permissions: AuthorityAssociation[];
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Identity plus every annotation outside it, so a write that only re-points
|
|
49
|
-
* an attachment association's `attachmentRecordId` still counts as a
|
|
50
|
-
* change. Identity alone decides which stored association a write lands on;
|
|
51
|
-
* this decides whether it says anything new.
|
|
52
|
-
*/
|
|
53
|
-
export declare function associationIdentical(a: Association, b: Association): boolean;
|
|
54
|
-
/**
|
|
55
|
-
* An association's identity, stripped of every annotation outside it — an
|
|
56
|
-
* attachment's `attachmentRecordId` dropped, everything else unchanged.
|
|
57
|
-
* What a change event reports for an association that's gone: the same
|
|
58
|
-
* thing a `purged` frame does for a destroyed record's content, naming
|
|
59
|
-
* what happened without repeating a payload that's no longer current.
|
|
60
|
-
* See docs/spec/events.md § The event shape.
|
|
61
|
-
*/
|
|
62
|
-
export declare function stripAssociationAnnotation(association: Association): Association;
|
|
63
|
-
/**
|
|
64
|
-
* What a `changes.associations` list moves against a record's current
|
|
65
|
-
* associations, one tagged edit per association.
|
|
66
|
-
*
|
|
67
|
-
* An entry matching something already there by identity displaced it rather
|
|
68
|
-
* than joining it, which is a `repoint`: the association is still on the
|
|
69
|
-
* record and only its annotation moved, so no `remove` can describe it.
|
|
70
|
-
* `previous` is the prior association in full, annotation included — the
|
|
71
|
-
* only place an overwritten or removed `attachmentRecordId` survives.
|
|
72
|
-
* See docs/spec/journal.md § The entry.
|
|
73
|
-
*/
|
|
74
|
-
export declare function associationDelta(before: Association[], after: Association[]): AssociationChange[];
|
|
75
|
-
/**
|
|
76
|
-
* The two flat lists a change frame carries, derived from the tagged list.
|
|
77
|
-
* The feed reports what is true now, so a `repoint` appears only under its
|
|
78
|
-
* new value and a `remove` by identity alone — the prior state the journal
|
|
79
|
-
* keeps has no place on a notification. The data half alone: `reshare` is
|
|
80
|
-
* what announces an ACL move. See docs/spec/events.md § The event shape.
|
|
81
|
-
*/
|
|
82
|
-
export declare function feedAssociationDelta(changes: AssociationChange[]): {
|
|
83
|
-
added: DataAssociation[];
|
|
84
|
-
removed: DataAssociation[];
|
|
85
|
-
};
|
|
86
|
-
/** Structural equality per target arm — what dissociate() matches on. */
|
|
87
|
-
export declare function targetEqual(a: RelationshipTarget, b: RelationshipTarget): boolean;
|
|
88
|
-
/**
|
|
89
|
-
* An association edit list travels one surface: authority and data share
|
|
90
|
-
* storage and a delta, and never share a call. Refused here so every
|
|
91
|
-
* adapter inherits the same rule.
|
|
92
|
-
* See docs/spec/access-control.md § Storage unifies; the API does not.
|
|
93
|
-
*/
|
|
94
|
-
export declare function assertOneSurface(changes: readonly AssociationEdit[]): void;
|
|
95
|
-
/**
|
|
96
|
-
* The set a list of edits leaves behind: removes first, then adds, an add
|
|
97
|
-
* landing on an identity already held in place. Adds naming one identity
|
|
98
|
-
* collapse, last wins; an add outlives a remove of the same identity.
|
|
99
|
-
* See docs/spec/adapters.md § Amending associations.
|
|
100
|
-
*/
|
|
101
|
-
export declare function applyAssociationEdits(current: Association[], changes: readonly AssociationEdit[]): Association[];
|
|
15
|
+
import type { ChangeOp, RecordChangeSet, RecordJournalEntry, StackRecord } from './types/index.js';
|
|
102
16
|
/**
|
|
103
17
|
* A change set has to name at least one aspect. Refused rather than read
|
|
104
18
|
* as a no-op: it addresses nothing, so there is nothing it could have
|
|
@@ -135,37 +49,8 @@ export declare function takesIfVersion(changes: RecordChangeSet): boolean;
|
|
|
135
49
|
* adapter receives is one it must write.
|
|
136
50
|
*/
|
|
137
51
|
export declare function effectiveChanges(changes: RecordChangeSet, ops: ChangeOp[]): RecordChangeSet;
|
|
138
|
-
/**
|
|
139
|
-
* Whether a merge patch produced the content the record already held.
|
|
140
|
-
* Compared by serialization: content is JSON by construction and a patch
|
|
141
|
-
* preserves key order for every field it does not name, so an unchanged
|
|
142
|
-
* record encodes stably. A reordering patch that changes nothing else is
|
|
143
|
-
* the one case this reports as a change, costing an empty version rather
|
|
144
|
-
* than a wrong answer.
|
|
145
|
-
*/
|
|
146
|
-
export declare function contentEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean;
|
|
147
|
-
/** Bootstraps a `_group` record's first admin at create time. */
|
|
148
|
-
export declare function stampGroupAdmin(associations: DataAssociation[] | undefined, creator: EntityId): DataAssociation[];
|
|
149
|
-
/**
|
|
150
|
-
* Whether a Record is a `_group`, in any of its type versions — the family
|
|
151
|
-
* whose roster rules apply.
|
|
152
|
-
*/
|
|
153
|
-
export declare function isGroupRecord(record: StackRecord): boolean;
|
|
154
|
-
/**
|
|
155
|
-
* The tombstone a soft-deleted Record is presented as. `permissions` is
|
|
156
|
-
* retained because it decides whether the caller may undelete; history is
|
|
157
|
-
* exempt, which is why getVersions() still serves the content this
|
|
158
|
-
* withholds. See docs/spec/versioning.md § The tombstone is literal.
|
|
159
|
-
*/
|
|
160
|
-
export declare function tombstoneOf(record: StackRecord): StackRecord;
|
|
161
52
|
/** A soft-deleted Record presented as its tombstone; anything else untouched. */
|
|
162
53
|
export declare const presentDeleted: (record: StackRecord) => StackRecord;
|
|
163
|
-
/**
|
|
164
|
-
* Whether a tagged edit moved an authority element, reading whichever half
|
|
165
|
-
* of the pair carries one. The delta is one list across the partition, so
|
|
166
|
-
* every consumer that serves one half alone asks this.
|
|
167
|
-
*/
|
|
168
|
-
export declare function movesAuthority(change: AssociationChange): boolean;
|
|
169
54
|
/**
|
|
170
55
|
* A journal entry as a reader who cannot reshare sees it: the authority
|
|
171
56
|
* half of its delta dropped, the `reshare` op left standing, so the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-changes.d.ts","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"record-changes.d.ts","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAEV,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAOtE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC1C,QAAQ,EAAE,CA2BZ;AAiBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,OAAO,CAErD;AAcD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAIhE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,CAU3F;AAgCD,iFAAiF;AACjF,eAAO,MAAM,cAAc,GAAI,QAAQ,WAAW,KAAG,WACJ,CAAC;AAWlD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,kBAAkB,CAKrF"}
|
package/dist/record-changes.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* -------------------------------------------------------
|
|
4
4
|
* Two jobs that share one question — what does this Record actually say?
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
6
|
+
* The change-set helpers answer it against a proposed write, so the no-op
|
|
7
7
|
* decision and a change event's `ops` are the same comparison and can never
|
|
8
8
|
* disagree. The projections answer it against a reader: a soft-deleted
|
|
9
9
|
* Record is its tombstone, and a journal entry names the ACL it moved
|
|
@@ -12,188 +12,9 @@
|
|
|
12
12
|
* See docs/spec/events.md § The event shape and docs/spec/versioning.md
|
|
13
13
|
* § The tombstone is literal.
|
|
14
14
|
*/
|
|
15
|
-
import { baseIdOf } from './schema.js';
|
|
16
15
|
import { StackBadRequestError } from './errors.js';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
* Association identity — what dissociate() matches and a second associate()
|
|
20
|
-
* of the same reference is a repeat of. Matches the SQLite adapter's
|
|
21
|
-
* association primary key (kind, label, file_id, related_scope, related_id,
|
|
22
|
-
* related_ns, related_stack, related_role), which is why an attachment's
|
|
23
|
-
* `attachmentRecordId` is absent here: it annotates a reference rather than
|
|
24
|
-
* naming one. `related_role` is in both because member and admin name two
|
|
25
|
-
* different sets of people, so two group grantees differing only by role
|
|
26
|
-
* are two elements. See docs/spec/data-model.md § Associations.
|
|
27
|
-
*/
|
|
28
|
-
export function associationEqual(a, b) {
|
|
29
|
-
// Never "the same one": naming a malformed association is
|
|
30
|
-
// validateAssociation()'s job, which this must reach without throwing.
|
|
31
|
-
if (!a || !b)
|
|
32
|
-
return false;
|
|
33
|
-
if (a.kind !== b.kind || a.label !== b.label)
|
|
34
|
-
return false;
|
|
35
|
-
if (a.kind === 'attachment' && b.kind === 'attachment')
|
|
36
|
-
return a.fileId === b.fileId;
|
|
37
|
-
if (a.kind === 'relationship' && b.kind === 'relationship') {
|
|
38
|
-
return targetEqual(a.target, b.target);
|
|
39
|
-
}
|
|
40
|
-
if (a.kind === 'permission' && b.kind === 'permission') {
|
|
41
|
-
return granteeEqual(a.grantee, b.grantee);
|
|
42
|
-
}
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Structural equality per grantee arm. `role` is required, so there is no
|
|
47
|
-
* absent-means-any spelling to normalize.
|
|
48
|
-
*/
|
|
49
|
-
export function granteeEqual(a, b) {
|
|
50
|
-
if (!a || !b)
|
|
51
|
-
return false;
|
|
52
|
-
if (a.kind !== b.kind)
|
|
53
|
-
return false;
|
|
54
|
-
if (a.kind === 'entity' && b.kind === 'entity')
|
|
55
|
-
return a.entityId === b.entityId;
|
|
56
|
-
if (a.kind === 'group' && b.kind === 'group') {
|
|
57
|
-
return a.groupId === b.groupId && a.role === b.role;
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Whether an association carries authority rather than data — the partition
|
|
63
|
-
* `StackRecord.permissions` and `StackRecord.associations` project, and the
|
|
64
|
-
* line `associate()`/`dissociate()` refuse to cross.
|
|
65
|
-
* See docs/spec/access-control.md § Record-level permissions.
|
|
66
|
-
*/
|
|
67
|
-
export function isAuthorityAssociation(a) {
|
|
68
|
-
return a?.kind === 'permission' || a?.kind === 'anyone';
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* One stored association set split into the two the record presents. An app
|
|
72
|
-
* editing tags never sees the authority half, so it cannot drop it.
|
|
73
|
-
*/
|
|
74
|
-
export function partitionAssociations(associations) {
|
|
75
|
-
return {
|
|
76
|
-
associations: associations.filter((a) => !isAuthorityAssociation(a)),
|
|
77
|
-
permissions: associations.filter(isAuthorityAssociation),
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Identity plus every annotation outside it, so a write that only re-points
|
|
82
|
-
* an attachment association's `attachmentRecordId` still counts as a
|
|
83
|
-
* change. Identity alone decides which stored association a write lands on;
|
|
84
|
-
* this decides whether it says anything new.
|
|
85
|
-
*/
|
|
86
|
-
export function associationIdentical(a, b) {
|
|
87
|
-
if (!associationEqual(a, b))
|
|
88
|
-
return false;
|
|
89
|
-
if (a.kind === 'attachment' && b.kind === 'attachment') {
|
|
90
|
-
return (a.attachmentRecordId ?? '') === (b.attachmentRecordId ?? '');
|
|
91
|
-
}
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* An association's identity, stripped of every annotation outside it — an
|
|
96
|
-
* attachment's `attachmentRecordId` dropped, everything else unchanged.
|
|
97
|
-
* What a change event reports for an association that's gone: the same
|
|
98
|
-
* thing a `purged` frame does for a destroyed record's content, naming
|
|
99
|
-
* what happened without repeating a payload that's no longer current.
|
|
100
|
-
* See docs/spec/events.md § The event shape.
|
|
101
|
-
*/
|
|
102
|
-
export function stripAssociationAnnotation(association) {
|
|
103
|
-
if (association.kind !== 'attachment')
|
|
104
|
-
return association;
|
|
105
|
-
const { attachmentRecordId: _attachmentRecordId, ...identity } = association;
|
|
106
|
-
return identity;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* What a `changes.associations` list moves against a record's current
|
|
110
|
-
* associations, one tagged edit per association.
|
|
111
|
-
*
|
|
112
|
-
* An entry matching something already there by identity displaced it rather
|
|
113
|
-
* than joining it, which is a `repoint`: the association is still on the
|
|
114
|
-
* record and only its annotation moved, so no `remove` can describe it.
|
|
115
|
-
* `previous` is the prior association in full, annotation included — the
|
|
116
|
-
* only place an overwritten or removed `attachmentRecordId` survives.
|
|
117
|
-
* See docs/spec/journal.md § The entry.
|
|
118
|
-
*/
|
|
119
|
-
export function associationDelta(before, after) {
|
|
120
|
-
const changes = after
|
|
121
|
-
.filter((a) => !before.some((b) => associationIdentical(a, b)))
|
|
122
|
-
.map((association) => {
|
|
123
|
-
const previous = before.find((b) => associationEqual(b, association));
|
|
124
|
-
return previous
|
|
125
|
-
? { op: 'repoint', association, previous }
|
|
126
|
-
: { op: 'add', association };
|
|
127
|
-
});
|
|
128
|
-
return changes.concat(before
|
|
129
|
-
.filter((b) => !after.some((a) => associationEqual(a, b)))
|
|
130
|
-
.map((association) => ({ op: 'remove', association })));
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* The two flat lists a change frame carries, derived from the tagged list.
|
|
134
|
-
* The feed reports what is true now, so a `repoint` appears only under its
|
|
135
|
-
* new value and a `remove` by identity alone — the prior state the journal
|
|
136
|
-
* keeps has no place on a notification. The data half alone: `reshare` is
|
|
137
|
-
* what announces an ACL move. See docs/spec/events.md § The event shape.
|
|
138
|
-
*/
|
|
139
|
-
export function feedAssociationDelta(changes) {
|
|
140
|
-
const added = [];
|
|
141
|
-
const removed = [];
|
|
142
|
-
for (const c of changes) {
|
|
143
|
-
if (c.op === 'remove') {
|
|
144
|
-
const identity = stripAssociationAnnotation(c.association);
|
|
145
|
-
if (!isAuthorityAssociation(identity))
|
|
146
|
-
removed.push(identity);
|
|
147
|
-
}
|
|
148
|
-
else if (!isAuthorityAssociation(c.association)) {
|
|
149
|
-
added.push(c.association);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return { added, removed };
|
|
153
|
-
}
|
|
154
|
-
/** Structural equality per target arm — what dissociate() matches on. */
|
|
155
|
-
export function targetEqual(a, b) {
|
|
156
|
-
if (a.kind !== b.kind)
|
|
157
|
-
return false;
|
|
158
|
-
if (a.kind === 'record' && b.kind === 'record') {
|
|
159
|
-
return a.recordId === b.recordId && (a.stackUrl ?? '') === (b.stackUrl ?? '');
|
|
160
|
-
}
|
|
161
|
-
if (a.kind === 'entity' && b.kind === 'entity')
|
|
162
|
-
return a.entityId === b.entityId;
|
|
163
|
-
if (a.kind === 'external' && b.kind === 'external')
|
|
164
|
-
return a.ns === b.ns && a.id === b.id;
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* An association edit list travels one surface: authority and data share
|
|
169
|
-
* storage and a delta, and never share a call. Refused here so every
|
|
170
|
-
* adapter inherits the same rule.
|
|
171
|
-
* See docs/spec/access-control.md § Storage unifies; the API does not.
|
|
172
|
-
*/
|
|
173
|
-
export function assertOneSurface(changes) {
|
|
174
|
-
const authority = changes.filter((c) => isAuthorityAssociation(c.association)).length;
|
|
175
|
-
if (authority === 0 || authority === changes.length)
|
|
176
|
-
return;
|
|
177
|
-
throw new StackBadRequestError('An association edit list carries authority or data, never both: permission and anyone ' +
|
|
178
|
-
'elements travel on the permissions surface.');
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* The set a list of edits leaves behind: removes first, then adds, an add
|
|
182
|
-
* landing on an identity already held in place. Adds naming one identity
|
|
183
|
-
* collapse, last wins; an add outlives a remove of the same identity.
|
|
184
|
-
* See docs/spec/adapters.md § Amending associations.
|
|
185
|
-
*/
|
|
186
|
-
export function applyAssociationEdits(current, changes) {
|
|
187
|
-
let next = current.filter((a) => !changes.some((c) => c.op === 'remove' && associationEqual(c.association, a)));
|
|
188
|
-
for (const c of changes) {
|
|
189
|
-
if (c.op !== 'add')
|
|
190
|
-
continue;
|
|
191
|
-
next = next.some((a) => associationEqual(a, c.association))
|
|
192
|
-
? next.map((a) => (associationEqual(a, c.association) ? c.association : a))
|
|
193
|
-
: [...next, c.association];
|
|
194
|
-
}
|
|
195
|
-
return next;
|
|
196
|
-
}
|
|
16
|
+
import { associationDelta, isAuthorityAssociation } from './associations/identity.js';
|
|
17
|
+
import { RECORD_CHANGE_SET_KEYS } from './types/index.js';
|
|
197
18
|
/**
|
|
198
19
|
* A change set has to name at least one aspect. Refused rather than read
|
|
199
20
|
* as a no-op: it addresses nothing, so there is nothing it could have
|
|
@@ -302,44 +123,21 @@ export function effectiveChanges(changes, ops) {
|
|
|
302
123
|
return effective;
|
|
303
124
|
}
|
|
304
125
|
/**
|
|
305
|
-
* Whether a merge patch produced the content
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* the one case this reports as a change, costing an empty version rather
|
|
310
|
-
* than a wrong answer.
|
|
126
|
+
* Whether a merge patch produced the content already held, compared by
|
|
127
|
+
* serialization: a patch preserves the order of every key it does not name.
|
|
128
|
+
* A pure reordering is the one false "change", costing an empty version
|
|
129
|
+
* rather than a wrong answer.
|
|
311
130
|
*/
|
|
312
|
-
|
|
131
|
+
function contentEqual(a, b) {
|
|
313
132
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
314
133
|
}
|
|
315
|
-
/** Bootstraps a `_group` record's first admin at create time. */
|
|
316
|
-
export function stampGroupAdmin(associations, creator) {
|
|
317
|
-
const list = associations ?? [];
|
|
318
|
-
const alreadyAdmin = list.some((a) => a.kind === 'relationship' &&
|
|
319
|
-
a.label === 'admin' &&
|
|
320
|
-
a.target.kind === 'entity' &&
|
|
321
|
-
a.target.entityId === creator);
|
|
322
|
-
if (alreadyAdmin)
|
|
323
|
-
return list;
|
|
324
|
-
return [
|
|
325
|
-
...list,
|
|
326
|
-
{ kind: 'relationship', label: 'admin', target: { kind: 'entity', entityId: creator } },
|
|
327
|
-
];
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Whether a Record is a `_group`, in any of its type versions — the family
|
|
331
|
-
* whose roster rules apply.
|
|
332
|
-
*/
|
|
333
|
-
export function isGroupRecord(record) {
|
|
334
|
-
return baseIdOf(record.typeId) === SYSTEM_TYPES.GROUP;
|
|
335
|
-
}
|
|
336
134
|
/**
|
|
337
135
|
* The tombstone a soft-deleted Record is presented as. `permissions` is
|
|
338
136
|
* retained because it decides whether the caller may undelete; history is
|
|
339
137
|
* exempt, which is why getVersions() still serves the content this
|
|
340
138
|
* withholds. See docs/spec/versioning.md § The tombstone is literal.
|
|
341
139
|
*/
|
|
342
|
-
|
|
140
|
+
function tombstoneOf(record) {
|
|
343
141
|
return {
|
|
344
142
|
id: record.id,
|
|
345
143
|
typeId: record.typeId,
|
|
@@ -359,7 +157,7 @@ export const presentDeleted = (record) => record.deletedAt ? tombstoneOf(record)
|
|
|
359
157
|
* of the pair carries one. The delta is one list across the partition, so
|
|
360
158
|
* every consumer that serves one half alone asks this.
|
|
361
159
|
*/
|
|
362
|
-
|
|
160
|
+
function movesAuthority(change) {
|
|
363
161
|
return isAuthorityAssociation(change.association);
|
|
364
162
|
}
|
|
365
163
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-changes.js","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"record-changes.js","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Stack — Schema Utilities
|
|
3
3
|
* -------------------------------------------------------
|
|
4
|
-
*
|
|
4
|
+
* What can be said about a TypeSchema and a TypeId without a stack: a
|
|
5
|
+
* schema's hash, whether one schema reads as another, whether one is a
|
|
6
|
+
* legal in-place evolution of another, and how a TypeId splits into its
|
|
7
|
+
* family and version.
|
|
5
8
|
*
|
|
6
9
|
* Hashing produces a stable SHA-256 fingerprint of a TypeSchema
|
|
7
10
|
* by canonicalizing it first (alphabetical keys, minified JSON).
|
|
8
11
|
* This is used for drift detection — not type identity, which is
|
|
9
12
|
* the namespaced ID controlled by the app author.
|
|
10
13
|
*/
|
|
11
|
-
import type { TypeSchema } from './types.js';
|
|
14
|
+
import type { TypeSchema } from './types/index.js';
|
|
12
15
|
import type { ReadonlyTypeSchema } from './type-handle.js';
|
|
13
16
|
/**
|
|
14
17
|
* Compute a stable SHA-256 hash of a TypeSchema.
|
|
@@ -36,6 +39,12 @@ export type SchemaDriftViolation = {
|
|
|
36
39
|
* docs/spec/data-model.md § Schema drift detection.
|
|
37
40
|
*/
|
|
38
41
|
export declare const diffSchemas: (stored: TypeSchema, candidate: TypeSchema) => SchemaDriftViolation[];
|
|
42
|
+
/**
|
|
43
|
+
* A schema's top-level `file-ref` fields — the content half of what a
|
|
44
|
+
* record references, beside its attachment associations. A nested one is
|
|
45
|
+
* validated but is not a reference. See docs/spec/data-model.md § Types.
|
|
46
|
+
*/
|
|
47
|
+
export declare const fileRefFields: (schema: ReadonlyTypeSchema) => string[];
|
|
39
48
|
/**
|
|
40
49
|
* Parse a versioned TypeId into its base and version components.
|
|
41
50
|
* e.g. "com.example.myapp/note@2" → { baseId: "com.example.myapp/note", version: 2 }
|
|
@@ -45,17 +54,19 @@ export declare const parseTypeId: (typeId: string) => {
|
|
|
45
54
|
baseId: string;
|
|
46
55
|
version: number;
|
|
47
56
|
} | null;
|
|
48
|
-
/**
|
|
49
|
-
* Build a versioned TypeId from a base ID and version number.
|
|
50
|
-
* e.g. ("com.example.myapp/note", 2) → "com.example.myapp/note@2"
|
|
51
|
-
*/
|
|
52
|
-
export declare const buildTypeId: (baseId: string, version: number) => string;
|
|
53
57
|
/**
|
|
54
58
|
* Extract the base (family) ID from a TypeId, tolerating an already-bare
|
|
55
59
|
* baseId (no "@n" suffix) as a no-op. Used to compare across versions —
|
|
56
60
|
* e.g. a grant on "comment@1" and a record at "comment@2" share a baseId.
|
|
57
61
|
*/
|
|
58
62
|
export declare const baseIdOf: (typeId: string) => string;
|
|
63
|
+
/**
|
|
64
|
+
* Why `migratesFrom` cannot be the lineage of `id`, or null if it can. A
|
|
65
|
+
* version migrates from an earlier version of its own family; a step into
|
|
66
|
+
* another family is a migration, not lineage. See docs/spec/data-model.md
|
|
67
|
+
* § Type migrations.
|
|
68
|
+
*/
|
|
69
|
+
export declare const lineageProblem: (id: string, migratesFrom: unknown) => string | null;
|
|
59
70
|
/**
|
|
60
71
|
* Why `value` cannot name a type family, or null if it can. A family is a
|
|
61
72
|
* bare `BaseId`; a versioned TypeId names one version and is refused with the
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,kBAAkB,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAqE3D;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAU,QAAQ,UAAU,KAAG,OAAO,CAAC,MAAM,CAMnE,CAAC;AAmFF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GACvB,iBAAiB,kBAAkB,EACnC,gBAAgB,kBAAkB,KACjC,OAA8F,CAAC;AASlG,MAAM,MAAM,oBAAoB,GAAG;IACjC,qHAAqH;IACrH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAmGF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,UAAU,EAAE,WAAW,UAAU,KAAG,oBAAoB,EAI3F,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,kBAAkB,KAAG,MAAM,EAGrC,CAAC;AAM7B;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,KAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAIlF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,MAA+C,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,MAAM,EAAE,cAAc,OAAO,KAAG,MAAM,GAAG,IAW3E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,EAAE,OAAO,MAAM,KAAG,MAAM,GAAG,IAWxE,CAAC"}
|