@graview/core 0.1.3 → 0.1.4
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/dist/app.d.ts +9 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js.map +1 -1
- package/dist/capabilities.js +1 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/cli/check/policy.d.ts.map +1 -1
- package/dist/cli/check/policy.js +40 -0
- package/dist/cli/check/policy.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/document/canonical.d.ts +2 -1
- package/dist/document/canonical.d.ts.map +1 -1
- package/dist/document/canonical.js +2 -1
- package/dist/document/canonical.js.map +1 -1
- package/dist/document/diff.d.ts.map +1 -1
- package/dist/document/diff.js +3 -1
- package/dist/document/diff.js.map +1 -1
- package/dist/document/edit.d.ts +7 -1
- package/dist/document/edit.d.ts.map +1 -1
- package/dist/document/edit.js +46 -2
- package/dist/document/edit.js.map +1 -1
- package/dist/document/index.d.ts +1 -1
- package/dist/document/index.d.ts.map +1 -1
- package/dist/document/migrate.d.ts.map +1 -1
- package/dist/document/migrate.js +3 -2
- package/dist/document/migrate.js.map +1 -1
- package/dist/document/patch.d.ts.map +1 -1
- package/dist/document/patch.js +2 -5
- package/dist/document/patch.js.map +1 -1
- package/dist/document/schema.d.ts +10 -10
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/integrity.d.ts.map +1 -1
- package/dist/integrity.js +35 -5
- package/dist/integrity.js.map +1 -1
- package/dist/invariants/types.d.ts +1 -1
- package/dist/invariants/types.d.ts.map +1 -1
- package/dist/mutations/define-mutation.d.ts +22 -2
- package/dist/mutations/define-mutation.d.ts.map +1 -1
- package/dist/mutations/define-mutation.js +18 -5
- package/dist/mutations/define-mutation.js.map +1 -1
- package/dist/mutations/node-ref.d.ts +5 -2
- package/dist/mutations/node-ref.d.ts.map +1 -1
- package/dist/mutations/node-ref.js +28 -7
- package/dist/mutations/node-ref.js.map +1 -1
- package/dist/mutations/types.d.ts +2 -2
- package/dist/mutations/types.d.ts.map +1 -1
- package/dist/ops/log.d.ts +11 -0
- package/dist/ops/log.d.ts.map +1 -1
- package/dist/ops/log.js.map +1 -1
- package/dist/ops/served.d.ts +80 -0
- package/dist/ops/served.d.ts.map +1 -0
- package/dist/ops/served.js +316 -0
- package/dist/ops/served.js.map +1 -0
- package/dist/ops/types.d.ts +8 -0
- package/dist/ops/types.d.ts.map +1 -1
- package/dist/ops/withheld.d.ts +63 -8
- package/dist/ops/withheld.d.ts.map +1 -1
- package/dist/ops/withheld.js +198 -22
- package/dist/ops/withheld.js.map +1 -1
- package/dist/ops/writers.d.ts +29 -0
- package/dist/ops/writers.d.ts.map +1 -0
- package/dist/ops/writers.js +98 -0
- package/dist/ops/writers.js.map +1 -0
- package/dist/permissions/sight.d.ts +15 -2
- package/dist/permissions/sight.d.ts.map +1 -1
- package/dist/permissions/sight.js +34 -5
- package/dist/permissions/sight.js.map +1 -1
- package/dist/presence.d.ts +24 -2
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +26 -1
- package/dist/presence.js.map +1 -1
- package/dist/refusal.d.ts +9 -5
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +9 -5
- package/dist/refusal.js.map +1 -1
- package/dist/schema/json-schema.d.ts.map +1 -1
- package/dist/schema/json-schema.js +27 -1
- package/dist/schema/json-schema.js.map +1 -1
- package/dist/schema/schema.d.ts +19 -4
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js.map +1 -1
- package/dist/seen.d.ts +54 -1
- package/dist/seen.d.ts.map +1 -1
- package/dist/seen.js +457 -25
- package/dist/seen.js.map +1 -1
- package/dist/store.d.ts +90 -10
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +146 -35
- package/dist/store.js.map +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/ops/withheld.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Primitive } from "../graph/primitives.js";
|
|
2
|
+
import { type FieldWriter, type Timeline } from "./served.js";
|
|
2
3
|
import type { Author, Operation } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* A LOG A SEAT MAY NOT FULLY SEE IS REDACTED, NOT GAPPED (FR-16).
|
|
@@ -17,6 +18,52 @@ export declare const WITHHELD_AUTHOR: Author;
|
|
|
17
18
|
export declare function isWithheld(op: Pick<Operation, "withheld">): boolean;
|
|
18
19
|
/** The record ids a primitive touches. */
|
|
19
20
|
export declare function touchedBy(primitive: Primitive): readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* WHAT ONE SEAT IS SERVED (FR-55): the judgement a log is redacted by.
|
|
23
|
+
* `sees` is the seat's sight — the ids it may be told. `shows` is what it
|
|
24
|
+
* is served: a record it sees, unless a field the record cannot do without
|
|
25
|
+
* names one it may not see. `served` is a record as the seat receives it,
|
|
26
|
+
* and `optional` says whether a kind's field may be left off one. A bare
|
|
27
|
+
* `(id) => boolean` is a lens that clears nothing: a record whose field
|
|
28
|
+
* names an unseen id is not served at all.
|
|
29
|
+
*/
|
|
30
|
+
export interface SeatLens {
|
|
31
|
+
readonly sees: (id: string) => boolean;
|
|
32
|
+
readonly shows: (id: string) => boolean;
|
|
33
|
+
readonly served: <N extends {
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly kind: string;
|
|
36
|
+
}>(node: N) => N | undefined;
|
|
37
|
+
/** A record as the seat is served it, given who wrote each field's value: the seat's own words are served as written (FR-55). */
|
|
38
|
+
readonly servedWith: <N extends {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly kind: string;
|
|
41
|
+
}>(node: N, writer: FieldWriter) => N | undefined;
|
|
42
|
+
/** The seat whose words these are — the person, for an agent acting for one. */
|
|
43
|
+
readonly actor?: string;
|
|
44
|
+
readonly optional: (kind: string, field: string) => boolean;
|
|
45
|
+
/** The kind of a record, by id, when it is known: for a patch, whose primitive does not say. */
|
|
46
|
+
readonly kindOf: (id: string) => string | undefined;
|
|
47
|
+
/** The store's graph now and the log that led to it, so an op is judged where it stood (`serveAlong`). */
|
|
48
|
+
readonly timeline?: Timeline;
|
|
49
|
+
/**
|
|
50
|
+
* THIS LENS AS OF NOW, ITS JUDGEMENTS KEPT: each id judged once, each
|
|
51
|
+
* record served once, for one reading of a store that does not change
|
|
52
|
+
* while it is read — a log redacted, a snapshot served. A lens follows
|
|
53
|
+
* the store as it is asked (FR-51); a pinned one is thrown away after the
|
|
54
|
+
* reading it was made for, so it never answers for a store that moved.
|
|
55
|
+
*/
|
|
56
|
+
readonly pin?: () => SeatLens;
|
|
57
|
+
}
|
|
58
|
+
/** A lens over a bare sight: it serves a record whole or not at all. */
|
|
59
|
+
export declare function lensOf(seeing: SeatLens | ((id: string) => boolean)): SeatLens;
|
|
60
|
+
/**
|
|
61
|
+
* WHETHER A VALUE NAMES ANYTHING THE SEAT MAY NOT SEE (FR-55): any string
|
|
62
|
+
* in it, at any depth, a value or a key, that is an unseen record's id. An
|
|
63
|
+
* id is minted from a label, so an id a seat is served is the name of what
|
|
64
|
+
* it was kept from.
|
|
65
|
+
*/
|
|
66
|
+
export declare function namesUnseen(value: unknown, sees: (id: string) => boolean): boolean;
|
|
20
67
|
/**
|
|
21
68
|
* Whether an op touched, read or named anything `sees` says no to: then it
|
|
22
69
|
* is withheld whole, because its sentence ("Book a test drive for Freya")
|
|
@@ -26,12 +73,20 @@ export declare function touchesUnseen(op: Operation, sees: (id: string) => boole
|
|
|
26
73
|
/**
|
|
27
74
|
* THE OP AS A SEAT THAT MAY NOT SEE IT RECEIVES IT. Its id, seq, batch and
|
|
28
75
|
* time stand; who made it, what it meant, the call and the inverse go. Its
|
|
29
|
-
* primitives keep the ones that touch only what the seat
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
76
|
+
* primitives keep the ones that touch only what the seat is served, as it
|
|
77
|
+
* is served them (FR-55) — a change to a record the seat can see still
|
|
78
|
+
* reaches it, or its copy of the graph would go stale, and no id of what it
|
|
79
|
+
* may not see rides along in a field — and its reads and writes keep only
|
|
80
|
+
* served ids, so an undo the seat asks for is still blocked by it where it
|
|
81
|
+
* should be.
|
|
82
|
+
*/
|
|
83
|
+
export declare function withhold(op: Operation, seeing: SeatLens | ((id: string) => boolean), served?: readonly Primitive[]): Operation;
|
|
84
|
+
/**
|
|
85
|
+
* Every op of a log as a seat receives it: what it may see as it is, the
|
|
86
|
+
* rest withheld in place. An op is withheld when it touches a record the
|
|
87
|
+
* seat is not served, or names one it may not see ANYWHERE — its call, its
|
|
88
|
+
* sentence, its author, a field value in a primitive or its inverse
|
|
89
|
+
* (FR-55). One withheld already is withheld again under this seat's lens.
|
|
33
90
|
*/
|
|
34
|
-
export declare function
|
|
35
|
-
/** Every op of a log as a seat receives it: what it may see as it is, the rest withheld in place. */
|
|
36
|
-
export declare function redact(ops: readonly Operation[], sees: (id: string) => boolean): Operation[];
|
|
91
|
+
export declare function redact(ops: readonly Operation[], seeing: SeatLens | ((id: string) => boolean)): Operation[];
|
|
37
92
|
//# sourceMappingURL=withheld.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withheld.d.ts","sourceRoot":"","sources":["../../src/ops/withheld.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"withheld.d.ts","sourceRoot":"","sources":["../../src/ops/withheld.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAI/D,OAAO,EAAc,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;;;;;GAQG;AAEH,+DAA+D;AAC/D,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD,0EAA0E;AAC1E,eAAO,MAAM,eAAe,EAAE,MAA4D,CAAC;AAE3F,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,OAAO,CAEnE;AAED,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,MAAM,EAAE,CAWjE;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IACtG,iIAAiI;IACjI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,CAAC,GAAG,SAAS,CAAC;IAC/H,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5D,gGAAgG;IAChG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,0GAA0G;IAC1G,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,QAAQ,CAAC;CAC/B;AAMD,wEAAwE;AACxE,wBAAgB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,QAAQ,CAW7E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAalF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAInF;AAwCD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAsB9H;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,EAAE,CAmB3G"}
|
package/dist/ops/withheld.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { UNSET } from "../graph/primitives.js";
|
|
2
|
+
import { actingAs } from "../permissions/policy.js";
|
|
3
|
+
import { serveAlong } from "./served.js";
|
|
1
4
|
/**
|
|
2
5
|
* A LOG A SEAT MAY NOT FULLY SEE IS REDACTED, NOT GAPPED (FR-16).
|
|
3
6
|
*
|
|
@@ -28,17 +31,47 @@ export function touchedBy(primitive) {
|
|
|
28
31
|
return [primitive.edge.from, primitive.edge.to];
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
34
|
+
/** Whether any field of a record — not its id or kind — names what `sees` says no to. */
|
|
35
|
+
const fieldsNameUnseen = (node, sees) => Object.entries(node).some(([key, value]) => key !== "id" && key !== "kind" && namesUnseen(value, sees));
|
|
36
|
+
/** A lens over a bare sight: it serves a record whole or not at all. */
|
|
37
|
+
export function lensOf(seeing) {
|
|
38
|
+
if (typeof seeing !== "function")
|
|
39
|
+
return seeing;
|
|
40
|
+
const sees = seeing;
|
|
41
|
+
return {
|
|
42
|
+
sees,
|
|
43
|
+
shows: sees,
|
|
44
|
+
served: (node) => (sees(node.id) && !fieldsNameUnseen(node, sees) ? node : undefined),
|
|
45
|
+
servedWith: (node) => (sees(node.id) && !fieldsNameUnseen(node, sees) ? node : undefined),
|
|
46
|
+
optional: () => false,
|
|
47
|
+
kindOf: () => undefined,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* WHETHER A VALUE NAMES ANYTHING THE SEAT MAY NOT SEE (FR-55): any string
|
|
52
|
+
* in it, at any depth, a value or a key, that is an unseen record's id. An
|
|
53
|
+
* id is minted from a label, so an id a seat is served is the name of what
|
|
54
|
+
* it was kept from.
|
|
55
|
+
*/
|
|
56
|
+
export function namesUnseen(value, sees) {
|
|
33
57
|
if (typeof value === "string")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
for (
|
|
40
|
-
|
|
41
|
-
|
|
58
|
+
return !sees(value);
|
|
59
|
+
if (value === null || typeof value !== "object")
|
|
60
|
+
return false;
|
|
61
|
+
// Walked without copying: a served log asks this of every op in it.
|
|
62
|
+
if (Array.isArray(value)) {
|
|
63
|
+
for (let at = 0; at < value.length; at++)
|
|
64
|
+
if (namesUnseen(value[at], sees))
|
|
65
|
+
return true;
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
for (const key in value) {
|
|
69
|
+
if (!Object.hasOwn(value, key))
|
|
70
|
+
continue;
|
|
71
|
+
if (!sees(key) || namesUnseen(value[key], sees))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
42
75
|
}
|
|
43
76
|
/**
|
|
44
77
|
* Whether an op touched, read or named anything `sees` says no to: then it
|
|
@@ -50,17 +83,62 @@ export function touchesUnseen(op, sees) {
|
|
|
50
83
|
return true;
|
|
51
84
|
if (op.writes.some((id) => !sees(id)) || op.reads.some((id) => !sees(id)))
|
|
52
85
|
return true;
|
|
53
|
-
return op.mutation !== null &&
|
|
86
|
+
return op.mutation !== null && namesUnseen(op.mutation.args, sees);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A PRIMITIVE AS A SEAT RECEIVES IT, or nothing (FR-55). One that touches a
|
|
90
|
+
* record the seat is not served goes. A record it adds is served as the
|
|
91
|
+
* seat's view serves it — a field naming an unseen record cleared, or the
|
|
92
|
+
* primitive dropped when that field is one the record cannot do without,
|
|
93
|
+
* so a client never adds a record that fails its own declaration. A patch
|
|
94
|
+
* that wrote such a field says the field was cleared, as the view shows
|
|
95
|
+
* it; one it cannot clear goes. A removal needs only the record's id.
|
|
96
|
+
*/
|
|
97
|
+
function servedPrimitive(primitive, lens) {
|
|
98
|
+
if (!touchedBy(primitive).every(lens.shows))
|
|
99
|
+
return undefined;
|
|
100
|
+
switch (primitive.op) {
|
|
101
|
+
case "add-node": {
|
|
102
|
+
const node = lens.served(primitive.node);
|
|
103
|
+
return node ? (node === primitive.node ? primitive : { op: "add-node", node }) : undefined;
|
|
104
|
+
}
|
|
105
|
+
case "remove-node": {
|
|
106
|
+
const node = primitive.node;
|
|
107
|
+
if (!fieldsNameUnseen(node, lens.sees))
|
|
108
|
+
return primitive;
|
|
109
|
+
return { op: "remove-node", node: Object.fromEntries(Object.entries(node).filter(([key, value]) => key === "id" || key === "kind" || !namesUnseen(value, lens.sees))) };
|
|
110
|
+
}
|
|
111
|
+
case "patch-node": {
|
|
112
|
+
const kind = lens.kindOf(primitive.id);
|
|
113
|
+
const after = {};
|
|
114
|
+
for (const [field, value] of Object.entries(primitive.after)) {
|
|
115
|
+
if (!namesUnseen(value, lens.sees))
|
|
116
|
+
after[field] = value;
|
|
117
|
+
else if (kind !== undefined && lens.optional(kind, field))
|
|
118
|
+
after[field] = UNSET;
|
|
119
|
+
else
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const before = Object.fromEntries(Object.entries(primitive.before).filter(([, value]) => !namesUnseen(value, lens.sees)));
|
|
123
|
+
return { op: "patch-node", id: primitive.id, before, after };
|
|
124
|
+
}
|
|
125
|
+
case "add-edge":
|
|
126
|
+
case "remove-edge":
|
|
127
|
+
return namesUnseen(primitive.edge, lens.sees) ? undefined : primitive;
|
|
128
|
+
}
|
|
54
129
|
}
|
|
55
130
|
/**
|
|
56
131
|
* THE OP AS A SEAT THAT MAY NOT SEE IT RECEIVES IT. Its id, seq, batch and
|
|
57
132
|
* time stand; who made it, what it meant, the call and the inverse go. Its
|
|
58
|
-
* primitives keep the ones that touch only what the seat
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
133
|
+
* primitives keep the ones that touch only what the seat is served, as it
|
|
134
|
+
* is served them (FR-55) — a change to a record the seat can see still
|
|
135
|
+
* reaches it, or its copy of the graph would go stale, and no id of what it
|
|
136
|
+
* may not see rides along in a field — and its reads and writes keep only
|
|
137
|
+
* served ids, so an undo the seat asks for is still blocked by it where it
|
|
138
|
+
* should be.
|
|
62
139
|
*/
|
|
63
|
-
export function withhold(op,
|
|
140
|
+
export function withhold(op, seeing, served) {
|
|
141
|
+
const lens = lensOf(seeing);
|
|
64
142
|
return {
|
|
65
143
|
id: op.id,
|
|
66
144
|
seq: op.seq,
|
|
@@ -68,17 +146,115 @@ export function withhold(op, sees) {
|
|
|
68
146
|
author: WITHHELD_AUTHOR,
|
|
69
147
|
intent: WITHHELD_INTENT,
|
|
70
148
|
mutation: null,
|
|
71
|
-
primitives:
|
|
149
|
+
primitives: served ??
|
|
150
|
+
op.primitives.flatMap((primitive) => {
|
|
151
|
+
const one = servedPrimitive(primitive, lens);
|
|
152
|
+
return one ? [one] : [];
|
|
153
|
+
}),
|
|
72
154
|
inverse: [],
|
|
73
|
-
reads: op.reads.filter(
|
|
74
|
-
writes: op.writes.filter(
|
|
155
|
+
reads: op.reads.filter((id) => lens.shows(id) && isRecord(lens, id)),
|
|
156
|
+
writes: op.writes.filter((id) => lens.shows(id) && isRecord(lens, id)),
|
|
75
157
|
at: op.at,
|
|
76
158
|
...(op.undoes !== undefined ? { undoes: op.undoes } : {}),
|
|
77
159
|
withheld: true,
|
|
78
160
|
};
|
|
79
161
|
}
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Every op of a log as a seat receives it: what it may see as it is, the
|
|
164
|
+
* rest withheld in place. An op is withheld when it touches a record the
|
|
165
|
+
* seat is not served, or names one it may not see ANYWHERE — its call, its
|
|
166
|
+
* sentence, its author, a field value in a primitive or its inverse
|
|
167
|
+
* (FR-55). One withheld already is withheld again under this seat's lens.
|
|
168
|
+
*/
|
|
169
|
+
export function redact(ops, seeing) {
|
|
170
|
+
// One reading of the store, whatever its length: every id and record judged once in it.
|
|
171
|
+
const given = lensOf(seeing);
|
|
172
|
+
const lens = given.pin?.() ?? given;
|
|
173
|
+
/*
|
|
174
|
+
* ALONG THE STORE'S HISTORY, when the lens knows it: each primitive judged
|
|
175
|
+
* by whether its record was served just before it and just after, so the
|
|
176
|
+
* ops a seat is served fold to the snapshot it is served (`serveAlong`).
|
|
177
|
+
*/
|
|
178
|
+
if (lens.timeline) {
|
|
179
|
+
const judge = {
|
|
180
|
+
served: (node, writer) => lens.servedWith(node, writer),
|
|
181
|
+
edgeClean: (edge) => !namesUnseen(edge, lens.sees),
|
|
182
|
+
sees: lens.sees,
|
|
183
|
+
names: (value) => namesUnseen(value, lens.sees),
|
|
184
|
+
};
|
|
185
|
+
return serveAlong(ops, lens.timeline, judge).map(({ op, primitives, faithful }) => (!op.withheld && faithful ? whole(op, lens, primitives) : undefined) ?? withhold(op, lens, primitives));
|
|
186
|
+
}
|
|
187
|
+
return ops.map((op) => (!op.withheld && !touchesUnseen(op, lens.shows) ? whole(op, lens) : undefined) ?? withhold(op, lens));
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* AN OP SERVED WHOLE, when what it did is all the seat's to know: as it is
|
|
191
|
+
* when it names nothing hidden, and with its reads and writes trimmed of
|
|
192
|
+
* what is hidden when that is the only place it does — what it looked at
|
|
193
|
+
* is not the seat's to be told, what it did is. A string its primitives are
|
|
194
|
+
* served with, as the seat is served them, is the seat's to read anywhere
|
|
195
|
+
* in it — a field value the seat wrote, in a patch and in the inverse that
|
|
196
|
+
* would put it back — and so is its call, when the call was the seat's own
|
|
197
|
+
* (FR-55). Otherwise its call, sentence, author and inverse are not
|
|
198
|
+
* trimmed: an act's sentence is made from its call ("Compare with Freya
|
|
199
|
+
* Davies"), so one that names a hidden record anywhere withholds the op.
|
|
200
|
+
*/
|
|
201
|
+
function whole(op, lens, served) {
|
|
202
|
+
/*
|
|
203
|
+
* WHAT IT READ, AS RECORDS THE SEAT SEES (FR-55). An act that looked for a
|
|
204
|
+
* record that is not there read its absence, and one that looked for a
|
|
205
|
+
* hidden one read nothing the seat may be told: both are left out alike,
|
|
206
|
+
* or the reads of a seat's own act would say which guess was real.
|
|
207
|
+
*/
|
|
208
|
+
const kept = (id) => lens.sees(id) && isRecord(lens, id);
|
|
209
|
+
const reads = op.reads.filter(kept);
|
|
210
|
+
const writes = op.writes.filter(kept);
|
|
211
|
+
const tidy = reads.length === op.reads.length && writes.length === op.writes.length ? op : { ...op, reads, writes };
|
|
212
|
+
/*
|
|
213
|
+
* ANOTHER AUTHOR'S SENTENCE, ONLY IF ITS READER SEES WHAT IT READ. A
|
|
214
|
+
* sentence names records by their labels, which no id check catches;
|
|
215
|
+
* the op says which records its `describe` read, and a seat that may not
|
|
216
|
+
* see one of them is served the op withheld. The seat's own sentences
|
|
217
|
+
* were worded from its own view.
|
|
218
|
+
*/
|
|
219
|
+
const own = lens.actor !== undefined && actingAs(op.author).id === lens.actor;
|
|
220
|
+
if (!own && op.described?.some((id) => !lens.sees(id)))
|
|
221
|
+
return undefined;
|
|
222
|
+
if (!namesUnseen(op, lens.sees))
|
|
223
|
+
return tidy;
|
|
224
|
+
const said = new Set();
|
|
225
|
+
const collect = (value) => {
|
|
226
|
+
if (typeof value === "string")
|
|
227
|
+
said.add(value);
|
|
228
|
+
else if (Array.isArray(value))
|
|
229
|
+
for (const inner of value)
|
|
230
|
+
collect(inner);
|
|
231
|
+
else if (value !== null && typeof value === "object")
|
|
232
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
233
|
+
said.add(key);
|
|
234
|
+
collect(inner);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
/*
|
|
238
|
+
* THE SEAT'S OWN WORDS EXCUSE ONLY WHAT IT WROTE. A value the primitives
|
|
239
|
+
* are served with (the seat wrote it, or it would have been cleared) may
|
|
240
|
+
* stand in the inverse that puts it back; the call may name what the
|
|
241
|
+
* seat said only when the call is the seat's own. Another author's call,
|
|
242
|
+
* sentence and name are judged by sight alone, whatever the seat wrote.
|
|
243
|
+
*/
|
|
244
|
+
if (served)
|
|
245
|
+
collect(served);
|
|
246
|
+
const told = (id) => lens.sees(id) || said.has(id);
|
|
247
|
+
if (namesUnseen(tidy.inverse, told))
|
|
248
|
+
return undefined;
|
|
249
|
+
if (own) {
|
|
250
|
+
if (op.mutation)
|
|
251
|
+
collect(op.mutation.args);
|
|
252
|
+
return namesUnseen({ ...tidy, primitives: [], inverse: [] }, told) ? undefined : tidy;
|
|
253
|
+
}
|
|
254
|
+
return namesUnseen({ ...tidy, primitives: [], inverse: [] }, lens.sees) ? undefined : tidy;
|
|
255
|
+
}
|
|
256
|
+
/** Whether an id names a record the store knows — in the graph or its log — when the lens can say; a bare sight cannot, and keeps every id. */
|
|
257
|
+
function isRecord(lens, id) {
|
|
258
|
+
return lens.timeline === undefined || lens.kindOf(id) !== undefined;
|
|
83
259
|
}
|
|
84
260
|
//# sourceMappingURL=withheld.js.map
|
package/dist/ops/withheld.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withheld.js","sourceRoot":"","sources":["../../src/ops/withheld.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"withheld.js","sourceRoot":"","sources":["../../src/ops/withheld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Operation } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* WHO WROTE EACH FIELD'S VALUE, AND WHEN (FR-55).
|
|
4
|
+
*
|
|
5
|
+
* A seat is served its own words: a field whose value the seat wrote is
|
|
6
|
+
* served as written even when it names a record the seat may not see,
|
|
7
|
+
* because saying back what a seat said tells it nothing — and judging it
|
|
8
|
+
* like anybody else's would tell a seat that guessed an id whether the
|
|
9
|
+
* guess was real. So the seat view has to know who wrote a field's value,
|
|
10
|
+
* at the moment it is served and at every moment of the log it serves.
|
|
11
|
+
*
|
|
12
|
+
* Each op that writes a field is an entry: the seq, and the seat that wrote
|
|
13
|
+
* it — the person, for an agent acting for one. An undo is never the
|
|
14
|
+
* author of what it puts back: the value it restores is the words of
|
|
15
|
+
* whoever wrote it before the op it takes back. Kept as the log goes, like
|
|
16
|
+
* `recordsOf`: a call reads only the ops appended since the last, a log cut
|
|
17
|
+
* back takes out what its cut ops wrote, and a log compacted behind its
|
|
18
|
+
* horizon keeps what was read before it.
|
|
19
|
+
*/
|
|
20
|
+
export interface Writers {
|
|
21
|
+
/** Who wrote the value a field held just before op `seq` ran; `undefined` when nobody this log knows. */
|
|
22
|
+
writerAt(id: string, field: string, seq: number): string | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Who wrote each field's value in a log, kept as the log goes (see `Writers`). */
|
|
25
|
+
export declare function writersOf(log: {
|
|
26
|
+
all(): readonly Operation[];
|
|
27
|
+
readonly length?: number;
|
|
28
|
+
}): Writers;
|
|
29
|
+
//# sourceMappingURL=writers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writers.d.ts","sourceRoot":"","sources":["../../src/ops/writers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,OAAO;IACtB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACtE;AAiFD,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,GAAG,EAAE;IAAE,GAAG,IAAI,SAAS,SAAS,EAAE,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAoBjG"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isUnset } from "../graph/primitives.js";
|
|
2
|
+
import { actingAs } from "../permissions/policy.js";
|
|
3
|
+
const keyOf = (id, field) => `${id}\u0000${field}`;
|
|
4
|
+
const INDEXES = new WeakMap();
|
|
5
|
+
function indexFrom(base) {
|
|
6
|
+
const fields = new Map();
|
|
7
|
+
const writerAt = (id, field, seq) => {
|
|
8
|
+
const entries = fields.get(keyOf(id, field));
|
|
9
|
+
if (!entries)
|
|
10
|
+
return undefined;
|
|
11
|
+
let low = 0;
|
|
12
|
+
let high = entries.length;
|
|
13
|
+
while (low < high) {
|
|
14
|
+
const middle = (low + high) >> 1;
|
|
15
|
+
if (entries[middle].seq < seq)
|
|
16
|
+
low = middle + 1;
|
|
17
|
+
else
|
|
18
|
+
high = middle;
|
|
19
|
+
}
|
|
20
|
+
return low === 0 ? undefined : entries[low - 1].by;
|
|
21
|
+
};
|
|
22
|
+
return { base, end: base, read: [], fields, written: [], seqOf: new Map(), writers: { writerAt } };
|
|
23
|
+
}
|
|
24
|
+
/** The fields one primitive writes, by record. */
|
|
25
|
+
function writtenBy(primitive) {
|
|
26
|
+
if (primitive.op === "add-node")
|
|
27
|
+
return [primitive.node.id, Object.keys(primitive.node).filter((field) => field !== "id" && field !== "kind")];
|
|
28
|
+
if (primitive.op === "patch-node")
|
|
29
|
+
return [primitive.id, Object.keys(primitive.after).filter((field) => !isUnset(primitive.after[field]))];
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function readInto(index, op) {
|
|
33
|
+
const seq = index.end;
|
|
34
|
+
const author = actingAs(op.author).id;
|
|
35
|
+
// What an undo puts back is the words of whoever wrote them before the op it takes back.
|
|
36
|
+
const undone = op.undoes !== undefined ? index.seqOf.get(op.undoes) : undefined;
|
|
37
|
+
const keys = [];
|
|
38
|
+
for (const primitive of op.primitives) {
|
|
39
|
+
const written = writtenBy(primitive);
|
|
40
|
+
if (!written)
|
|
41
|
+
continue;
|
|
42
|
+
const [id, fields] = written;
|
|
43
|
+
for (const field of fields) {
|
|
44
|
+
const by = op.undoes === undefined ? author : undone !== undefined ? index.writers.writerAt(id, field, undone) : undefined;
|
|
45
|
+
const key = keyOf(id, field);
|
|
46
|
+
let entries = index.fields.get(key);
|
|
47
|
+
if (!entries)
|
|
48
|
+
index.fields.set(key, (entries = []));
|
|
49
|
+
entries.push({ seq, by });
|
|
50
|
+
keys.push(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
index.written.push({ seq, keys });
|
|
54
|
+
index.seqOf.set(op.id, seq);
|
|
55
|
+
index.read.push(op);
|
|
56
|
+
index.end++;
|
|
57
|
+
}
|
|
58
|
+
function cutBack(index, seq) {
|
|
59
|
+
while (index.written.length > 0 && index.written.at(-1).seq >= seq) {
|
|
60
|
+
const { keys } = index.written.pop();
|
|
61
|
+
for (const key of keys)
|
|
62
|
+
index.fields.get(key)?.pop();
|
|
63
|
+
}
|
|
64
|
+
for (const op of index.read.slice(seq - index.base))
|
|
65
|
+
index.seqOf.delete(op.id);
|
|
66
|
+
index.read.length = seq - index.base;
|
|
67
|
+
index.end = seq;
|
|
68
|
+
}
|
|
69
|
+
/** Who wrote each field's value in a log, kept as the log goes (see `Writers`). */
|
|
70
|
+
export function writersOf(log) {
|
|
71
|
+
const ops = log.all();
|
|
72
|
+
const end = typeof log.length === "number" ? log.length : ops.length;
|
|
73
|
+
const first = end - ops.length;
|
|
74
|
+
let index = INDEXES.get(log);
|
|
75
|
+
if (index && index.base <= first && first <= index.end) {
|
|
76
|
+
let agreed = Math.min(index.end, end);
|
|
77
|
+
while (agreed > first && ops[agreed - 1 - first] !== index.read[agreed - 1 - index.base])
|
|
78
|
+
agreed--;
|
|
79
|
+
if (agreed === first && first > index.base && agreed < index.end)
|
|
80
|
+
index = undefined;
|
|
81
|
+
else {
|
|
82
|
+
if (agreed < index.end)
|
|
83
|
+
cutBack(index, agreed);
|
|
84
|
+
if (first > index.base) {
|
|
85
|
+
index.read = index.read.slice(first - index.base);
|
|
86
|
+
index.base = first;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else
|
|
91
|
+
index = undefined;
|
|
92
|
+
if (!index)
|
|
93
|
+
INDEXES.set(log, (index = indexFrom(first)));
|
|
94
|
+
for (let seq = index.end; seq < end; seq++)
|
|
95
|
+
readInto(index, ops[seq - first]);
|
|
96
|
+
return index.writers;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=writers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writers.js","sourceRoot":"","sources":["../../src/ops/writers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Epoch } from "../ops/log.js";
|
|
1
2
|
import type { Operation } from "../ops/types.js";
|
|
2
3
|
import type { Policy, Principal } from "./types.js";
|
|
3
4
|
/** The edges a graph can be asked about, to say what is joined to whom. */
|
|
@@ -25,6 +26,8 @@ export interface RecordedLog {
|
|
|
25
26
|
all(): readonly Operation[];
|
|
26
27
|
/** The seq the next op takes, counting what a compaction archived; without it, the ops it holds. */
|
|
27
28
|
readonly length?: number;
|
|
29
|
+
/** Its epochs, for a log compacted behind a checkpoint that names who made what behind it (`Epoch.creators`). */
|
|
30
|
+
epochs?(): readonly Epoch[];
|
|
28
31
|
}
|
|
29
32
|
/**
|
|
30
33
|
* The records a log names, read from its add- and remove-node primitives.
|
|
@@ -38,12 +41,22 @@ export interface RecordedLog {
|
|
|
38
41
|
* is taken out, back to where the log and the index still agree. A log
|
|
39
42
|
* compacted behind its horizon (FR-23) keeps what the index had already
|
|
40
43
|
* read of the archived ops, so a record made behind the horizon is still
|
|
41
|
-
* known by its maker for as long as this log is open
|
|
42
|
-
* compacted never read them
|
|
44
|
+
* known by its maker for as long as this log is open. A log OPENED
|
|
45
|
+
* compacted never read them: it knows them from its checkpoint, which keeps
|
|
46
|
+
* who made each record behind it (`Epoch.creators`, written by
|
|
47
|
+
* `store.checkpoint`), and a checkpoint without that (one written before it
|
|
48
|
+
* existed) leaves it knowing its makers from the horizon on.
|
|
43
49
|
* The `Records` returned is the same object every time, and answers as of
|
|
44
50
|
* the last call.
|
|
45
51
|
*/
|
|
46
52
|
export declare function recordsOf(log: RecordedLog): Records;
|
|
53
|
+
/**
|
|
54
|
+
* WHO MADE EACH RECORD BEFORE `seq`, as a checkpoint at `seq` keeps it
|
|
55
|
+
* (`Epoch.creators`): record id to the seat that first added it, in the
|
|
56
|
+
* order they were made — what the log's checkpoint already kept, then what
|
|
57
|
+
* the ops it holds before `seq` add.
|
|
58
|
+
*/
|
|
59
|
+
export declare function creatorsBefore(log: RecordedLog, seq: number): Record<string, string>;
|
|
47
60
|
/**
|
|
48
61
|
* Whether a principal may see one record.
|
|
49
62
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sight.d.ts","sourceRoot":"","sources":["../../src/permissions/sight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAS,MAAM,YAAY,CAAC;AAE3D,2EAA2E;AAC3E,UAAU,MAAM;IACd,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpD,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACpD;AAKD,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAE5E;AAED;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC,wFAAwF;IACxF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,0GAA0G;AAC1G,MAAM,WAAW,WAAW;IAC1B,GAAG,IAAI,SAAS,SAAS,EAAE,CAAC;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"sight.d.ts","sourceRoot":"","sources":["../../src/permissions/sight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAS,MAAM,YAAY,CAAC;AAE3D,2EAA2E;AAC3E,UAAU,MAAM;IACd,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpD,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACpD;AAKD,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAE5E;AAED;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC,wFAAwF;IACxF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,0GAA0G;AAC1G,MAAM,WAAW,WAAW;IAC1B,GAAG,IAAI,SAAS,SAAS,EAAE,CAAC;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iHAAiH;IACjH,MAAM,CAAC,IAAI,SAAS,KAAK,EAAE,CAAC;CAC7B;AA2DD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAwBnD;AAQD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpD,KAAK,EAAE,MAAM;AACb,gFAAgF;AAChF,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,GACnC,OAAO,CAmBT"}
|
|
@@ -5,9 +5,10 @@ export function sightedKinds(policy) {
|
|
|
5
5
|
return new Set((policy?.sees ?? []).flatMap((sight) => sight.kinds));
|
|
6
6
|
}
|
|
7
7
|
const INDEXES = new WeakMap();
|
|
8
|
-
|
|
8
|
+
/** A fresh index for a log that begins at seq `base`, knowing the makers its checkpoint kept behind it. */
|
|
9
|
+
function indexFrom(base, behind) {
|
|
9
10
|
const kinds = new Map();
|
|
10
|
-
const creators = new Map();
|
|
11
|
+
const creators = new Map(Object.entries(behind ?? {}));
|
|
11
12
|
return { base, end: base, read: [], kinds, creators, entries: [], records: { kindOf: (id) => kinds.get(id), creatorOf: (id) => creators.get(id) } };
|
|
12
13
|
}
|
|
13
14
|
/** Reads one op into the index: the kind of each record it first adds or removes, and who first made one. */
|
|
@@ -53,8 +54,11 @@ function cutBack(index, seq) {
|
|
|
53
54
|
* is taken out, back to where the log and the index still agree. A log
|
|
54
55
|
* compacted behind its horizon (FR-23) keeps what the index had already
|
|
55
56
|
* read of the archived ops, so a record made behind the horizon is still
|
|
56
|
-
* known by its maker for as long as this log is open
|
|
57
|
-
* compacted never read them
|
|
57
|
+
* known by its maker for as long as this log is open. A log OPENED
|
|
58
|
+
* compacted never read them: it knows them from its checkpoint, which keeps
|
|
59
|
+
* who made each record behind it (`Epoch.creators`, written by
|
|
60
|
+
* `store.checkpoint`), and a checkpoint without that (one written before it
|
|
61
|
+
* existed) leaves it knowing its makers from the horizon on.
|
|
58
62
|
* The `Records` returned is the same object every time, and answers as of
|
|
59
63
|
* the last call.
|
|
60
64
|
*/
|
|
@@ -85,11 +89,36 @@ export function recordsOf(log) {
|
|
|
85
89
|
else
|
|
86
90
|
index = undefined;
|
|
87
91
|
if (!index)
|
|
88
|
-
INDEXES.set(log, (index = indexFrom(first)));
|
|
92
|
+
INDEXES.set(log, (index = indexFrom(first, first > 0 ? checkpointOf(log, first)?.creators : undefined)));
|
|
89
93
|
for (let seq = index.end; seq < end; seq++)
|
|
90
94
|
readInto(index, ops[seq - first]);
|
|
91
95
|
return index.records;
|
|
92
96
|
}
|
|
97
|
+
/** The checkpoint a log compacted at `seq` begins from: the last epoch marked `horizon`, when it is there. */
|
|
98
|
+
function checkpointOf(log, seq) {
|
|
99
|
+
const checkpoint = [...(log.epochs?.() ?? [])].reverse().find((epoch) => epoch.horizon);
|
|
100
|
+
return checkpoint?.seq === seq ? checkpoint : undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* WHO MADE EACH RECORD BEFORE `seq`, as a checkpoint at `seq` keeps it
|
|
104
|
+
* (`Epoch.creators`): record id to the seat that first added it, in the
|
|
105
|
+
* order they were made — what the log's checkpoint already kept, then what
|
|
106
|
+
* the ops it holds before `seq` add.
|
|
107
|
+
*/
|
|
108
|
+
export function creatorsBefore(log, seq) {
|
|
109
|
+
recordsOf(log);
|
|
110
|
+
const index = INDEXES.get(log);
|
|
111
|
+
const after = new Set();
|
|
112
|
+
for (let at = index.entries.length - 1; at >= 0 && index.entries[at].seq >= seq; at--) {
|
|
113
|
+
if (index.entries[at].creator)
|
|
114
|
+
after.add(index.entries[at].id);
|
|
115
|
+
}
|
|
116
|
+
const creators = {};
|
|
117
|
+
for (const [id, by] of index.creators)
|
|
118
|
+
if (!after.has(id))
|
|
119
|
+
creators[id] = by;
|
|
120
|
+
return creators;
|
|
121
|
+
}
|
|
93
122
|
/**
|
|
94
123
|
* Whether a principal may see one record.
|
|
95
124
|
*
|