@haverstack/core 0.33.0 → 0.36.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 -1
- package/dist/access.d.ts +39 -34
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +94 -68
- package/dist/access.js.map +1 -1
- package/dist/changes.d.ts +74 -58
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +115 -101
- package/dist/changes.js.map +1 -1
- package/dist/combine.d.ts.map +1 -1
- package/dist/combine.js +7 -0
- package/dist/combine.js.map +1 -1
- package/dist/grants.d.ts +78 -33
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +164 -72
- package/dist/grants.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/query-validation.d.ts +30 -1
- package/dist/query-validation.d.ts.map +1 -1
- package/dist/query-validation.js +128 -2
- package/dist/query-validation.js.map +1 -1
- package/dist/record-changes.d.ts +77 -57
- package/dist/record-changes.d.ts.map +1 -1
- package/dist/record-changes.js +153 -89
- package/dist/record-changes.js.map +1 -1
- package/dist/scoped-stack.d.ts +120 -120
- package/dist/scoped-stack.d.ts.map +1 -1
- package/dist/scoped-stack.js +210 -190
- package/dist/scoped-stack.js.map +1 -1
- package/dist/stack.d.ts +178 -168
- package/dist/stack.d.ts.map +1 -1
- package/dist/stack.js +346 -277
- package/dist/stack.js.map +1 -1
- package/dist/testing.d.ts +16 -5
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +124 -52
- package/dist/testing.js.map +1 -1
- package/dist/types.d.ts +155 -113
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +0 -2
- package/dist/validate.js.map +1 -1
- package/dist/wire-record.d.ts.map +1 -1
- package/dist/wire-record.js.map +1 -1
- package/package.json +1 -1
package/dist/record-changes.d.ts
CHANGED
|
@@ -6,22 +6,44 @@
|
|
|
6
6
|
* The equality 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
|
-
* Record is its tombstone, and a
|
|
10
|
-
*
|
|
9
|
+
* Record is its tombstone, and a journal entry names the ACL it moved
|
|
10
|
+
* only to a reader who could have moved it.
|
|
11
11
|
*
|
|
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 { Association, ChangeOp, EntityId,
|
|
15
|
+
import type { Association, AssociationChange, AuthorityAssociation, ChangeOp, DataAssociation, EntityId, PermissionGrantee, RecordChanges, RecordJournalEntry, RelationshipTarget, StackRecord } from './types.js';
|
|
16
16
|
/**
|
|
17
17
|
* Association identity — what dissociate() matches and a second associate()
|
|
18
18
|
* of the same reference is a repeat of. Matches the SQLite adapter's
|
|
19
19
|
* association primary key (kind, label, file_id, related_scope, related_id,
|
|
20
|
-
* related_ns, related_stack), which is why an attachment's
|
|
20
|
+
* related_ns, related_stack, related_role), which is why an attachment's
|
|
21
21
|
* `attachmentRecordId` is absent here: it annotates a reference rather than
|
|
22
|
-
* naming one.
|
|
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.
|
|
23
25
|
*/
|
|
24
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: PermissionGrantee, b: PermissionGrantee): 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
|
+
};
|
|
25
47
|
/**
|
|
26
48
|
* Identity plus every annotation outside it, so a write that only re-points
|
|
27
49
|
* an attachment association's `attachmentRecordId` still counts as a
|
|
@@ -40,20 +62,28 @@ export declare function associationIdentical(a: Association, b: Association): bo
|
|
|
40
62
|
export declare function stripAssociationAnnotation(association: Association): Association;
|
|
41
63
|
/**
|
|
42
64
|
* What a `changes.associations` list moves against a record's current
|
|
43
|
-
* associations
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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.
|
|
48
73
|
*/
|
|
49
|
-
export declare function associationDelta(before: Association[], after: Association[]):
|
|
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.
|
|
80
|
+
*/
|
|
81
|
+
export declare function feedAssociationDelta(changes: AssociationChange[]): {
|
|
50
82
|
added: Association[];
|
|
51
83
|
removed: Association[];
|
|
52
|
-
replaced: Association[];
|
|
53
84
|
};
|
|
54
85
|
/** Structural equality per target arm — what dissociate() matches on. */
|
|
55
86
|
export declare function targetEqual(a: RelationshipTarget, b: RelationshipTarget): boolean;
|
|
56
|
-
export declare function permissionEqual(a: Permission, b: Permission): boolean;
|
|
57
87
|
/**
|
|
58
88
|
* A change set has to name at least one aspect. Refused rather than read
|
|
59
89
|
* as a no-op: it addresses nothing, so there is nothing it could have
|
|
@@ -64,72 +94,48 @@ export declare function permissionEqual(a: Permission, b: Permission): boolean;
|
|
|
64
94
|
export declare function assertNonEmptyChangeSet(changes: RecordChanges): void;
|
|
65
95
|
/**
|
|
66
96
|
* Which aspects a change set actually moves, against the record as it
|
|
67
|
-
* stands
|
|
68
|
-
*
|
|
69
|
-
* already holds contributes nothing.
|
|
70
|
-
*
|
|
71
|
-
* `merged` is the content the patch produces, computed once by the
|
|
97
|
+
* stands. A key naming the value a record already holds contributes
|
|
98
|
+
* nothing. `merged` is the content the patch produces, computed once by the
|
|
72
99
|
* caller that had to validate it anyway.
|
|
73
|
-
* See docs/spec/events.md § The event shape.
|
|
74
100
|
*/
|
|
75
101
|
export declare function changeSetOps(existing: StackRecord, changes: RecordChanges, merged: Record<string, unknown> | undefined): ChangeOp[];
|
|
76
102
|
/**
|
|
77
|
-
* Whether a change set's ops advance `version`/`updatedAt` at all.
|
|
78
|
-
*
|
|
79
|
-
* `associations` is a no-bump write, same as calling associate()/
|
|
80
|
-
* dissociate() directly. Every other op does. See
|
|
81
|
-
* docs/spec/versioning.md § Version history.
|
|
103
|
+
* Whether a change set's ops advance `version`/`updatedAt` at all. After the
|
|
104
|
+
* no-bump set above, this is `patch` and the whole-record verbs.
|
|
82
105
|
*/
|
|
83
106
|
export declare function bumpsVersion(ops: ChangeOp[]): boolean;
|
|
84
107
|
/**
|
|
85
|
-
* Whether `ifVersion` applies to a change set. A set
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* Read off the keys the caller wrote rather than the ops the set turns out
|
|
91
|
-
* to move, so a stale caller is told its version is stale whatever its
|
|
92
|
-
* patch says — including when the patch restates what the record already
|
|
93
|
-
* holds. See docs/spec/versioning.md § Optimistic concurrency.
|
|
108
|
+
* Whether `ifVersion` applies to a change set. A set naming only keys from
|
|
109
|
+
* the no-precondition list above carries none; any other aspect named
|
|
110
|
+
* restores the guard over the whole call. Read off the keys the caller
|
|
111
|
+
* wrote rather than the ops the set turns out to move, so a stale caller is
|
|
112
|
+
* told its version is stale whatever its patch says.
|
|
94
113
|
*/
|
|
95
114
|
export declare function takesIfVersion(changes: RecordChanges): boolean;
|
|
96
115
|
/**
|
|
97
|
-
* The change set narrowed to the aspects that actually moved. An adapter
|
|
98
|
-
*
|
|
116
|
+
* The change set narrowed to the aspects that actually moved. An adapter is
|
|
117
|
+
* handed this rather than what the caller wrote, so restating an aspect
|
|
99
118
|
* cannot rewrite it: `unlisted: true` on an already-unlisted record would
|
|
100
|
-
* otherwise drag `unlistedAt` forward
|
|
101
|
-
*
|
|
102
|
-
* every key an adapter receives is one it must write.
|
|
119
|
+
* otherwise drag `unlistedAt` forward with no op reporting it. Every key an
|
|
120
|
+
* adapter receives is one it must write.
|
|
103
121
|
*/
|
|
104
122
|
export declare function effectiveChanges(changes: RecordChanges, ops: ChangeOp[]): RecordChanges;
|
|
105
123
|
/**
|
|
106
124
|
* Whether a merge patch produced the content the record already held.
|
|
107
|
-
* Compared by serialization: content is JSON by construction
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* wrong answer.
|
|
125
|
+
* Compared by serialization: content is JSON by construction and a patch
|
|
126
|
+
* preserves key order for every field it does not name, so an unchanged
|
|
127
|
+
* record encodes stably. A reordering patch that changes nothing else is
|
|
128
|
+
* the one case this reports as a change, costing an empty version rather
|
|
129
|
+
* than a wrong answer.
|
|
113
130
|
*/
|
|
114
131
|
export declare function contentEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* Ensures `creator` carries an `admin` relationship association, adding one
|
|
118
|
-
* if it's not already present. Used to bootstrap a `_group` record's first
|
|
119
|
-
* admin at create time.
|
|
120
|
-
*/
|
|
121
|
-
export declare function stampGroupAdmin(associations: Association[] | undefined, creator: EntityId): Association[];
|
|
132
|
+
/** Bootstraps a `_group` record's first admin at create time. */
|
|
133
|
+
export declare function stampGroupAdmin(associations: DataAssociation[] | undefined, creator: EntityId): DataAssociation[];
|
|
122
134
|
/**
|
|
123
135
|
* Whether a Record is a `_group`, in any of its type versions — the family
|
|
124
136
|
* whose roster rules apply.
|
|
125
137
|
*/
|
|
126
138
|
export declare function isGroupRecord(record: StackRecord): boolean;
|
|
127
|
-
/**
|
|
128
|
-
* Drops a snapshot's `permissions` — owner-only audit data, never served
|
|
129
|
-
* to a non-owner history reader. `entityId` (change attribution) stays.
|
|
130
|
-
* See docs/spec/versioning.md § History access.
|
|
131
|
-
*/
|
|
132
|
-
export declare function stripVersionPermissions(version: RecordVersion): RecordVersion;
|
|
133
139
|
/**
|
|
134
140
|
* The tombstone a soft-deleted Record is presented as. `permissions` is
|
|
135
141
|
* retained because it decides whether the caller may undelete; history is
|
|
@@ -139,4 +145,18 @@ export declare function stripVersionPermissions(version: RecordVersion): RecordV
|
|
|
139
145
|
export declare function tombstoneOf(record: StackRecord): StackRecord;
|
|
140
146
|
/** A soft-deleted Record presented as its tombstone; anything else untouched. */
|
|
141
147
|
export declare const presentDeleted: (record: StackRecord) => StackRecord;
|
|
148
|
+
/**
|
|
149
|
+
* Whether a tagged edit moved an authority element, reading whichever half
|
|
150
|
+
* of the pair carries one. The delta is one list across the partition, so
|
|
151
|
+
* every consumer that serves one half alone asks this.
|
|
152
|
+
*/
|
|
153
|
+
export declare function movesAuthority(change: AssociationChange): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* A journal entry as a reader who cannot reshare sees it: the authority
|
|
156
|
+
* half of its delta dropped, the `permissions` op left standing, so the
|
|
157
|
+
* entry still names *that* the ACL moved. Passing the mutate-surface gate
|
|
158
|
+
* buys the record's content history, which is not a route to its sharing
|
|
159
|
+
* graph. See docs/spec/journal.md § Reading it.
|
|
160
|
+
*/
|
|
161
|
+
export declare function withoutAuthorityChanges(entry: RecordJournalEntry): RecordJournalEntry;
|
|
142
162
|
//# sourceMappingURL=record-changes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-changes.d.ts","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,
|
|
1
|
+
{"version":3,"file":"record-changes.d.ts","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"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"}
|
package/dist/record-changes.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* The equality 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
|
-
* Record is its tombstone, and a
|
|
10
|
-
*
|
|
9
|
+
* Record is its tombstone, and a journal entry names the ACL it moved
|
|
10
|
+
* only to a reader who could have moved it.
|
|
11
11
|
*
|
|
12
12
|
* See docs/spec/events.md § The event shape and docs/spec/versioning.md
|
|
13
13
|
* § The tombstone is literal.
|
|
@@ -19,11 +19,17 @@ import { SYSTEM_TYPES, RECORD_CHANGE_KEYS } from './types.js';
|
|
|
19
19
|
* Association identity — what dissociate() matches and a second associate()
|
|
20
20
|
* of the same reference is a repeat of. Matches the SQLite adapter's
|
|
21
21
|
* association primary key (kind, label, file_id, related_scope, related_id,
|
|
22
|
-
* related_ns, related_stack), which is why an attachment's
|
|
22
|
+
* related_ns, related_stack, related_role), which is why an attachment's
|
|
23
23
|
* `attachmentRecordId` is absent here: it annotates a reference rather than
|
|
24
|
-
* naming one.
|
|
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.
|
|
25
27
|
*/
|
|
26
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;
|
|
27
33
|
if (a.kind !== b.kind || a.label !== b.label)
|
|
28
34
|
return false;
|
|
29
35
|
if (a.kind === 'attachment' && b.kind === 'attachment')
|
|
@@ -31,8 +37,46 @@ export function associationEqual(a, b) {
|
|
|
31
37
|
if (a.kind === 'relationship' && b.kind === 'relationship') {
|
|
32
38
|
return targetEqual(a.target, b.target);
|
|
33
39
|
}
|
|
40
|
+
if (a.kind === 'permission' && b.kind === 'permission') {
|
|
41
|
+
return granteeEqual(a.grantee, b.grantee);
|
|
42
|
+
}
|
|
34
43
|
return true;
|
|
35
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.scope !== b.scope)
|
|
53
|
+
return false;
|
|
54
|
+
if (a.scope === 'entity' && b.scope === 'entity')
|
|
55
|
+
return a.entityId === b.entityId;
|
|
56
|
+
if (a.scope === 'group' && b.scope === '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
|
+
}
|
|
36
80
|
/**
|
|
37
81
|
* Identity plus every annotation outside it, so a write that only re-points
|
|
38
82
|
* an attachment association's `attachmentRecordId` still counts as a
|
|
@@ -63,23 +107,40 @@ export function stripAssociationAnnotation(association) {
|
|
|
63
107
|
}
|
|
64
108
|
/**
|
|
65
109
|
* What a `changes.associations` list moves against a record's current
|
|
66
|
-
* associations
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
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.
|
|
71
118
|
*/
|
|
72
119
|
export function associationDelta(before, after) {
|
|
73
|
-
const
|
|
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((previous) => ({ op: 'remove', previous })));
|
|
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.
|
|
137
|
+
*/
|
|
138
|
+
export function feedAssociationDelta(changes) {
|
|
74
139
|
return {
|
|
75
|
-
added,
|
|
76
|
-
removed:
|
|
77
|
-
.filter((
|
|
78
|
-
.map(stripAssociationAnnotation),
|
|
79
|
-
// An addition matching something already there by identity overwrote
|
|
80
|
-
// it rather than joining it. `removed` cannot report these: the
|
|
81
|
-
// association is still on the record, only its annotation changed.
|
|
82
|
-
replaced: added.flatMap((a) => before.filter((b) => associationEqual(a, b))),
|
|
140
|
+
added: changes.filter((c) => c.op !== 'remove').map((c) => c.association),
|
|
141
|
+
removed: changes
|
|
142
|
+
.filter((c) => c.op === 'remove')
|
|
143
|
+
.map((c) => stripAssociationAnnotation(c.previous)),
|
|
83
144
|
};
|
|
84
145
|
}
|
|
85
146
|
/** Structural equality per target arm — what dissociate() matches on. */
|
|
@@ -95,19 +156,6 @@ export function targetEqual(a, b) {
|
|
|
95
156
|
return a.ns === b.ns && a.id === b.id;
|
|
96
157
|
return false;
|
|
97
158
|
}
|
|
98
|
-
export function permissionEqual(a, b) {
|
|
99
|
-
if (a.access !== b.access)
|
|
100
|
-
return false;
|
|
101
|
-
if (a.access === 'public')
|
|
102
|
-
return true;
|
|
103
|
-
if (a.access === 'entity' && b.access === 'entity') {
|
|
104
|
-
return a.entityId === b.entityId && a.read === b.read && a.write === b.write;
|
|
105
|
-
}
|
|
106
|
-
if (a.access === 'group' && b.access === 'group') {
|
|
107
|
-
return a.groupId === b.groupId && a.role === b.role && a.read === b.read && a.write === b.write;
|
|
108
|
-
}
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
159
|
/**
|
|
112
160
|
* A change set has to name at least one aspect. Refused rather than read
|
|
113
161
|
* as a no-op: it addresses nothing, so there is nothing it could have
|
|
@@ -117,21 +165,16 @@ export function permissionEqual(a, b) {
|
|
|
117
165
|
*/
|
|
118
166
|
export function assertNonEmptyChangeSet(changes) {
|
|
119
167
|
// Presence, not truthiness: `unlisted: false` and `parentId: null` are
|
|
120
|
-
// aspects this call names
|
|
121
|
-
// change the caller asked for.
|
|
168
|
+
// aspects this call names.
|
|
122
169
|
if (RECORD_CHANGE_KEYS.some((key) => changes[key] !== undefined))
|
|
123
170
|
return;
|
|
124
171
|
throw new StackQueryError('A change set names at least one of: ' + RECORD_CHANGE_KEYS.join(', ') + '.');
|
|
125
172
|
}
|
|
126
173
|
/**
|
|
127
174
|
* Which aspects a change set actually moves, against the record as it
|
|
128
|
-
* stands
|
|
129
|
-
*
|
|
130
|
-
* already holds contributes nothing.
|
|
131
|
-
*
|
|
132
|
-
* `merged` is the content the patch produces, computed once by the
|
|
175
|
+
* stands. A key naming the value a record already holds contributes
|
|
176
|
+
* nothing. `merged` is the content the patch produces, computed once by the
|
|
133
177
|
* caller that had to validate it anyway.
|
|
134
|
-
* See docs/spec/events.md § The event shape.
|
|
135
178
|
*/
|
|
136
179
|
export function changeSetOps(existing, changes, merged) {
|
|
137
180
|
const ops = [];
|
|
@@ -140,14 +183,15 @@ export function changeSetOps(existing, changes, merged) {
|
|
|
140
183
|
if (changes.parentId !== undefined && changes.parentId !== (existing.parentId ?? null)) {
|
|
141
184
|
ops.push('reparent');
|
|
142
185
|
}
|
|
143
|
-
if (changes.permissions &&
|
|
186
|
+
if (changes.permissions &&
|
|
187
|
+
associationDelta(existing.permissions ?? [], changes.permissions).length > 0) {
|
|
144
188
|
ops.push('permissions');
|
|
145
189
|
}
|
|
146
190
|
if (changes.associations) {
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
191
|
+
const delta = associationDelta(existing.associations ?? [], changes.associations);
|
|
192
|
+
if (delta.some((c) => c.op !== 'remove'))
|
|
149
193
|
ops.push('associate');
|
|
150
|
-
if (
|
|
194
|
+
if (delta.some((c) => c.op === 'remove'))
|
|
151
195
|
ops.push('dissociate');
|
|
152
196
|
}
|
|
153
197
|
if (changes.unlisted !== undefined && Boolean(existing.unlistedAt) !== changes.unlisted) {
|
|
@@ -156,36 +200,53 @@ export function changeSetOps(existing, changes, merged) {
|
|
|
156
200
|
return ops;
|
|
157
201
|
}
|
|
158
202
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
|
|
203
|
+
* The ops whose prior state the journal already carries in full, so a
|
|
204
|
+
* snapshot would preserve nothing a restore could not otherwise reach. A
|
|
205
|
+
* change set naming only these is a no-bump write.
|
|
206
|
+
* See docs/spec/versioning.md § Version history.
|
|
207
|
+
*/
|
|
208
|
+
const NO_BUMP_OPS = new Set([
|
|
209
|
+
'associate',
|
|
210
|
+
'dissociate',
|
|
211
|
+
'permissions',
|
|
212
|
+
'reparent',
|
|
213
|
+
'unlist',
|
|
214
|
+
'list',
|
|
215
|
+
]);
|
|
216
|
+
/**
|
|
217
|
+
* Whether a change set's ops advance `version`/`updatedAt` at all. After the
|
|
218
|
+
* no-bump set above, this is `patch` and the whole-record verbs.
|
|
164
219
|
*/
|
|
165
220
|
export function bumpsVersion(ops) {
|
|
166
|
-
return ops.some((op) => op
|
|
221
|
+
return ops.some((op) => !NO_BUMP_OPS.has(op));
|
|
167
222
|
}
|
|
168
223
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
224
|
+
* The keys that guard nothing, because none of them moves `version` — a
|
|
225
|
+
* precondition on it would fence a write that the number it names cannot
|
|
226
|
+
* describe. See docs/spec/versioning.md § Optimistic concurrency.
|
|
227
|
+
*/
|
|
228
|
+
const NO_PRECONDITION_KEYS = new Set([
|
|
229
|
+
'associations',
|
|
230
|
+
'permissions',
|
|
231
|
+
'parentId',
|
|
232
|
+
'unlisted',
|
|
233
|
+
]);
|
|
234
|
+
/**
|
|
235
|
+
* Whether `ifVersion` applies to a change set. A set naming only keys from
|
|
236
|
+
* the no-precondition list above carries none; any other aspect named
|
|
237
|
+
* restores the guard over the whole call. Read off the keys the caller
|
|
238
|
+
* wrote rather than the ops the set turns out to move, so a stale caller is
|
|
239
|
+
* told its version is stale whatever its patch says.
|
|
178
240
|
*/
|
|
179
241
|
export function takesIfVersion(changes) {
|
|
180
|
-
return RECORD_CHANGE_KEYS.some((key) => key
|
|
242
|
+
return RECORD_CHANGE_KEYS.some((key) => !NO_PRECONDITION_KEYS.has(key) && changes[key] !== undefined);
|
|
181
243
|
}
|
|
182
244
|
/**
|
|
183
|
-
* The change set narrowed to the aspects that actually moved. An adapter
|
|
184
|
-
*
|
|
245
|
+
* The change set narrowed to the aspects that actually moved. An adapter is
|
|
246
|
+
* handed this rather than what the caller wrote, so restating an aspect
|
|
185
247
|
* cannot rewrite it: `unlisted: true` on an already-unlisted record would
|
|
186
|
-
* otherwise drag `unlistedAt` forward
|
|
187
|
-
*
|
|
188
|
-
* every key an adapter receives is one it must write.
|
|
248
|
+
* otherwise drag `unlistedAt` forward with no op reporting it. Every key an
|
|
249
|
+
* adapter receives is one it must write.
|
|
189
250
|
*/
|
|
190
251
|
export function effectiveChanges(changes, ops) {
|
|
191
252
|
const effective = {};
|
|
@@ -204,24 +265,16 @@ export function effectiveChanges(changes, ops) {
|
|
|
204
265
|
}
|
|
205
266
|
/**
|
|
206
267
|
* Whether a merge patch produced the content the record already held.
|
|
207
|
-
* Compared by serialization: content is JSON by construction
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* wrong answer.
|
|
268
|
+
* Compared by serialization: content is JSON by construction and a patch
|
|
269
|
+
* preserves key order for every field it does not name, so an unchanged
|
|
270
|
+
* record encodes stably. A reordering patch that changes nothing else is
|
|
271
|
+
* the one case this reports as a change, costing an empty version rather
|
|
272
|
+
* than a wrong answer.
|
|
213
273
|
*/
|
|
214
274
|
export function contentEqual(a, b) {
|
|
215
275
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
216
276
|
}
|
|
217
|
-
|
|
218
|
-
return a.length === b.length && a.every((p, i) => permissionEqual(p, b[i]));
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Ensures `creator` carries an `admin` relationship association, adding one
|
|
222
|
-
* if it's not already present. Used to bootstrap a `_group` record's first
|
|
223
|
-
* admin at create time.
|
|
224
|
-
*/
|
|
277
|
+
/** Bootstraps a `_group` record's first admin at create time. */
|
|
225
278
|
export function stampGroupAdmin(associations, creator) {
|
|
226
279
|
const list = associations ?? [];
|
|
227
280
|
const alreadyAdmin = list.some((a) => a.kind === 'relationship' &&
|
|
@@ -242,17 +295,6 @@ export function stampGroupAdmin(associations, creator) {
|
|
|
242
295
|
export function isGroupRecord(record) {
|
|
243
296
|
return baseIdOf(record.typeId) === SYSTEM_TYPES.GROUP;
|
|
244
297
|
}
|
|
245
|
-
/**
|
|
246
|
-
* Drops a snapshot's `permissions` — owner-only audit data, never served
|
|
247
|
-
* to a non-owner history reader. `entityId` (change attribution) stays.
|
|
248
|
-
* See docs/spec/versioning.md § History access.
|
|
249
|
-
*/
|
|
250
|
-
export function stripVersionPermissions(version) {
|
|
251
|
-
if (version.permissions === undefined)
|
|
252
|
-
return version;
|
|
253
|
-
const { permissions: _permissions, ...rest } = version;
|
|
254
|
-
return rest;
|
|
255
|
-
}
|
|
256
298
|
/**
|
|
257
299
|
* The tombstone a soft-deleted Record is presented as. `permissions` is
|
|
258
300
|
* retained because it decides whether the caller may undelete; history is
|
|
@@ -274,4 +316,26 @@ export function tombstoneOf(record) {
|
|
|
274
316
|
}
|
|
275
317
|
/** A soft-deleted Record presented as its tombstone; anything else untouched. */
|
|
276
318
|
export const presentDeleted = (record) => record.deletedAt ? tombstoneOf(record) : record;
|
|
319
|
+
/**
|
|
320
|
+
* Whether a tagged edit moved an authority element, reading whichever half
|
|
321
|
+
* of the pair carries one. The delta is one list across the partition, so
|
|
322
|
+
* every consumer that serves one half alone asks this.
|
|
323
|
+
*/
|
|
324
|
+
export function movesAuthority(change) {
|
|
325
|
+
return isAuthorityAssociation(change.op === 'remove' ? change.previous : change.association);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* A journal entry as a reader who cannot reshare sees it: the authority
|
|
329
|
+
* half of its delta dropped, the `permissions` op left standing, so the
|
|
330
|
+
* entry still names *that* the ACL moved. Passing the mutate-surface gate
|
|
331
|
+
* buys the record's content history, which is not a route to its sharing
|
|
332
|
+
* graph. See docs/spec/journal.md § Reading it.
|
|
333
|
+
*/
|
|
334
|
+
export function withoutAuthorityChanges(entry) {
|
|
335
|
+
if (!entry.associations?.some(movesAuthority))
|
|
336
|
+
return entry;
|
|
337
|
+
const data = entry.associations.filter((c) => !movesAuthority(c));
|
|
338
|
+
const { associations: _authority, ...rest } = entry;
|
|
339
|
+
return data.length ? { ...rest, associations: data } : rest;
|
|
340
|
+
}
|
|
277
341
|
//# sourceMappingURL=record-changes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-changes.js","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"record-changes.js","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"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"}
|