@graphty/graphty-element 2.5.1 → 2.6.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.
Files changed (135) hide show
  1. package/dist/ai.js +3 -3
  2. package/dist/catalog.d.ts +16 -0
  3. package/dist/catalog.js +34 -32
  4. package/dist/chunks/{AiManager-CrbvKdEK.js → AiManager-4iQpsJW1.js} +4 -4
  5. package/dist/chunks/{DataSource-qU-nLhXN.js → DataSource-BL2UzPff.js} +2 -2
  6. package/dist/chunks/GraphSession-BhuHSXIo.js +12819 -0
  7. package/dist/chunks/{GraphtyLogger-DOTwCiMR.js → GraphtyLogger-B_O67a6c.js} +1 -1
  8. package/dist/chunks/{VoiceInputAdapter-D4NrRL_1.js → VoiceInputAdapter-Cc6mHXTI.js} +1 -1
  9. package/dist/chunks/{XRPivotCameraController-Uqa47vmo.js → XRPivotCameraController-BLa89LXn.js} +2 -2
  10. package/dist/chunks/{algorithms-D-ab-Auu.js → algorithms-BJ6DQMOe.js} +931 -781
  11. package/dist/chunks/{capability-check-Vw3IcqiE.js → capability-check-Am2zliFj.js} +1 -1
  12. package/dist/chunks/{detect-B4Qrw976.js → detect-fyuVnlCT.js} +1 -1
  13. package/dist/chunks/{format-detection-r2IfNFXO.js → format-detection-BHwrAVzW.js} +1 -1
  14. package/dist/chunks/{index-J9MgLio9.js → index-BkBLbvui.js} +2691 -2434
  15. package/dist/chunks/optionsFromZod-CKMYSwTz.js +3636 -0
  16. package/dist/chunks/{paletteRegistry-Kt-6CeoN.js → paletteRegistry-BCFSwJGK.js} +224 -189
  17. package/dist/chunks/parse-BMTqt4SS.js +3658 -0
  18. package/dist/chunks/{types-C_c53VgR.js → types-DFchv4Ny.js} +4 -1
  19. package/dist/custom-elements.json +1 -1
  20. package/dist/extend.d.ts +10 -8
  21. package/dist/extend.js +6 -6
  22. package/dist/graphty-catalog.json +75 -38
  23. package/dist/graphty.bundle.js +55368 -48970
  24. package/dist/graphty.js +19 -19
  25. package/dist/index.d.ts +1 -1
  26. package/dist/logging.js +2 -2
  27. package/dist/schema.d.ts +15 -1
  28. package/dist/schema.js +1 -1
  29. package/dist/session.d.ts +30 -7
  30. package/dist/session.js +40 -37
  31. package/dist/src/Graph.d.ts +35 -7
  32. package/dist/src/acceleration/types.d.ts +79 -43
  33. package/dist/src/algorithms/Algorithm.d.ts +52 -4
  34. package/dist/src/algorithms/BFSAlgorithm.d.ts +3 -0
  35. package/dist/src/algorithms/BellmanFordAlgorithm.d.ts +3 -0
  36. package/dist/src/algorithms/BetweennessCentralityAlgorithm.d.ts +3 -0
  37. package/dist/src/algorithms/BipartiteMatchingAlgorithm.d.ts +3 -0
  38. package/dist/src/algorithms/ClosenessCentralityAlgorithm.d.ts +3 -0
  39. package/dist/src/algorithms/ConnectedComponentsAlgorithm.d.ts +4 -1
  40. package/dist/src/algorithms/DFSAlgorithm.d.ts +3 -0
  41. package/dist/src/algorithms/DegreeAlgorithm.d.ts +3 -0
  42. package/dist/src/algorithms/DijkstraAlgorithm.d.ts +6 -0
  43. package/dist/src/algorithms/EigenvectorCentralityAlgorithm.d.ts +2 -0
  44. package/dist/src/algorithms/FloydWarshallAlgorithm.d.ts +3 -0
  45. package/dist/src/algorithms/GirvanNewmanAlgorithm.d.ts +3 -0
  46. package/dist/src/algorithms/HITSAlgorithm.d.ts +3 -0
  47. package/dist/src/algorithms/KCoreAlgorithm.d.ts +3 -0
  48. package/dist/src/algorithms/KatzCentralityAlgorithm.d.ts +3 -0
  49. package/dist/src/algorithms/KruskalAlgorithm.d.ts +4 -1
  50. package/dist/src/algorithms/LabelPropagationAlgorithm.d.ts +3 -0
  51. package/dist/src/algorithms/LeidenAlgorithm.d.ts +3 -0
  52. package/dist/src/algorithms/LinkPredictionAlgorithm.d.ts +4 -1
  53. package/dist/src/algorithms/LouvainAlgorithm.d.ts +3 -0
  54. package/dist/src/algorithms/MaxFlowAlgorithm.d.ts +3 -0
  55. package/dist/src/algorithms/MinCutAlgorithm.d.ts +3 -0
  56. package/dist/src/algorithms/PageRankAlgorithm.d.ts +3 -0
  57. package/dist/src/algorithms/PrimAlgorithm.d.ts +3 -0
  58. package/dist/src/algorithms/StronglyConnectedComponentsAlgorithm.d.ts +3 -0
  59. package/dist/src/algorithms/input/ScopedInput.d.ts +185 -0
  60. package/dist/src/algorithms/input/derivedInputs.d.ts +199 -0
  61. package/dist/src/algorithms/input/maskBack.d.ts +37 -0
  62. package/dist/src/algorithms/metrics/MetricAlgorithm.d.ts +3 -3
  63. package/dist/src/algorithms/results/DeclaredAlgorithm.d.ts +4 -3
  64. package/dist/src/algorithms/results/types.d.ts +28 -6
  65. package/dist/src/algorithms/utils/communityUtils.d.ts +0 -48
  66. package/dist/src/algorithms/utils/graphUtils.d.ts +2 -68
  67. package/dist/src/algorithms/utils/snapshotGraph.d.ts +3 -1
  68. package/dist/src/catalog/algorithms.d.ts +3 -0
  69. package/dist/src/catalog/layouts.d.ts +2 -0
  70. package/dist/src/catalog/sets/canonical.d.ts +68 -0
  71. package/dist/src/catalog/sets/hash.d.ts +126 -0
  72. package/dist/src/catalog/sets/parse.d.ts +115 -0
  73. package/dist/src/catalog/types.d.ts +329 -8
  74. package/dist/src/data/GraphStore.d.ts +73 -1
  75. package/dist/src/data/edgeIdentity.d.ts +202 -1
  76. package/dist/src/data/ingest.d.ts +3 -1
  77. package/dist/src/data/report.d.ts +20 -0
  78. package/dist/src/graphty-element.d.ts +42 -6
  79. package/dist/src/layout/D3GraphLayoutEngine.d.ts +11 -0
  80. package/dist/src/layout/LayoutEngine.d.ts +56 -0
  81. package/dist/src/layout/NGraphLayoutEngine.d.ts +10 -0
  82. package/dist/src/layout/SimulationLayoutEngine.d.ts +11 -0
  83. package/dist/src/managers/AlgorithmManager.d.ts +8 -0
  84. package/dist/src/managers/DataManager.d.ts +11 -0
  85. package/dist/src/managers/LayoutManager.d.ts +126 -2
  86. package/dist/src/managers/StatsManager.d.ts +1 -0
  87. package/dist/src/session/GraphSession.d.ts +48 -0
  88. package/dist/src/session/attributes.d.ts +121 -1
  89. package/dist/src/session/cost/estimate.d.ts +20 -0
  90. package/dist/src/session/cost/index.d.ts +1 -1
  91. package/dist/src/session/planning.d.ts +32 -2
  92. package/dist/src/session/query.d.ts +7 -0
  93. package/dist/src/session/results/ResultsApi.d.ts +14 -1
  94. package/dist/src/session/runs/Run.d.ts +65 -4
  95. package/dist/src/session/runs/RunsApi.d.ts +58 -2
  96. package/dist/src/session/runs/runId.d.ts +55 -6
  97. package/dist/src/session/runs/types.d.ts +36 -8
  98. package/dist/src/session/scope/ElementMask.d.ts +14 -1
  99. package/dist/src/session/scope/ScopeApi.d.ts +160 -31
  100. package/dist/src/session/scope/index.d.ts +1 -1
  101. package/dist/src/session/selection/SelectionApi.d.ts +15 -10
  102. package/dist/src/session/selection/index.d.ts +1 -1
  103. package/dist/src/session/selection/targets.d.ts +6 -7
  104. package/dist/src/session/sets/SetsApi.d.ts +110 -0
  105. package/dist/src/session/sets/algebra.d.ts +124 -0
  106. package/dist/src/session/sets/cache.d.ts +197 -0
  107. package/dist/src/session/sets/captures.d.ts +83 -0
  108. package/dist/src/session/sets/dependencies.d.ts +167 -0
  109. package/dist/src/session/sets/layers.d.ts +101 -0
  110. package/dist/src/session/sets/notify.d.ts +122 -0
  111. package/dist/src/session/sets/offers.d.ts +103 -0
  112. package/dist/src/session/sets/path.d.ts +37 -0
  113. package/dist/src/session/sets/prepare.d.ts +209 -0
  114. package/dist/src/session/sets/resolve.d.ts +311 -0
  115. package/dist/src/session/sets/signature.d.ts +77 -0
  116. package/dist/src/session/sets/status.d.ts +98 -0
  117. package/dist/src/session/sets/store.d.ts +196 -0
  118. package/dist/src/session/sets/types.d.ts +386 -0
  119. package/dist/src/session/styles/Layer.d.ts +9 -2
  120. package/dist/src/session/styles/StylesApi.d.ts +5 -2
  121. package/dist/src/session/styles/explain.d.ts +5 -2
  122. package/dist/src/session/styles/predicate.d.ts +41 -2
  123. package/dist/src/session/styles/repaint.d.ts +19 -0
  124. package/dist/src/session/styles/selector.d.ts +16 -5
  125. package/dist/src/session/types.d.ts +18 -0
  126. package/dist/src/session/visibility/VisibilityApi.d.ts +47 -3
  127. package/dist/src/session/visibility/filter.d.ts +86 -51
  128. package/dist/src/session/visibility/index.d.ts +1 -1
  129. package/dist/src/testing/fakeAccelerator.d.ts +5 -0
  130. package/dist/src/utils/queue-migration.d.ts +17 -0
  131. package/package.json +15 -9
  132. package/dist/chunks/GraphSession-DuAhRgCd.js +0 -8622
  133. package/dist/chunks/optionsFromZod-B9RncoTX.js +0 -2578
  134. package/dist/chunks/scales-CJCRwi2J.js +0 -3220
  135. package/dist/src/algorithms/utils/index.d.ts +0 -6
@@ -9,7 +9,9 @@
9
9
  * was implemented independently in four places, two of which carried a doc comment claiming to be
10
10
  * the only one, and the two sides of a style join could -- and did -- disagree in silence.
11
11
  */
12
- import type { EdgeId } from "../catalog/types";
12
+ import { type DuplicatePolicy, type GraphSnapshot } from "@graphty/graph-format";
13
+ import { type LanePair } from "../catalog/sets/hash";
14
+ import type { EdgeId, EdgeMember, NodeId } from "../catalog/types";
13
15
  /**
14
16
  * The id of the edge carrying one counter value.
15
17
  *
@@ -27,3 +29,202 @@ export declare function edgeIdOf(counter: number): EdgeId;
27
29
  * @returns the counter, or `INVALID_INDEX` when the id is not one this element ever assigned
28
30
  */
29
31
  export declare function edgeCounterOf(id: EdgeId): number;
32
+ /**
33
+ * The row of a session edge in a snapshot: its `Edge.index`.
34
+ * @param graph - the snapshot
35
+ * @param id - the session edge id
36
+ * @returns the row, or `INVALID_INDEX`
37
+ */
38
+ export declare function edgeRowOf(graph: GraphSnapshot, id: EdgeId): number;
39
+ /**
40
+ * The counter behind `GraphStore.nextEdgeId()`.
41
+ *
42
+ * An object rather than a number held by the store, so that its owner (`DataManager`, or a
43
+ * headless `GraphSession`) can hand the same one to every store it builds: a Clear or a replacing
44
+ * import then starts a new store without rewinding the counter, and an edge id is never issued
45
+ * twice in one session.
46
+ */
47
+ export interface EdgeCounter {
48
+ /** The value the next edge takes. */
49
+ next: number;
50
+ }
51
+ /**
52
+ * A counter starting at 0.
53
+ * @returns the counter
54
+ */
55
+ export declare function createEdgeCounter(): EdgeCounter;
56
+ /**
57
+ * Continue a counter one past a value already issued, as a graph restored with its edge-id column
58
+ * must, so a restored id is never issued again. Never moves the counter backwards.
59
+ * @param counter - the counter
60
+ * @param last - the largest counter value the restored graph carries
61
+ */
62
+ export declare function resumeEdgeCounter(counter: EdgeCounter, last: number): void;
63
+ /**
64
+ * The id minted for an edge added in the session without a file id. `graphty:` is a reserved
65
+ * namespace, so it can never collide with an id a file chose unless the file was written by the
66
+ * element itself.
67
+ * @param counter - the edge's counter value
68
+ * @returns the minted id
69
+ */
70
+ export declare function mintedEdgeId(counter: number): string;
71
+ /** What becomes of a record repeating an edge the graph already holds. */
72
+ type RepeatDecision =
73
+ /** `keep`: the repeat is an edge of its own. */
74
+ {
75
+ readonly kind: "add";
76
+ }
77
+ /** `error`: the load is refused with `E_DUPLICATE_EDGE`. */
78
+ | {
79
+ readonly kind: "refuse";
80
+ }
81
+ /** `first`: the repeat is dropped and the survivor is untouched. */
82
+ | {
83
+ readonly kind: "drop";
84
+ }
85
+ /**
86
+ * `last`, `sum`, `min`, `max`: the survivor takes `weight`, and under `last` the repeat's
87
+ * attributes replace the survivor's (`replaceRecord`).
88
+ */
89
+ | {
90
+ readonly kind: "merge";
91
+ readonly weight: number;
92
+ readonly replaceRecord: boolean;
93
+ };
94
+ /**
95
+ * The repeated-edge survivorship decision, one place for every ingest path and every test harness,
96
+ * so nothing re-implements which edges survive.
97
+ * @param policy - `data.knownFields.repeatedEdges`, or a call's override
98
+ * @param survivorWeight - the weight the edge already held carries
99
+ * @param repeatWeight - the repeating record's resolved weight
100
+ * @returns the decision
101
+ */
102
+ export declare function decideRepeat(policy: DuplicatePolicy, survivorWeight: number, repeatWeight: number): RepeatDecision;
103
+ /** The element-assigned edge counter column. Its value, printed, is `Edge.id`. */
104
+ export declare const EDGE_ID_COLUMN = "graphty.edgeId";
105
+ /** The builder columns the completion pass fills. Internal names; the `graphty.` prefix is reserved. */
106
+ export declare const IDENTITY_COLUMNS: {
107
+ /** Node: `hashNodeId` of the node id, two uint32 lanes. */
108
+ readonly nodeHash: "graphty.nodeHash";
109
+ /** Edge: `hashEdgeMember` of the edge's stable identity, two uint32 lanes. */
110
+ readonly edgeHash: "graphty.edgeHash";
111
+ /** Edge: its position among its pair's surviving edges in its load; -1 for a session edge. */
112
+ readonly edgeOrdinal: "graphty.edgeOrdinal";
113
+ /** Edge: its pair's surviving edge count in its load; -1 for a session edge. */
114
+ readonly edgeAmong: "graphty.edgeAmong";
115
+ };
116
+ /**
117
+ * The graph attribute recording whether edge pairs are ordered (1) or unordered (0). Latched once
118
+ * per store, when the first edge is completed: a pair is ordered only when the graph was declared
119
+ * directed by then, and a direction settled later changes nothing already written.
120
+ */
121
+ export declare const PAIRS_ORDERED_ATTRIBUTE = "graphty.edgePairsOrdered";
122
+ /** Where the completion pass reads endpoints and node ids: a builder, or a snapshot. */
123
+ export interface IdentityGraph {
124
+ /**
125
+ * The declared endpoints of a live edge.
126
+ * @param edge - the edge row
127
+ * @returns [source index, target index]
128
+ */
129
+ endpoints(edge: number): readonly [number, number];
130
+ /**
131
+ * The id of a live node.
132
+ * @param node - the node row
133
+ * @returns the id
134
+ */
135
+ idOf(node: number): NodeId;
136
+ /**
137
+ * The hash of a live node's id, when the caller already has it (the hash of `idOf(node)`).
138
+ * Absent: hashed from `idOf`.
139
+ * @param node - the node row
140
+ * @returns the hash
141
+ */
142
+ hashOf?(node: number): LanePair;
143
+ }
144
+ /** Receives one completed edge row. */
145
+ type IdentityWriter = (row: number, ordinal: number, among: number, hash: LanePair) => void;
146
+ /** What the tests read: the transient bytes of the last completed load, and how many edges it held. */
147
+ export declare const identityCounters: {
148
+ lastTransientBytes: number;
149
+ lastLoadEdges: number;
150
+ };
151
+ /**
152
+ * Complete one load: give each of its surviving edges its ordinal and among, counted per pair in
153
+ * ingest order, and its edge hash.
154
+ *
155
+ * The load's rows are sorted by (pair, row) through a permutation over two endpoint arrays, 20
156
+ * transient bytes per loaded edge with the row list and 4 per node (see `sortPairs`), and the columns are filled in one pass. No
157
+ * map over the whole graph's pairs is kept. Rows are appended in ingest order and a compacting
158
+ * freeze keeps their order, so row order within a load is counter order.
159
+ * @param rows - the load's surviving edge rows, ascending
160
+ * @param graph - where endpoints and ids are read
161
+ * @param ordered - whether pairs are ordered (the graph was declared directed at ingest)
162
+ * @param fileIdAt - the file id of the edge at a position of `rows`, or undefined
163
+ * @param write - receives each completed row
164
+ */
165
+ export declare function completeLoad(rows: Uint32Array, graph: IdentityGraph, ordered: boolean, fileIdAt: (position: number) => string | number | undefined, write: IdentityWriter): void;
166
+ /**
167
+ * The hash of a session edge: its file id when it has one, else the id minted from its counter.
168
+ * @param graph - where endpoints and ids are read
169
+ * @param row - the edge row
170
+ * @param counter - its counter value
171
+ * @param fileId - its file id, if any
172
+ * @param ordered - whether pairs are ordered
173
+ * @returns the hash
174
+ */
175
+ export declare function sessionEdgeHash(graph: IdentityGraph, row: number, counter: number, fileId: string | number | undefined, ordered: boolean): LanePair;
176
+ /** The four identity columns of a snapshot, read or computed. */
177
+ interface IdentityColumns {
178
+ /** Two lanes per node. */
179
+ readonly nodeHash: Uint32Array;
180
+ /** Two lanes per edge. */
181
+ readonly edgeHash: Uint32Array;
182
+ /** Per edge; -1 for a session edge. */
183
+ readonly edgeOrdinal: Int32Array;
184
+ /** Per edge; -1 for a session edge. */
185
+ readonly edgeAmong: Int32Array;
186
+ }
187
+ /**
188
+ * Whether a snapshot's edge pairs are ordered: the store's latch when it has one, else the
189
+ * snapshot's own direction (a raw graph-format or graph-io snapshot was declared by its producer).
190
+ * @param snapshot - the snapshot
191
+ * @returns true when pairs are ordered
192
+ */
193
+ export declare function pairsOrdered(snapshot: GraphSnapshot): boolean;
194
+ /**
195
+ * A stable edge member with its ends in the canonical comparator order when pairs are unordered,
196
+ * so `b -> a` and `a -> b` spell one member of an undirected graph. Anything that is not a pair
197
+ * of ids passes through unchanged for a validator to judge; an already canonical member is
198
+ * returned as the same object.
199
+ * @param member - the member as given
200
+ * @param ordered - whether the graph's pairs are ordered
201
+ * @returns the member
202
+ */
203
+ export declare function canonicalEdgeEnds<T>(member: T, ordered: boolean): T;
204
+ /**
205
+ * A snapshot's identity columns: the store's, when it carries them, else computed from its ids on
206
+ * first read and cached -- exactly what the completion pass would have written had the whole
207
+ * snapshot been one load with no file ids.
208
+ * @param snapshot - the snapshot
209
+ * @returns the columns
210
+ */
211
+ export declare function identityColumnsOf(snapshot: GraphSnapshot): IdentityColumns;
212
+ /**
213
+ * The bytes the identity columns hold in a snapshot: data plus validity of each of the four,
214
+ * which is what the memory budget of design 6.5 counts (8 per node, 16 per edge).
215
+ * @param snapshot - the snapshot
216
+ * @returns the byte count; 0 for a snapshot without the columns
217
+ */
218
+ export declare function identityColumnBytes(snapshot: GraphSnapshot): number;
219
+ /**
220
+ * An edge's stable identity, built from its row's columns (design 12.3): its file id when the
221
+ * caller read one at the configured `edgeIdPath`, else its ordinal and among when it came from a
222
+ * load, else the id minted from its counter. The ends of an unordered pair are in the canonical
223
+ * comparator order, so both orientations of one edge give one member.
224
+ * @param snapshot - the snapshot the row belongs to
225
+ * @param edge - the edge row
226
+ * @param fileId - the edge's file id, read by the caller at the configured `edgeIdPath`
227
+ * @returns the member
228
+ */
229
+ export declare function stableEdgeMember(snapshot: GraphSnapshot, edge: number, fileId?: string | number): EdgeMember;
230
+ export {};
@@ -58,10 +58,12 @@ export declare function resolveEdgeWeight(record: Record<string | number, unknow
58
58
  * @param srcId - source node id, already extracted with JMESPath
59
59
  * @param dstId - destination node id
60
60
  * @param weight - the resolved weight
61
+ * @param fileId - the edge's id read at the configured `edgeIdPath`, when there is one: its stable
62
+ * identity (design/sets/sets-design.md 12.3)
61
63
  * @returns the logical edge index and the counter stamped into the edge's id column, or
62
64
  * `INVALID_INDEX` for both when either id is not one graph-format accepts
63
65
  */
64
- export declare function ingestEdge(store: GraphStore, srcId: unknown, dstId: unknown, weight: number): {
66
+ export declare function ingestEdge(store: GraphStore, srcId: unknown, dstId: unknown, weight: number, fileId?: string | number): {
65
67
  index: number;
66
68
  edgeId: number;
67
69
  };
@@ -60,6 +60,20 @@ export interface ImportReport {
60
60
  /** The record key weights were read from, or null when no record carried one. */
61
61
  readonly attribute: string | null;
62
62
  };
63
+ /**
64
+ * How a set, a style layer or a saved reference will find the edges this load stored again:
65
+ * by the file's own edge id, or, without one, by position among the edges of the same pair.
66
+ * A reference by position matches a different edge if a later file lists that pair's edges
67
+ * in another order, which is why the report says how many there are.
68
+ */
69
+ readonly edgeIdentity: {
70
+ /** The record key file ids were read at (`knownFields.edgeIdPath`), or null when none is configured. */
71
+ readonly idPath: string | null;
72
+ /** Edges stored with a file id. */
73
+ readonly byId: number;
74
+ /** Edges stored without one, matched by position among their pair's edges. */
75
+ readonly byPosition: number;
76
+ };
63
77
  }
64
78
  /**
65
79
  * The mutable tally a load keeps while it runs, before it is frozen into an {@link ImportReport}.
@@ -86,6 +100,10 @@ export interface ImportTally {
86
100
  weightsResolvedFrom: "path" | "legacy" | "none";
87
101
  /** The record key that weight came from. */
88
102
  weightsAttribute: string | null;
103
+ /** Edges stored with a file id. */
104
+ edgesById: number;
105
+ /** Edges stored without one. */
106
+ edgesByPosition: number;
89
107
  }
90
108
  /**
91
109
  * A fresh, zeroed tally.
@@ -104,6 +122,8 @@ interface ImportReportContext {
104
122
  readonly nodes: number;
105
123
  /** Edges the graph holds now. */
106
124
  readonly edges: number;
125
+ /** The configured file-id path, or null. */
126
+ readonly idPath: string | null;
107
127
  }
108
128
  /**
109
129
  * Freeze one load's tally and its context into the report a consumer reads.
@@ -1,7 +1,7 @@
1
1
  import type { DuplicatePolicy } from "@graphty/graph-format";
2
2
  import { LitElement } from "lit";
3
3
  import { type AccelerationPolicy } from "./acceleration";
4
- import type { AlgorithmKey, Scope } from "./catalog/types";
4
+ import type { AlgorithmKey, Scope, ScopeInput } from "./catalog/types";
5
5
  import type { GraphBackgroundConfig, GraphBehaviorConfig, GraphSelectionStyleInput, ViewMode } from "./config";
6
6
  import { type AlgorithmOnLoad } from "./config/DataConfig";
7
7
  import type { PartialXRConfig } from "./config/xr-config-schema";
@@ -9,7 +9,7 @@ import { Graph } from "./Graph";
9
9
  import type { ScreenshotOptions, ScreenshotResult } from "./screenshot/types.js";
10
10
  import type { GraphSession } from "./session";
11
11
  import type { Run, StartOptions } from "./session/runs";
12
- import type { SelectionDelta, SelectionTarget, SetOp } from "./session/selection";
12
+ import type { SelectionDelta, SelectionOp, SelectionTarget } from "./session/selection";
13
13
  /**
14
14
  * Graphty creates a graph
15
15
  */
@@ -96,7 +96,7 @@ export declare class Graphty extends LitElement {
96
96
  * </script>
97
97
  * ```
98
98
  */
99
- select(target: SelectionTarget, op?: SetOp): Promise<SelectionDelta>;
99
+ select(target: SelectionTarget, op?: SelectionOp): Promise<SelectionDelta>;
100
100
  /**
101
101
  * Called when the element is added to the DOM. Sets up the graph container and resize observer.
102
102
  */
@@ -429,6 +429,40 @@ export declare class Graphty extends LitElement {
429
429
  * Sets layout-specific configuration. Updates active layout if one is set.
430
430
  */
431
431
  set layoutConfig(value: Record<string, unknown> | undefined);
432
+ /**
433
+ * What the layout runs over: a set, a query, a list of nodes -- any scope.
434
+ * @remarks
435
+ * The scope's nodes move and every other node is held where it is. The members are the ones
436
+ * the scope had when the layout started, so a later click, filter change or attribute edit
437
+ * does not move what the layout holds, and a node added afterwards is held too.
438
+ *
439
+ * CARRIED across `layout` and `layoutConfig` changes, so changing one force setting never
440
+ * un-scopes the layout. Setting it restarts the running layout. Only a live simulation --
441
+ * whose catalogue entry reads `scoped: true` -- lays out a scope; under any other layout, or
442
+ * when the set it names is removed, the scope is inactive and the whole graph is laid out.
443
+ * Nothing here throws: a value that is not a scope is reported and dropped.
444
+ *
445
+ * Reads `undefined` when layouts run over the whole graph, never `"graph"`.
446
+ * @since 2.5.0
447
+ * @example JavaScript property
448
+ * ```typescript
449
+ * const id = element.session.sets.create({ kind: "fixed", nodes: ["a", "b", "c"], reading: "induced" });
450
+ * element.layout = "ngraph";
451
+ * element.layoutScope = { set: id };
452
+ * ```
453
+ * @example HTML attribute (JSON)
454
+ * ```html
455
+ * <graphty-element layout="ngraph" layout-scope='{"nodes":["a","b","c"]}'></graphty-element>
456
+ * ```
457
+ * @returns The scope, or undefined for the whole graph
458
+ */
459
+ get layoutScope(): Scope | undefined;
460
+ /**
461
+ * Sets what the layout runs over, and restarts the running layout over it. A value that is
462
+ * not a scope is reported and dropped, never thrown: this setter is reached from
463
+ * `attributeChangedCallback`, where a throw would reach nobody.
464
+ */
465
+ set layoutScope(value: ScopeInput | undefined);
432
466
  /**
433
467
  * How the element DRIVES the layout, as distinct from what the layout engine is configured
434
468
  * with.
@@ -1345,7 +1379,9 @@ export declare class Graphty extends LitElement {
1345
1379
  * default engine, or a registered engine name (such as `"ngraph"`).
1346
1380
  * @param type - Layout id or engine name
1347
1381
  * @param opts - Layout-specific options
1348
- * @param options - Queue options
1382
+ * @param options - Queue options, and `scope`: what the layout runs over. A live simulation
1383
+ * moves the scope's nodes and holds the rest; absent keeps the scope already set, and
1384
+ * `"graph"` clears it. See {@link Graphty.layoutScope}.
1349
1385
  * @returns Promise that resolves when layout is initialized
1350
1386
  * @since 1.5.0
1351
1387
  * @example
@@ -1355,7 +1391,7 @@ export declare class Graphty extends LitElement {
1355
1391
  * await element.setLayout('ngraph', { springLength: 100 });
1356
1392
  * ```
1357
1393
  */
1358
- setLayout(type: string, opts?: object, options?: import("./utils/queue-migration").QueueableOptions): Promise<void>;
1394
+ setLayout(type: string, opts?: object, options?: import("./utils/queue-migration").SetLayoutOptions): Promise<void>;
1359
1395
  /**
1360
1396
  * Zoom the camera to fit all nodes in view.
1361
1397
  * @since 1.5.0
@@ -1540,7 +1576,7 @@ export declare class Graphty extends LitElement {
1540
1576
  * ```
1541
1577
  */
1542
1578
  applyCameraView(id: string, options?: {
1543
- scope?: Scope;
1579
+ scope?: ScopeInput;
1544
1580
  params?: Readonly<Record<string, unknown>>;
1545
1581
  } & import("./screenshot/types.js").CameraAnimationOptions): Promise<void>;
1546
1582
  /**
@@ -1,3 +1,4 @@
1
+ import type { NodeMask } from "@graphty/graph-format";
1
2
  import { Edge as D3Edge, forceSimulation, InputEdge as D3InputEdge, Node as D3Node } from "d3-force-3d";
2
3
  import { z } from "zod/v4";
3
4
  import { type OptionsSchema } from "../config";
@@ -21,6 +22,8 @@ export declare class D3GraphEngine extends LayoutEngine {
21
22
  static type: string;
22
23
  static maxDimensions: number;
23
24
  static zodOptionsSchema: OptionsSchema;
25
+ /** Accepts a scope: a held node is fixed through d3's own `fx`/`fy`/`fz`. */
26
+ static scoped: boolean;
24
27
  d3ForceLayout: ReturnType<typeof forceSimulation>;
25
28
  d3AlphaMin: number;
26
29
  d3AlphaTarget: number;
@@ -123,6 +126,14 @@ export declare class D3GraphEngine extends LayoutEngine {
123
126
  * @param n - The node to unpin
124
127
  */
125
128
  unpin(n: Node): void;
129
+ /**
130
+ * Holds the nodes a scoped layout may not move, as d3 fixes a node: at its current position.
131
+ *
132
+ * A node that is no longer held is released unless the reader pinned it.
133
+ * @param mask - One bit per row to hold, or null to hold nothing.
134
+ * @param rows - How many rows the mask covers.
135
+ */
136
+ setHoldMask(mask: NodeMask | null, rows: number): void;
126
137
  /**
127
138
  * Take a node out of the simulation.
128
139
  *
@@ -1,3 +1,4 @@
1
+ import { type NodeMask } from "@graphty/graph-format";
1
2
  import { z } from "zod/v4";
2
3
  import type { AuthoredLayoutDescriptor } from "../catalog/types";
3
4
  import type { OptionsSchema } from "../config";
@@ -53,6 +54,25 @@ export interface LayoutEngineStatics {
53
54
  * for, instead of offering it on seventeen layouts that ignore it.
54
55
  */
55
56
  honoursWeights?: boolean;
57
+ /**
58
+ * Whether this engine can lay out a set of nodes while holding every other node still, which is
59
+ * what `setLayout(type, opts, { scope })` asks of it.
60
+ *
61
+ * Optional, and false unless declared: an engine that says nothing refuses a scope with
62
+ * `E_UNSUPPORTED`, so no existing engine is handed a hold it never agreed to.
63
+ *
64
+ * THE CONTRACT A SCOPED ENGINE ACCEPTS. The element hands it a hold mask through
65
+ * {@link LayoutEngine.setHoldMask} after `init()` and again whenever the graph is renumbered,
66
+ * and the protected `writeNodePosition` already refuses a layout write onto a held row that
67
+ * has a coordinate -- so a held node never MOVES under any engine. That alone is not enough:
68
+ * an engine that keeps integrating a held body computes every force on its members against a
69
+ * position the element will never draw. A scoped engine must therefore treat held nodes as
70
+ * fixed in its own state -- a fixed-node mask, `fx`/`fy`, a pinned body -- read through
71
+ * the protected `isHeld(index)`, including for a node added after the hold was set and a node a
72
+ * reader unpins while it is held. The hold is never a pin: it is not written to the element's
73
+ * pin lane, so it never leaks into saved pins or exports.
74
+ */
75
+ scoped?: boolean;
56
76
  /**
57
77
  * What the catalogue publishes about this layout, so a picker can offer it.
58
78
  *
@@ -98,6 +118,14 @@ export declare abstract class LayoutEngine {
98
118
  * advertising a control that changes nothing.
99
119
  */
100
120
  static honoursWeights: boolean;
121
+ /**
122
+ * Whether this engine accepts a scope. See {@link LayoutEngineStatics.scoped}, which states the
123
+ * contract a scoped engine accepts.
124
+ *
125
+ * False here because a one-shot arrangement recomputes every coordinate from scratch, and
126
+ * where it would place a subset among nodes it may not move is a question nothing answers yet.
127
+ */
128
+ static scoped: boolean;
101
129
  /**
102
130
  * What a picker reads about this layout. See {@link LayoutEngineStatics.descriptor}.
103
131
  *
@@ -136,6 +164,10 @@ export declare abstract class LayoutEngine {
136
164
  * would silently swap that array for the one its own graph owns.
137
165
  */
138
166
  private positionArrayAttached;
167
+ /** The rows the element is holding still, or null when nothing is held. See {@link setHoldMask}. */
168
+ private hold;
169
+ /** How many rows {@link hold} covers; a row at or past it is newer than the hold, so held. */
170
+ private holdRows;
139
171
  abstract init(): Promise<void>;
140
172
  abstract addNode(n: Node): void;
141
173
  abstract addEdge(e: Edge): void;
@@ -211,6 +243,30 @@ export declare abstract class LayoutEngine {
211
243
  * @param positions - the element-owned array
212
244
  */
213
245
  attachPositions(positions: ElementPositions): void;
246
+ /**
247
+ * Hold the nodes a scoped layout may not move, or release them all with null.
248
+ *
249
+ * The element calls this on an engine whose class declares `static scoped = true`, after
250
+ * `init()` and after every renumbering of the graph. A set bit is a held row. A row at or past
251
+ * `rows` belongs to a node that arrived after the scope was captured, and is held too: the
252
+ * members of a scoped layout are the ones it started with. An engine that overrides this calls
253
+ * `super.setHoldMask` first and then fixes held nodes in its own state (see
254
+ * {@link LayoutEngineStatics.scoped}).
255
+ * @param mask - One bit per row, set for a row to hold; null holds nothing.
256
+ * @param rows - How many rows the mask covers.
257
+ */
258
+ setHoldMask(mask: NodeMask | null, rows: number): void;
259
+ /**
260
+ * The hold mask the element last handed this engine, or null when nothing is held.
261
+ * @returns The mask, which the caller must not change.
262
+ */
263
+ get holdMask(): NodeMask | null;
264
+ /**
265
+ * Whether the element is holding this row still for a scoped layout.
266
+ * @param index - The node's row, or `INVALID_INDEX`.
267
+ * @returns True while a hold is set and the row is held or newer than the hold.
268
+ */
269
+ protected isHeld(index: number): boolean;
214
270
  /**
215
271
  * Copy every node's current coordinates out of the engine and into the position array.
216
272
  *
@@ -1,3 +1,4 @@
1
+ import type { NodeMask } from "@graphty/graph-format";
1
2
  import { Layout as NGraphLayout } from "ngraph.forcelayout";
2
3
  import { Graph as NGraph, Link as NGraphLink, Node as NGraphNode } from "ngraph.graph";
3
4
  import { type OptionsSchema } from "../config";
@@ -11,6 +12,8 @@ export declare class NGraphEngine extends LayoutEngine {
11
12
  static type: string;
12
13
  static maxDimensions: number;
13
14
  static zodOptionsSchema: OptionsSchema;
15
+ /** Accepts a scope: a held node is a pinned body in ngraph's own simulation. */
16
+ static scoped: boolean;
14
17
  ngraph: NGraph;
15
18
  ngraphLayout: NGraphLayout<NGraph>;
16
19
  /**
@@ -104,6 +107,13 @@ export declare class NGraphEngine extends LayoutEngine {
104
107
  * @param n - The node to unpin
105
108
  */
106
109
  unpin(n: Node): void;
110
+ /**
111
+ * Holds the nodes a scoped layout may not move, as pinned bodies. A node that is no longer
112
+ * held is released unless the reader pinned it.
113
+ * @param mask - One bit per row to hold, or null to hold nothing.
114
+ * @param rows - How many rows the mask covers.
115
+ */
116
+ setHoldMask(mask: NodeMask | null, rows: number): void;
107
117
  /**
108
118
  * Take a node out of the simulation, and the links ngraph drops with it.
109
119
  *
@@ -186,6 +186,11 @@ export interface SimulationEngineInit {
186
186
  */
187
187
  export declare class SimulationLayoutEngine extends LayoutEngine {
188
188
  #private;
189
+ /**
190
+ * Every simulation accepts a scope: a held row is OR-ed into the fixed-node mask, so the
191
+ * simulation stops integrating it as well as publishing it. See `LayoutEngineStatics.scoped`.
192
+ */
193
+ static scoped: boolean;
189
194
  /** Which simulation this bridge drives. */
190
195
  readonly simulationType: SimulationType;
191
196
  /** The accelerator member this simulation needs, asked of the controller before every build. */
@@ -372,6 +377,12 @@ export declare class SimulationLayoutEngine extends LayoutEngine {
372
377
  * @param n - The node that was unpinned.
373
378
  */
374
379
  unpin(n: Node): void;
380
+ /**
381
+ * Holds the rows a scoped layout may not move, in the simulation's own fixed-node mask too.
382
+ * @param mask - One bit per row to hold, or null to hold nothing.
383
+ * @param rows - How many rows the mask covers.
384
+ */
385
+ setHoldMask(mask: NodeMask | null, rows: number): void;
375
386
  /**
376
387
  * Places one node now. A drag reaches this per pointer move, and `replayPins` once per pin.
377
388
  * @param n - The node that moved.
@@ -92,6 +92,14 @@ export declare class AlgorithmManager implements Manager {
92
92
  * @returns The target.
93
93
  */
94
94
  private targetFor;
95
+ /**
96
+ * A run's scope as bitmaps over the snapshot the graph holds now. The run resolved it when it
97
+ * started; a freeze since then resolves it again, so an algorithm never reads bitmaps over a
98
+ * snapshot that is no longer the graph.
99
+ * @param context - What the run handed the work.
100
+ * @returns The scope, or null when the run carries none this module can read.
101
+ */
102
+ private scopeOf;
95
103
  /**
96
104
  * Do the work.
97
105
  *
@@ -80,6 +80,17 @@ export declare class DataManager implements Manager {
80
80
  private logger;
81
81
  /** The one graph-format builder and its cached snapshot; replaced only by `clear()`/`dispose()`. */
82
82
  private store;
83
+ /**
84
+ * The edge counter every store this manager builds draws from, so a Clear or a replacing
85
+ * import never rewinds it and an edge id is never issued twice (design/sets 4.2).
86
+ */
87
+ private readonly edgeCounter;
88
+ /**
89
+ * The attribute revisions and the input tick (design/sets 6.2), the same object the session
90
+ * over this manager reads, handed to every store this manager builds so a freeze advances it
91
+ * and a Clear never rewinds it.
92
+ */
93
+ private readonly inputs;
83
94
  graphResults?: AdHocData;
84
95
  meshCache: MeshCache;
85
96
  private graphContext;