@graview/core 0.1.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/LICENSE +96 -0
- package/README.md +35 -0
- package/dist/app.d.ts +294 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +49 -0
- package/dist/app.js.map +1 -0
- package/dist/arrange.d.ts +185 -0
- package/dist/arrange.d.ts.map +1 -0
- package/dist/arrange.js +456 -0
- package/dist/arrange.js.map +1 -0
- package/dist/beginning.d.ts +65 -0
- package/dist/beginning.d.ts.map +1 -0
- package/dist/beginning.js +94 -0
- package/dist/beginning.js.map +1 -0
- package/dist/bind.d.ts +42 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +26 -0
- package/dist/bind.js.map +1 -0
- package/dist/city.d.ts +93 -0
- package/dist/city.d.ts.map +1 -0
- package/dist/city.js +160 -0
- package/dist/city.js.map +1 -0
- package/dist/cli/check/arrangement.d.ts +13 -0
- package/dist/cli/check/arrangement.d.ts.map +1 -0
- package/dist/cli/check/arrangement.js +63 -0
- package/dist/cli/check/arrangement.js.map +1 -0
- package/dist/cli/check/beginnings.d.ts +16 -0
- package/dist/cli/check/beginnings.d.ts.map +1 -0
- package/dist/cli/check/beginnings.js +53 -0
- package/dist/cli/check/beginnings.js.map +1 -0
- package/dist/cli/check/brand.d.ts +17 -0
- package/dist/cli/check/brand.d.ts.map +1 -0
- package/dist/cli/check/brand.js +153 -0
- package/dist/cli/check/brand.js.map +1 -0
- package/dist/cli/check/city.d.ts +17 -0
- package/dist/cli/check/city.d.ts.map +1 -0
- package/dist/cli/check/city.js +58 -0
- package/dist/cli/check/city.js.map +1 -0
- package/dist/cli/check/context.d.ts +50 -0
- package/dist/cli/check/context.d.ts.map +1 -0
- package/dist/cli/check/context.js +37 -0
- package/dist/cli/check/context.js.map +1 -0
- package/dist/cli/check/fields.d.ts +16 -0
- package/dist/cli/check/fields.d.ts.map +1 -0
- package/dist/cli/check/fields.js +237 -0
- package/dist/cli/check/fields.js.map +1 -0
- package/dist/cli/check/index.d.ts +14 -0
- package/dist/cli/check/index.d.ts.map +1 -0
- package/dist/cli/check/index.js +14 -0
- package/dist/cli/check/index.js.map +1 -0
- package/dist/cli/check/intelligence.d.ts +17 -0
- package/dist/cli/check/intelligence.d.ts.map +1 -0
- package/dist/cli/check/intelligence.js +136 -0
- package/dist/cli/check/intelligence.js.map +1 -0
- package/dist/cli/check/lenses.d.ts +17 -0
- package/dist/cli/check/lenses.d.ts.map +1 -0
- package/dist/cli/check/lenses.js +239 -0
- package/dist/cli/check/lenses.js.map +1 -0
- package/dist/cli/check/migrations.d.ts +16 -0
- package/dist/cli/check/migrations.d.ts.map +1 -0
- package/dist/cli/check/migrations.js +43 -0
- package/dist/cli/check/migrations.js.map +1 -0
- package/dist/cli/check/modules.d.ts +16 -0
- package/dist/cli/check/modules.d.ts.map +1 -0
- package/dist/cli/check/modules.js +123 -0
- package/dist/cli/check/modules.js.map +1 -0
- package/dist/cli/check/policy.d.ts +16 -0
- package/dist/cli/check/policy.d.ts.map +1 -0
- package/dist/cli/check/policy.js +90 -0
- package/dist/cli/check/policy.js.map +1 -0
- package/dist/cli/check/relations.d.ts +29 -0
- package/dist/cli/check/relations.d.ts.map +1 -0
- package/dist/cli/check/relations.js +279 -0
- package/dist/cli/check/relations.js.map +1 -0
- package/dist/cli/check/routes.d.ts +16 -0
- package/dist/cli/check/routes.d.ts.map +1 -0
- package/dist/cli/check/routes.js +31 -0
- package/dist/cli/check/routes.js.map +1 -0
- package/dist/cli/check/settings.d.ts +16 -0
- package/dist/cli/check/settings.d.ts.map +1 -0
- package/dist/cli/check/settings.js +81 -0
- package/dist/cli/check/settings.js.map +1 -0
- package/dist/cli/check.d.ts +36 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +76 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/create.d.ts +20 -0
- package/dist/cli/create.d.ts.map +1 -0
- package/dist/cli/create.js +251 -0
- package/dist/cli/create.js.map +1 -0
- package/dist/cli/describe.d.ts +35 -0
- package/dist/cli/describe.d.ts.map +1 -0
- package/dist/cli/describe.js +230 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/docs.d.ts +11 -0
- package/dist/cli/docs.d.ts.map +1 -0
- package/dist/cli/docs.js +152 -0
- package/dist/cli/docs.js.map +1 -0
- package/dist/cli/index.d.ts +18 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +281 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/extend.d.ts +23 -0
- package/dist/extend.d.ts.map +1 -0
- package/dist/extend.js +53 -0
- package/dist/extend.js.map +1 -0
- package/dist/graph/diff.d.ts +31 -0
- package/dist/graph/diff.d.ts.map +1 -0
- package/dist/graph/diff.js +71 -0
- package/dist/graph/diff.js.map +1 -0
- package/dist/graph/graph.d.ts +69 -0
- package/dist/graph/graph.d.ts.map +1 -0
- package/dist/graph/graph.js +284 -0
- package/dist/graph/graph.js.map +1 -0
- package/dist/graph/primitives.d.ts +52 -0
- package/dist/graph/primitives.d.ts.map +1 -0
- package/dist/graph/primitives.js +62 -0
- package/dist/graph/primitives.js.map +1 -0
- package/dist/graph/tracked.d.ts +31 -0
- package/dist/graph/tracked.d.ts.map +1 -0
- package/dist/graph/tracked.js +69 -0
- package/dist/graph/tracked.js.map +1 -0
- package/dist/graph/types.d.ts +34 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +0 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/installation.d.ts +112 -0
- package/dist/installation.d.ts.map +1 -0
- package/dist/installation.js +193 -0
- package/dist/installation.js.map +1 -0
- package/dist/intelligence-bridge.d.ts +73 -0
- package/dist/intelligence-bridge.d.ts.map +1 -0
- package/dist/intelligence-bridge.js +31 -0
- package/dist/intelligence-bridge.js.map +1 -0
- package/dist/invariants/engine.d.ts +36 -0
- package/dist/invariants/engine.d.ts.map +1 -0
- package/dist/invariants/engine.js +88 -0
- package/dist/invariants/engine.js.map +1 -0
- package/dist/invariants/types.d.ts +75 -0
- package/dist/invariants/types.d.ts.map +1 -0
- package/dist/invariants/types.js +2 -0
- package/dist/invariants/types.js.map +1 -0
- package/dist/modules.d.ts +75 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +87 -0
- package/dist/modules.js.map +1 -0
- package/dist/mutations/decidable.d.ts +26 -0
- package/dist/mutations/decidable.d.ts.map +1 -0
- package/dist/mutations/decidable.js +39 -0
- package/dist/mutations/decidable.js.map +1 -0
- package/dist/mutations/define-mutation.d.ts +32 -0
- package/dist/mutations/define-mutation.d.ts.map +1 -0
- package/dist/mutations/define-mutation.js +181 -0
- package/dist/mutations/define-mutation.js.map +1 -0
- package/dist/mutations/derive-edits.d.ts +75 -0
- package/dist/mutations/derive-edits.d.ts.map +1 -0
- package/dist/mutations/derive-edits.js +240 -0
- package/dist/mutations/derive-edits.js.map +1 -0
- package/dist/mutations/form.d.ts +63 -0
- package/dist/mutations/form.d.ts.map +1 -0
- package/dist/mutations/form.js +113 -0
- package/dist/mutations/form.js.map +1 -0
- package/dist/mutations/node-ref.d.ts +83 -0
- package/dist/mutations/node-ref.d.ts.map +1 -0
- package/dist/mutations/node-ref.js +113 -0
- package/dist/mutations/node-ref.js.map +1 -0
- package/dist/mutations/types.d.ts +136 -0
- package/dist/mutations/types.d.ts.map +1 -0
- package/dist/mutations/types.js +2 -0
- package/dist/mutations/types.js.map +1 -0
- package/dist/ops/log.d.ts +35 -0
- package/dist/ops/log.d.ts.map +1 -0
- package/dist/ops/log.js +103 -0
- package/dist/ops/log.js.map +1 -0
- package/dist/ops/types.d.ts +52 -0
- package/dist/ops/types.d.ts.map +1 -0
- package/dist/ops/types.js +2 -0
- package/dist/ops/types.js.map +1 -0
- package/dist/ops/undo.d.ts +33 -0
- package/dist/ops/undo.d.ts.map +1 -0
- package/dist/ops/undo.js +65 -0
- package/dist/ops/undo.js.map +1 -0
- package/dist/permissions/policy.d.ts +68 -0
- package/dist/permissions/policy.d.ts.map +1 -0
- package/dist/permissions/policy.js +191 -0
- package/dist/permissions/policy.js.map +1 -0
- package/dist/permissions/types.d.ts +78 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/persistence/memory.d.ts +6 -0
- package/dist/persistence/memory.d.ts.map +1 -0
- package/dist/persistence/memory.js +31 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +59 -0
- package/dist/persistence/sqlite.d.ts.map +1 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/persistence/types.d.ts +22 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +2 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/presence.d.ts +38 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +50 -0
- package/dist/presence.js.map +1 -0
- package/dist/scaffold/domain.d.ts +8 -0
- package/dist/scaffold/domain.d.ts.map +1 -0
- package/dist/scaffold/domain.js +331 -0
- package/dist/scaffold/domain.js.map +1 -0
- package/dist/scaffold/index.d.ts +66 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +142 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/lens.d.ts +31 -0
- package/dist/scaffold/lens.d.ts.map +1 -0
- package/dist/scaffold/lens.js +176 -0
- package/dist/scaffold/lens.js.map +1 -0
- package/dist/scaffold/names.d.ts +44 -0
- package/dist/scaffold/names.d.ts.map +1 -0
- package/dist/scaffold/names.js +69 -0
- package/dist/scaffold/names.js.map +1 -0
- package/dist/scaffold/project.d.ts +41 -0
- package/dist/scaffold/project.d.ts.map +1 -0
- package/dist/scaffold/project.js +604 -0
- package/dist/scaffold/project.js.map +1 -0
- package/dist/scaffold/ui.d.ts +15 -0
- package/dist/scaffold/ui.d.ts.map +1 -0
- package/dist/scaffold/ui.js +536 -0
- package/dist/scaffold/ui.js.map +1 -0
- package/dist/schema/define-node.d.ts +132 -0
- package/dist/schema/define-node.d.ts.map +1 -0
- package/dist/schema/define-node.js +254 -0
- package/dist/schema/define-node.js.map +1 -0
- package/dist/schema/figures.d.ts +42 -0
- package/dist/schema/figures.d.ts.map +1 -0
- package/dist/schema/figures.js +220 -0
- package/dist/schema/figures.js.map +1 -0
- package/dist/schema/json-schema.d.ts +39 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +74 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/schema.d.ts +43 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +102 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/types.d.ts +201 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +2 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/search.d.ts +215 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +449 -0
- package/dist/search.js.map +1 -0
- package/dist/settings.d.ts +30 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +74 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.d.ts +284 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +660 -0
- package/dist/store.js.map +1 -0
- package/dist/studio-door.d.ts +187 -0
- package/dist/studio-door.d.ts.map +1 -0
- package/dist/studio-door.js +20 -0
- package/dist/studio-door.js.map +1 -0
- package/dist/sync/conflict.d.ts +37 -0
- package/dist/sync/conflict.d.ts.map +1 -0
- package/dist/sync/conflict.js +56 -0
- package/dist/sync/conflict.js.map +1 -0
- package/dist/sync/engine.d.ts +118 -0
- package/dist/sync/engine.d.ts.map +1 -0
- package/dist/sync/engine.js +341 -0
- package/dist/sync/engine.js.map +1 -0
- package/dist/sync/google-calendar.d.ts +54 -0
- package/dist/sync/google-calendar.d.ts.map +1 -0
- package/dist/sync/google-calendar.js +167 -0
- package/dist/sync/google-calendar.js.map +1 -0
- package/dist/sync/types.d.ts +125 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +6 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/temporal/effectivity.d.ts +75 -0
- package/dist/temporal/effectivity.d.ts.map +1 -0
- package/dist/temporal/effectivity.js +89 -0
- package/dist/temporal/effectivity.js.map +1 -0
- package/dist/testing.d.ts +63 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +194 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme/contrast.d.ts +47 -0
- package/dist/theme/contrast.d.ts.map +1 -0
- package/dist/theme/contrast.js +172 -0
- package/dist/theme/contrast.js.map +1 -0
- package/dist/theme/derive.d.ts +81 -0
- package/dist/theme/derive.d.ts.map +1 -0
- package/dist/theme/derive.js +171 -0
- package/dist/theme/derive.js.map +1 -0
- package/dist/theme/kit.d.ts +106 -0
- package/dist/theme/kit.d.ts.map +1 -0
- package/dist/theme/kit.js +84 -0
- package/dist/theme/kit.js.map +1 -0
- package/dist/theme/palettes.d.ts +32 -0
- package/dist/theme/palettes.d.ts.map +1 -0
- package/dist/theme/palettes.js +96 -0
- package/dist/theme/palettes.js.map +1 -0
- package/dist/theme/types.d.ts +131 -0
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +23 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/views/types.d.ts +89 -0
- package/dist/views/types.d.ts.map +1 -0
- package/dist/views/types.js +88 -0
- package/dist/views/types.js.map +1 -0
- package/dist/watched.d.ts +33 -0
- package/dist/watched.d.ts.map +1 -0
- package/dist/watched.js +50 -0
- package/dist/watched.js.map +1 -0
- package/dist/who.d.ts +26 -0
- package/dist/who.d.ts.map +1 -0
- package/dist/who.js +20 -0
- package/dist/who.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Primitive } from "../graph/primitives.js";
|
|
2
|
+
import type { MutationCall } from "../mutations/types.js";
|
|
3
|
+
export interface Author {
|
|
4
|
+
/**
|
|
5
|
+
* Who moved: a person, an agent acting on their behalf, a rule repairing
|
|
6
|
+
* something, or an external system of record whose change arrived here.
|
|
7
|
+
*
|
|
8
|
+
* `system` earns its place for the same reason the others do: an inbound
|
|
9
|
+
* calendar change is an ordinary op, appears in the activity list beside a
|
|
10
|
+
* person's edits, and is undone like anything else. A sync layer that wrote
|
|
11
|
+
* the graph outside the log would be the one kind of change nobody could
|
|
12
|
+
* see or take back.
|
|
13
|
+
*/
|
|
14
|
+
readonly kind: "human" | "agent" | "rule" | "system";
|
|
15
|
+
readonly id?: string;
|
|
16
|
+
readonly session?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One entry in the append-only log. The graph is a fold over these.
|
|
20
|
+
*
|
|
21
|
+
* `reads` is what turns undo from a stack into a dependency graph, and it
|
|
22
|
+
* has to be captured when the op runs — historical reads are not
|
|
23
|
+
* recoverable, so this field can never be backfilled.
|
|
24
|
+
*/
|
|
25
|
+
export interface Operation {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
/** Monotonic position in the log. */
|
|
28
|
+
readonly seq: number;
|
|
29
|
+
/** One user gesture, or one agent turn. */
|
|
30
|
+
readonly batch: string;
|
|
31
|
+
readonly author: Author;
|
|
32
|
+
/** Human-readable statement of what was meant, not what changed. */
|
|
33
|
+
readonly intent: string;
|
|
34
|
+
readonly mutation: MutationCall | null;
|
|
35
|
+
readonly primitives: readonly Primitive[];
|
|
36
|
+
readonly inverse: readonly Primitive[];
|
|
37
|
+
readonly reads: readonly string[];
|
|
38
|
+
readonly writes: readonly string[];
|
|
39
|
+
readonly at: string;
|
|
40
|
+
/** Set when this op exists to undo another one. */
|
|
41
|
+
readonly undoes?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface Batch {
|
|
44
|
+
readonly id: string;
|
|
45
|
+
readonly author: Author;
|
|
46
|
+
readonly intent: string;
|
|
47
|
+
readonly at: string;
|
|
48
|
+
readonly ops: readonly Operation[];
|
|
49
|
+
/** True when every op in the batch has been inverted by a later op. */
|
|
50
|
+
readonly undone: boolean;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ops/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,MAAM;IACrB;;;;;;;;;OASG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,CAAC;IACnC,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ops/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { OperationLog } from "./log.js";
|
|
2
|
+
import type { Operation } from "./types.js";
|
|
3
|
+
export interface UndoBlock {
|
|
4
|
+
/** The op that read something the undo target wrote. */
|
|
5
|
+
readonly op: Operation;
|
|
6
|
+
/** The node ids it read that the target wrote. */
|
|
7
|
+
readonly overlap: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export type UndoCheck = {
|
|
10
|
+
readonly ok: true;
|
|
11
|
+
readonly ops: readonly Operation[];
|
|
12
|
+
} | {
|
|
13
|
+
readonly ok: false;
|
|
14
|
+
readonly ops: readonly Operation[];
|
|
15
|
+
readonly blockedBy: readonly UndoBlock[];
|
|
16
|
+
/** Batches that would have to come along for the undo to be legal. */
|
|
17
|
+
readonly includeBatches: readonly string[];
|
|
18
|
+
readonly message: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Undoing an op out of order is legal exactly when no later live op read
|
|
22
|
+
* something it wrote. That is a checkable condition rather than a policy —
|
|
23
|
+
* so when it fails the framework can name the blocking op and offer to bring
|
|
24
|
+
* it along, instead of refusing or corrupting state.
|
|
25
|
+
*/
|
|
26
|
+
export declare function checkUndo(log: OperationLog, batchIds: readonly string[]): UndoCheck;
|
|
27
|
+
/**
|
|
28
|
+
* The primitives an undo would apply: each op's stored inverse, newest first,
|
|
29
|
+
* so dependent writes come apart in the order they went together. (An op's
|
|
30
|
+
* `inverse` is already reversed internally when the op is recorded.)
|
|
31
|
+
*/
|
|
32
|
+
export declare function undoPrimitives(ops: readonly Operation[]): import("../index.js").Primitive[];
|
|
33
|
+
//# sourceMappingURL=undo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/ops/undo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GACzD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;IACzC,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,SAAS,CAgDX;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,qCAEvD"}
|
package/dist/ops/undo.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Undoing an op out of order is legal exactly when no later live op read
|
|
3
|
+
* something it wrote. That is a checkable condition rather than a policy —
|
|
4
|
+
* so when it fails the framework can name the blocking op and offer to bring
|
|
5
|
+
* it along, instead of refusing or corrupting state.
|
|
6
|
+
*/
|
|
7
|
+
export function checkUndo(log, batchIds) {
|
|
8
|
+
const targets = new Set(batchIds);
|
|
9
|
+
const undone = log.undoneIds();
|
|
10
|
+
const ops = log
|
|
11
|
+
.all()
|
|
12
|
+
.filter((op) => targets.has(op.batch) && !undone.has(op.id));
|
|
13
|
+
if (ops.length === 0) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
ops,
|
|
17
|
+
blockedBy: [],
|
|
18
|
+
includeBatches: [],
|
|
19
|
+
message: batchIds.length === 0
|
|
20
|
+
? "No batch given to undo"
|
|
21
|
+
: `Nothing live to undo in ${batchIds.join(", ")} — already undone, or never applied`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const writes = new Set();
|
|
25
|
+
for (const op of ops)
|
|
26
|
+
for (const id of op.writes)
|
|
27
|
+
writes.add(id);
|
|
28
|
+
const earliest = Math.min(...ops.map((op) => op.seq));
|
|
29
|
+
const blockedBy = [];
|
|
30
|
+
for (const op of log.all()) {
|
|
31
|
+
if (op.seq <= earliest)
|
|
32
|
+
continue;
|
|
33
|
+
if (targets.has(op.batch))
|
|
34
|
+
continue;
|
|
35
|
+
if (undone.has(op.id))
|
|
36
|
+
continue;
|
|
37
|
+
const overlap = op.reads.filter((id) => writes.has(id));
|
|
38
|
+
if (overlap.length > 0)
|
|
39
|
+
blockedBy.push({ op, overlap });
|
|
40
|
+
}
|
|
41
|
+
if (blockedBy.length === 0)
|
|
42
|
+
return { ok: true, ops };
|
|
43
|
+
const includeBatches = [...new Set(blockedBy.map((b) => b.op.batch))];
|
|
44
|
+
const named = blockedBy
|
|
45
|
+
.map((b) => `"${b.op.intent}" (op ${b.op.id}, read ${b.overlap.join(", ")})`)
|
|
46
|
+
.join("; ");
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
ops,
|
|
50
|
+
blockedBy,
|
|
51
|
+
includeBatches,
|
|
52
|
+
message: `Cannot undo on its own — a later operation depends on it: ${named}. Include ${includeBatches
|
|
53
|
+
.map((id) => `batch ${id}`)
|
|
54
|
+
.join(", ")} to undo them together.`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The primitives an undo would apply: each op's stored inverse, newest first,
|
|
59
|
+
* so dependent writes come apart in the order they went together. (An op's
|
|
60
|
+
* `inverse` is already reversed internally when the op is recorded.)
|
|
61
|
+
*/
|
|
62
|
+
export function undoPrimitives(ops) {
|
|
63
|
+
return [...ops].sort((a, b) => b.seq - a.seq).flatMap((op) => op.inverse);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=undo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/ops/undo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { AnyMutationDefinition } from "../mutations/types.js";
|
|
2
|
+
import type { AnySchema } from "../schema/schema.js";
|
|
3
|
+
import type { Policy, Principal, Refusal } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* WHAT A REFUSAL CALLS THINGS. The policy knows acts and roles by their
|
|
6
|
+
* names; a person reads "Not permitted: close-deal on a deal — sales-manager
|
|
7
|
+
* can" struck through beside every button they may not press. The store
|
|
8
|
+
* hands its titles and nouns ("“Close the deal” on a deal — a sales manager
|
|
9
|
+
* can"); a role is always said in words.
|
|
10
|
+
*/
|
|
11
|
+
export interface PolicyWords {
|
|
12
|
+
readonly act?: (mutation: string) => string | undefined;
|
|
13
|
+
readonly noun?: (kind: string) => string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether a principal may run a mutation, and if not, who could.
|
|
17
|
+
*
|
|
18
|
+
* `kind` is the subject's kind when the call names one. A grant restricted by
|
|
19
|
+
* kind and a call whose subject cannot be resolved is refused rather than
|
|
20
|
+
* allowed: the safe reading of "I could not tell what this acts on" is no.
|
|
21
|
+
*/
|
|
22
|
+
export declare function permits(policy: Policy | undefined, principal: Principal, mutation: string, kind?: string,
|
|
23
|
+
/**
|
|
24
|
+
* Declared mutations any ONE of which being permitted permits this one.
|
|
25
|
+
* How a derived edit act is judged: whoever may already change or make a
|
|
26
|
+
* kind may change what was set when it was made — the policy's own grants,
|
|
27
|
+
* read again, rather than a second list.
|
|
28
|
+
*/
|
|
29
|
+
via?: readonly string[],
|
|
30
|
+
/**
|
|
31
|
+
* The id of the node the call acts on, when it names one. A `self` grant
|
|
32
|
+
* is only ever satisfied when this is the principal's own id.
|
|
33
|
+
*/
|
|
34
|
+
subjectId?: string,
|
|
35
|
+
/** How the refusal names an act and a kind: the store hands its titles and nouns. */
|
|
36
|
+
words?: PolicyWords): {
|
|
37
|
+
readonly ok: true;
|
|
38
|
+
} | {
|
|
39
|
+
readonly ok: false;
|
|
40
|
+
readonly refusal: Refusal;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* WHY, IN THE POLICY'S OWN WORDS.
|
|
44
|
+
*
|
|
45
|
+
* A grant carries a `describe` — documented from the day it was added as
|
|
46
|
+
* "shown when an action is withheld, so a refusal can say something useful"
|
|
47
|
+
* — and nothing read it. Every refusal in every surface was assembled from a
|
|
48
|
+
* mutation id and a list of role names, which is what the declaration says,
|
|
49
|
+
* not what the organisation means. The sentences of the grants that WOULD
|
|
50
|
+
* allow this are the ones worth repeating.
|
|
51
|
+
*/
|
|
52
|
+
export declare function whyNot(policy: Policy, mutation: string, kind?: string): readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* Every role that could run this mutation, so a refusal can name what would
|
|
55
|
+
* be needed instead of merely saying no.
|
|
56
|
+
*/
|
|
57
|
+
export declare function rolesWhoCould(policy: Policy, mutation: string, kind?: string): readonly string[];
|
|
58
|
+
/** Every role the policy mentions, declared or implied by its grants. */
|
|
59
|
+
export declare function rolesOf(policy: Policy): readonly string[];
|
|
60
|
+
/**
|
|
61
|
+
* The mutations a principal may run at all, ignoring any particular subject.
|
|
62
|
+
*
|
|
63
|
+
* This is what narrows an agent seat's generated tool schema: a seat holding
|
|
64
|
+
* a principal gets tools for what that principal can do, and there is no
|
|
65
|
+
* second list to keep in step.
|
|
66
|
+
*/
|
|
67
|
+
export declare function permittedMutations<S extends AnySchema>(policy: Policy | undefined, principal: Principal, mutations: readonly AnyMutationDefinition<S>[]): readonly AnyMutationDefinition<S>[];
|
|
68
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/permissions/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAS,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAWpE;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAQD;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM;AACb;;;;;GAKG;AACH,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE;AACvB;;;GAGG;AACH,SAAS,CAAC,EAAE,MAAM;AAClB,qFAAqF;AACrF,KAAK,GAAE,WAAgB,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA8D3E;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAUzF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,SAAS,MAAM,EAAE,CAcnB;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAQzD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,EACpD,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,qBAAqB,CAAC,CAAC,CAAC,EAAE,GAC7C,SAAS,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAUrC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { humaniseField, withArticle } from "../schema/define-node.js";
|
|
2
|
+
const matches = (allowed, value) => allowed === "*" || allowed.includes(value);
|
|
3
|
+
/** Whether a grant covers a principal at all, before looking at the call. */
|
|
4
|
+
function grantsTo(grant, principal) {
|
|
5
|
+
if (grant.roles === "*")
|
|
6
|
+
return true;
|
|
7
|
+
return (principal.roles ?? []).some((role) => grant.roles.includes(role));
|
|
8
|
+
}
|
|
9
|
+
/** "a sales manager", "a sales manager or a salesperson". */
|
|
10
|
+
function rolesSaid(roles) {
|
|
11
|
+
const spoken = roles.map((role) => withArticle(humaniseField(role).toLowerCase()));
|
|
12
|
+
return spoken.length <= 1 ? (spoken[0] ?? "") : `${spoken.slice(0, -1).join(", ")} or ${spoken[spoken.length - 1]}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether a principal may run a mutation, and if not, who could.
|
|
16
|
+
*
|
|
17
|
+
* `kind` is the subject's kind when the call names one. A grant restricted by
|
|
18
|
+
* kind and a call whose subject cannot be resolved is refused rather than
|
|
19
|
+
* allowed: the safe reading of "I could not tell what this acts on" is no.
|
|
20
|
+
*/
|
|
21
|
+
export function permits(policy, principal, mutation, kind,
|
|
22
|
+
/**
|
|
23
|
+
* Declared mutations any ONE of which being permitted permits this one.
|
|
24
|
+
* How a derived edit act is judged: whoever may already change or make a
|
|
25
|
+
* kind may change what was set when it was made — the policy's own grants,
|
|
26
|
+
* read again, rather than a second list.
|
|
27
|
+
*/
|
|
28
|
+
via,
|
|
29
|
+
/**
|
|
30
|
+
* The id of the node the call acts on, when it names one. A `self` grant
|
|
31
|
+
* is only ever satisfied when this is the principal's own id.
|
|
32
|
+
*/
|
|
33
|
+
subjectId,
|
|
34
|
+
/** How the refusal names an act and a kind: the store hands its titles and nouns. */
|
|
35
|
+
words = {}) {
|
|
36
|
+
// No policy means permission is not a concern in this installation.
|
|
37
|
+
if (!policy)
|
|
38
|
+
return { ok: true };
|
|
39
|
+
/*
|
|
40
|
+
* A derived act is permitted when the policy names it (or says `*`) —
|
|
41
|
+
* the grants are read first, as for any act — and otherwise when any of
|
|
42
|
+
* the declared acts it rides is permitted for this principal on this kind.
|
|
43
|
+
*/
|
|
44
|
+
if (via !== undefined) {
|
|
45
|
+
if (permits(policy, principal, mutation, kind, undefined, subjectId).ok)
|
|
46
|
+
return { ok: true };
|
|
47
|
+
if (via.some((name) => permits(policy, principal, name, kind, undefined, subjectId).ok))
|
|
48
|
+
return { ok: true };
|
|
49
|
+
/*
|
|
50
|
+
* A derived edit is reachable two ways, and the refusal has to count
|
|
51
|
+
* both: a grant naming it (or saying `*`), and a grant on any declared
|
|
52
|
+
* act it rides. Counting only the second said "no declared act writes or
|
|
53
|
+
* creates it, so no role can" to a rider while the driver's `mutations:
|
|
54
|
+
* "*"` grant plainly reached it.
|
|
55
|
+
*/
|
|
56
|
+
const names = [mutation, ...via];
|
|
57
|
+
const wouldNeed = [
|
|
58
|
+
...new Set(names.flatMap((name) => rolesWhoCould(policy, name, kind))),
|
|
59
|
+
].sort();
|
|
60
|
+
const who = wouldNeed.length === 0
|
|
61
|
+
? via.length === 0
|
|
62
|
+
? "no declared act creates or changes it, so no role can"
|
|
63
|
+
: "no role can"
|
|
64
|
+
: `${rolesSaid(wouldNeed)} can`;
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
refusal: {
|
|
68
|
+
mutation,
|
|
69
|
+
...(kind === undefined ? {} : { kind }),
|
|
70
|
+
wouldNeed,
|
|
71
|
+
message: said(policy, names, kind, who, words),
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
for (const grant of policy.grants) {
|
|
76
|
+
if (!grantsTo(grant, principal))
|
|
77
|
+
continue;
|
|
78
|
+
if (!matches(grant.mutations, mutation))
|
|
79
|
+
continue;
|
|
80
|
+
if (grant.kinds !== undefined && grant.kinds !== "*") {
|
|
81
|
+
if (kind === undefined || !grant.kinds.includes(kind))
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// "You, on yours": a self grant needs the subject to be the principal.
|
|
85
|
+
if (grant.self && (subjectId === undefined || principal.id === undefined || subjectId !== principal.id))
|
|
86
|
+
continue;
|
|
87
|
+
return { ok: true };
|
|
88
|
+
}
|
|
89
|
+
const wouldNeed = rolesWhoCould(policy, mutation, kind);
|
|
90
|
+
const who = wouldNeed.length === 0 ? "no role can" : `${rolesSaid(wouldNeed)} can`;
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
refusal: {
|
|
94
|
+
mutation,
|
|
95
|
+
...(kind === undefined ? {} : { kind }),
|
|
96
|
+
wouldNeed,
|
|
97
|
+
message: said(policy, [mutation], kind, who, words),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The refusal in words: what it was, who could, and why the policy says so.
|
|
103
|
+
*
|
|
104
|
+
* `names` is every act that would have reached this one, because a derived
|
|
105
|
+
* edit rides the acts that write its fields — and the sentence has to come
|
|
106
|
+
* from the same grants the roles did, or the two halves contradict.
|
|
107
|
+
*/
|
|
108
|
+
function said(policy, names, kind, who, words) {
|
|
109
|
+
const because = [...new Set(names.flatMap((name) => whyNot(policy, name, kind)))];
|
|
110
|
+
const act = words.act?.(names[0]);
|
|
111
|
+
return (`Not permitted: ${act ? `“${act}”` : names[0]}${kind ? ` on ${withArticle(words.noun?.(kind) ?? kind)}` : ""} — ${who}.` +
|
|
112
|
+
(because.length > 0 ? ` ${because.join(" ")}` : ""));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* WHY, IN THE POLICY'S OWN WORDS.
|
|
116
|
+
*
|
|
117
|
+
* A grant carries a `describe` — documented from the day it was added as
|
|
118
|
+
* "shown when an action is withheld, so a refusal can say something useful"
|
|
119
|
+
* — and nothing read it. Every refusal in every surface was assembled from a
|
|
120
|
+
* mutation id and a list of role names, which is what the declaration says,
|
|
121
|
+
* not what the organisation means. The sentences of the grants that WOULD
|
|
122
|
+
* allow this are the ones worth repeating.
|
|
123
|
+
*/
|
|
124
|
+
export function whyNot(policy, mutation, kind) {
|
|
125
|
+
const said = new Set();
|
|
126
|
+
for (const grant of policy.grants) {
|
|
127
|
+
if (!matches(grant.mutations, mutation))
|
|
128
|
+
continue;
|
|
129
|
+
if (grant.kinds !== undefined && grant.kinds !== "*" && kind !== undefined) {
|
|
130
|
+
if (!grant.kinds.includes(kind))
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (grant.describe)
|
|
134
|
+
said.add(grant.describe);
|
|
135
|
+
}
|
|
136
|
+
return [...said];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Every role that could run this mutation, so a refusal can name what would
|
|
140
|
+
* be needed instead of merely saying no.
|
|
141
|
+
*/
|
|
142
|
+
export function rolesWhoCould(policy, mutation, kind) {
|
|
143
|
+
const roles = new Set();
|
|
144
|
+
for (const grant of policy.grants) {
|
|
145
|
+
if (!matches(grant.mutations, mutation))
|
|
146
|
+
continue;
|
|
147
|
+
if (grant.kinds !== undefined && grant.kinds !== "*" && kind !== undefined) {
|
|
148
|
+
if (!grant.kinds.includes(kind))
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (grant.roles === "*") {
|
|
152
|
+
// Everyone already may; naming roles would be misleading.
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
for (const role of grant.roles)
|
|
156
|
+
roles.add(role);
|
|
157
|
+
}
|
|
158
|
+
return [...roles].sort();
|
|
159
|
+
}
|
|
160
|
+
/** Every role the policy mentions, declared or implied by its grants. */
|
|
161
|
+
export function rolesOf(policy) {
|
|
162
|
+
if (policy.roles)
|
|
163
|
+
return policy.roles;
|
|
164
|
+
const roles = new Set();
|
|
165
|
+
for (const grant of policy.grants) {
|
|
166
|
+
if (grant.roles === "*")
|
|
167
|
+
continue;
|
|
168
|
+
for (const role of grant.roles)
|
|
169
|
+
roles.add(role);
|
|
170
|
+
}
|
|
171
|
+
return [...roles].sort();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The mutations a principal may run at all, ignoring any particular subject.
|
|
175
|
+
*
|
|
176
|
+
* This is what narrows an agent seat's generated tool schema: a seat holding
|
|
177
|
+
* a principal gets tools for what that principal can do, and there is no
|
|
178
|
+
* second list to keep in step.
|
|
179
|
+
*/
|
|
180
|
+
export function permittedMutations(policy, principal, mutations) {
|
|
181
|
+
if (!policy)
|
|
182
|
+
return mutations;
|
|
183
|
+
return mutations.filter((mutation) => {
|
|
184
|
+
const subject = mutation.subject;
|
|
185
|
+
const kinds = subject && subject.kinds !== "*" ? subject.kinds : [undefined];
|
|
186
|
+
// Permitted for ANY of its subject kinds is enough to offer the tool; the
|
|
187
|
+
// store still refuses the individual call that is not allowed.
|
|
188
|
+
return kinds.some((kind) => permits(policy, principal, mutation.name, kind).ok);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/permissions/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Author } from "../ops/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Who is acting, and what they are allowed to be.
|
|
4
|
+
*
|
|
5
|
+
* A principal IS an author with roles. Attribution and authorisation are the
|
|
6
|
+
* same fact seen twice, not two systems: every op already records `{ kind,
|
|
7
|
+
* id, session }`, so adding roles to that shape means the thing the log
|
|
8
|
+
* blames is the thing the policy judged, by construction. There is no way to
|
|
9
|
+
* act as one participant and be authorised as another.
|
|
10
|
+
*/
|
|
11
|
+
export interface Principal extends Author {
|
|
12
|
+
readonly roles?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One permission: these roles may run these mutations, optionally only
|
|
16
|
+
* against subjects of certain kinds.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately small. A grant is a fact about the declaration — mutation
|
|
19
|
+
* names and node kinds, both of which `graview check` can see — so "a
|
|
20
|
+
* mutation no role can ever run" and "a role that may do nothing" are
|
|
21
|
+
* build-time findings rather than things discovered by a person who cannot
|
|
22
|
+
* press a button.
|
|
23
|
+
*/
|
|
24
|
+
export interface Grant {
|
|
25
|
+
/** Roles this grant is for. `"*"` means everyone, including no roles at all. */
|
|
26
|
+
readonly roles: readonly string[] | "*";
|
|
27
|
+
readonly mutations: readonly string[] | "*";
|
|
28
|
+
/** Restricts the grant to subjects of these kinds. Defaults to all of them. */
|
|
29
|
+
readonly kinds?: readonly string[] | "*";
|
|
30
|
+
/** Shown when an action is withheld, so a refusal can say something useful. */
|
|
31
|
+
readonly describe?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Only on the principal's OWN record: the call's subject must be the node
|
|
34
|
+
* whose id is the principal's. This is how a person edits their profile
|
|
35
|
+
* without a role that edits everyone's — the grant reads "you, on yours".
|
|
36
|
+
*/
|
|
37
|
+
readonly self?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A policy is deny-by-default, and its ABSENCE permits everything.
|
|
41
|
+
*
|
|
42
|
+
* The second half matters as much as the first: a store with no policy is not
|
|
43
|
+
* a store where nothing works, it is a store where permission is not a
|
|
44
|
+
* concern yet. An app opts in by declaring one.
|
|
45
|
+
*/
|
|
46
|
+
export interface Policy {
|
|
47
|
+
readonly grants: readonly Grant[];
|
|
48
|
+
/**
|
|
49
|
+
* Roles the policy knows about, so `graview check` can report a role that
|
|
50
|
+
* may do nothing. Derived from the grants when absent.
|
|
51
|
+
*/
|
|
52
|
+
readonly roles?: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
/** Why an action is not available, in terms someone can act on. */
|
|
55
|
+
export interface Refusal {
|
|
56
|
+
readonly mutation: string;
|
|
57
|
+
/** The subject kind that was refused, when the call names one. */
|
|
58
|
+
readonly kind?: string;
|
|
59
|
+
readonly message: string;
|
|
60
|
+
/**
|
|
61
|
+
* The roles that WOULD be allowed to do it. Empty means nobody can, which
|
|
62
|
+
* is a different problem and says so.
|
|
63
|
+
*/
|
|
64
|
+
readonly wouldNeed: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Thrown when a principal runs a mutation they may not.
|
|
68
|
+
*
|
|
69
|
+
* An error rather than a silent no-op: enforcement lives at the store, and a
|
|
70
|
+
* store that quietly did nothing would be indistinguishable from one that
|
|
71
|
+
* worked. Every caller — a person's click, an agent's tool call, a sync
|
|
72
|
+
* adapter's inbound change — hits the same wall in the same way.
|
|
73
|
+
*/
|
|
74
|
+
export declare class PermissionDeniedError extends Error {
|
|
75
|
+
readonly refusal: Refusal;
|
|
76
|
+
constructor(refusal: Refusal);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/permissions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAU,SAAQ,MAAM;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,KAAK;IACpB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5C,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,mEAAmE;AACnE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBACd,OAAO,EAAE,OAAO;CAK7B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when a principal runs a mutation they may not.
|
|
3
|
+
*
|
|
4
|
+
* An error rather than a silent no-op: enforcement lives at the store, and a
|
|
5
|
+
* store that quietly did nothing would be indistinguishable from one that
|
|
6
|
+
* worked. Every caller — a person's click, an agent's tool call, a sync
|
|
7
|
+
* adapter's inbound change — hits the same wall in the same way.
|
|
8
|
+
*/
|
|
9
|
+
export class PermissionDeniedError extends Error {
|
|
10
|
+
refusal;
|
|
11
|
+
constructor(refusal) {
|
|
12
|
+
super(refusal.message);
|
|
13
|
+
this.name = "PermissionDeniedError";
|
|
14
|
+
this.refusal = refusal;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/permissions/types.ts"],"names":[],"mappings":"AAsEA;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,OAAO,CAAU;IAC1B,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { GraphSnapshot } from "../graph/types.js";
|
|
2
|
+
import type { PersistenceAdapter } from "./types.js";
|
|
3
|
+
/** In-memory adapter. Deep-copies on the way in and out, so a stored graph
|
|
4
|
+
* cannot be mutated behind the store's back. */
|
|
5
|
+
export declare function createMemoryAdapter(seed?: Record<string, GraphSnapshot>): PersistenceAdapter<string>;
|
|
6
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/persistence/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD;gDACgD;AAChD,wBAAgB,mBAAmB,CACjC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAM,GACvC,kBAAkB,CAAC,MAAM,CAAC,CA2B5B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** In-memory adapter. Deep-copies on the way in and out, so a stored graph
|
|
2
|
+
* cannot be mutated behind the store's back. */
|
|
3
|
+
export function createMemoryAdapter(seed = {}) {
|
|
4
|
+
const graphs = new Map(Object.entries(seed).map(([k, v]) => [k, clone(v)]));
|
|
5
|
+
const logs = new Map();
|
|
6
|
+
return {
|
|
7
|
+
name: "memory",
|
|
8
|
+
async load(scope) {
|
|
9
|
+
const found = graphs.get(scope);
|
|
10
|
+
return found ? clone(found) : null;
|
|
11
|
+
},
|
|
12
|
+
async save(scope, snapshot) {
|
|
13
|
+
graphs.set(scope, clone(snapshot));
|
|
14
|
+
},
|
|
15
|
+
async delete(scope) {
|
|
16
|
+
graphs.delete(scope);
|
|
17
|
+
logs.delete(scope);
|
|
18
|
+
},
|
|
19
|
+
async loadLog(scope) {
|
|
20
|
+
return clone(logs.get(scope) ?? []);
|
|
21
|
+
},
|
|
22
|
+
async appendOps(scope, ops) {
|
|
23
|
+
const existing = logs.get(scope) ?? [];
|
|
24
|
+
logs.set(scope, [...existing, ...clone([...ops])]);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function clone(value) {
|
|
29
|
+
return structuredClone(value);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/persistence/memory.ts"],"names":[],"mappings":"AAIA;gDACgD;AAChD,MAAM,UAAU,mBAAmB,CACjC,OAAsC,EAAE;IAExC,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE5C,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,KAAK,CAAC,IAAI,CAAC,KAAK;YACd,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ;YACxB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,KAAK;YACjB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAI,KAAQ;IACxB,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC"}
|