@graphty/graphty-element 2.6.1 → 3.0.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 (163) hide show
  1. package/dist/ai.js +3 -3
  2. package/dist/catalog.js +53 -54
  3. package/dist/chunks/{AiManager-4iQpsJW1.js → AiManager-Bhh0rR_p.js} +706 -655
  4. package/dist/chunks/GraphSession-DPoTaT3b.js +21175 -0
  5. package/dist/chunks/{GraphtyLogger-B_O67a6c.js → GraphtyLogger-BtcBJQPL.js} +1 -1
  6. package/dist/chunks/{VoiceInputAdapter-Cc6mHXTI.js → VoiceInputAdapter-CdLsJ_nG.js} +1 -1
  7. package/dist/chunks/{XRPivotCameraController-BLa89LXn.js → XRPivotCameraController-CiLJ9Gz6.js} +2 -2
  8. package/dist/chunks/algorithms-qij74zEN.js +6811 -0
  9. package/dist/chunks/{capability-check-Am2zliFj.js → capability-check-BbgTejS3.js} +1 -1
  10. package/dist/chunks/definePalette-BYt2Llxs.js +1333 -0
  11. package/dist/chunks/fields-5uVC1Pll.js +4999 -0
  12. package/dist/chunks/{format-detection-BHwrAVzW.js → format-detection-FKaDMshR.js} +1 -1
  13. package/dist/chunks/{index-BkBLbvui.js → index-Cc_6D9hV.js} +6034 -7127
  14. package/dist/chunks/interpolation-Dk206AhZ.js +105 -0
  15. package/dist/chunks/paletteRegistry-De3CGdst.js +357 -0
  16. package/dist/chunks/parse-SVp77JbE.js +669 -0
  17. package/dist/chunks/{pluginRegistry-Bs8bEkz9.js → pluginRegistry-Ddfl6Mv2.js} +27 -24
  18. package/dist/chunks/{registry-BdGvyZou.js → registry-CgMqldp4.js} +1 -1
  19. package/dist/chunks/{DataSource-BL2UzPff.js → sources-BbAJCDIH.js} +279 -108
  20. package/dist/commands.d.ts +128 -19
  21. package/dist/commands.js +49 -1
  22. package/dist/custom-elements.json +1 -1
  23. package/dist/extend.d.ts +10 -2
  24. package/dist/extend.js +64 -57
  25. package/dist/graphty-catalog.json +6 -3
  26. package/dist/graphty.bundle.js +267177 -240648
  27. package/dist/graphty.js +84 -78
  28. package/dist/index.d.ts +4 -0
  29. package/dist/logging.js +2 -2
  30. package/dist/schema.js +70 -71
  31. package/dist/session.d.ts +5 -6
  32. package/dist/session.js +40 -86
  33. package/dist/src/Edge.d.ts +31 -67
  34. package/dist/src/Graph.d.ts +335 -77
  35. package/dist/src/Node.d.ts +36 -3
  36. package/dist/src/NodeBehavior.d.ts +28 -0
  37. package/dist/src/Styles.d.ts +15 -4
  38. package/dist/src/acceleration/AccelerationController.d.ts +8 -0
  39. package/dist/src/acceleration/narrow.d.ts +9 -1
  40. package/dist/src/acceleration/types.d.ts +10 -0
  41. package/dist/src/ai/AiController.d.ts +12 -0
  42. package/dist/src/ai/AiManager.d.ts +7 -0
  43. package/dist/src/ai/commands/AlgorithmCommands.d.ts +1 -1
  44. package/dist/src/ai/commands/LayoutCommands.d.ts +1 -1
  45. package/dist/src/ai/commands/StyleCommands.d.ts +1 -1
  46. package/dist/src/ai/commands/types.d.ts +20 -1
  47. package/dist/src/algorithms/Algorithm.d.ts +21 -4
  48. package/dist/src/algorithms/BFSAlgorithm.d.ts +0 -9
  49. package/dist/src/algorithms/BellmanFordAlgorithm.d.ts +0 -14
  50. package/dist/src/algorithms/DFSAlgorithm.d.ts +1 -1
  51. package/dist/src/algorithms/FloydWarshallAlgorithm.d.ts +5 -0
  52. package/dist/src/algorithms/GirvanNewmanAlgorithm.d.ts +5 -0
  53. package/dist/src/algorithms/LeidenAlgorithm.d.ts +5 -0
  54. package/dist/src/algorithms/PageRankAlgorithm.d.ts +1 -1
  55. package/dist/src/algorithms/StronglyConnectedComponentsAlgorithm.d.ts +1 -1
  56. package/dist/src/algorithms/metrics/fields.d.ts +23 -1
  57. package/dist/src/algorithms/utils/graphUtils.d.ts +13 -1
  58. package/dist/src/catalog/paletteRegistry.d.ts +4 -4
  59. package/dist/src/catalog/registry.d.ts +3 -2
  60. package/dist/src/catalog/types.d.ts +18 -1
  61. package/dist/src/config/GraphStyle.d.ts +1 -1
  62. package/dist/src/config/StyleTemplate.d.ts +2 -2
  63. package/dist/src/config/xr-config-schema.d.ts +4 -4
  64. package/dist/src/data/CSVDataSource.d.ts +77 -22
  65. package/dist/src/data/ErrorAggregator.d.ts +5 -0
  66. package/dist/src/data/GEXFDataSource.d.ts +12 -61
  67. package/dist/src/data/GraphMLDataSource.d.ts +3 -44
  68. package/dist/src/data/GraphStore.d.ts +322 -15
  69. package/dist/src/data/JsonDataSource.d.ts +43 -1
  70. package/dist/src/data/graph-io-import.d.ts +89 -0
  71. package/dist/src/data/graph-io-records.d.ts +64 -0
  72. package/dist/src/data/lane.d.ts +23 -0
  73. package/dist/src/data/positions.d.ts +13 -0
  74. package/dist/src/data/seedPosition.d.ts +16 -0
  75. package/dist/src/errors/GraphtyError.d.ts +3 -1
  76. package/dist/src/errors/codes.d.ts +23 -0
  77. package/dist/src/events.d.ts +12 -0
  78. package/dist/src/graphty-element.d.ts +149 -54
  79. package/dist/src/input/types.d.ts +2 -0
  80. package/dist/src/layout/D3GraphLayoutEngine.d.ts +17 -3
  81. package/dist/src/layout/FixedLayoutEngine.d.ts +20 -4
  82. package/dist/src/layout/KamadaKawaiLayoutEngine.d.ts +6 -0
  83. package/dist/src/layout/LayoutEngine.d.ts +214 -116
  84. package/dist/src/layout/NGraphLayoutEngine.d.ts +10 -3
  85. package/dist/src/layout/SimulationLayoutEngine.d.ts +8 -3
  86. package/dist/src/managers/AlgorithmManager.d.ts +24 -5
  87. package/dist/src/managers/DataManager.d.ts +258 -181
  88. package/dist/src/managers/EventManager.d.ts +5 -2
  89. package/dist/src/managers/GraphContext.d.ts +7 -0
  90. package/dist/src/managers/InputManager.d.ts +11 -0
  91. package/dist/src/managers/LayoutManager.d.ts +129 -50
  92. package/dist/src/managers/RenderManager.d.ts +14 -1
  93. package/dist/src/managers/UpdateManager.d.ts +20 -0
  94. package/dist/src/screenshot/ScreenshotCapture.d.ts +1 -1
  95. package/dist/src/session/GraphSession.d.ts +83 -6
  96. package/dist/src/session/commands/algo.d.ts +169 -0
  97. package/dist/src/session/commands/config.d.ts +45 -0
  98. package/dist/src/session/commands/data.d.ts +178 -0
  99. package/dist/src/session/commands/doors.d.ts +93 -0
  100. package/dist/src/session/commands/index.d.ts +20 -0
  101. package/dist/src/session/commands/layout.d.ts +104 -0
  102. package/dist/src/session/commands/positions.d.ts +30 -0
  103. package/dist/src/session/commands/sets.d.ts +113 -0
  104. package/dist/src/session/commands/style.d.ts +92 -0
  105. package/dist/src/session/commands/view.d.ts +57 -0
  106. package/dist/src/session/commands/visibility.d.ts +41 -0
  107. package/dist/src/session/data.d.ts +131 -4
  108. package/dist/src/session/index.d.ts +1 -1
  109. package/dist/src/session/planning.d.ts +25 -8
  110. package/dist/src/session/project/Dispatcher.d.ts +905 -0
  111. package/dist/src/session/project/History.d.ts +382 -0
  112. package/dist/src/session/project/arrangement.d.ts +247 -0
  113. package/dist/src/session/project/derive.d.ts +132 -0
  114. package/dist/src/session/project/digest.d.ts +33 -0
  115. package/dist/src/session/project/draft.d.ts +194 -0
  116. package/dist/src/session/project/graphOps.d.ts +304 -0
  117. package/dist/src/session/project/ingest.d.ts +364 -0
  118. package/dist/src/session/project/state.d.ts +145 -0
  119. package/dist/src/session/project/strict.d.ts +68 -0
  120. package/dist/src/session/results/RunResult.d.ts +48 -0
  121. package/dist/src/session/results/statistics.d.ts +20 -0
  122. package/dist/src/session/runs/Run.d.ts +80 -4
  123. package/dist/src/session/runs/RunsApi.d.ts +23 -6
  124. package/dist/src/session/runs/types.d.ts +25 -6
  125. package/dist/src/session/scope/ElementMask.d.ts +14 -0
  126. package/dist/src/session/scope/ScopeApi.d.ts +3 -22
  127. package/dist/src/session/scope/spaces.d.ts +29 -0
  128. package/dist/src/session/sealed.d.ts +22 -0
  129. package/dist/src/session/selection/SelectionApi.d.ts +14 -4
  130. package/dist/src/session/sets/SetsApi.d.ts +13 -5
  131. package/dist/src/session/sets/store.d.ts +54 -53
  132. package/dist/src/session/sets/types.d.ts +5 -2
  133. package/dist/src/session/styles/Layer.d.ts +5 -0
  134. package/dist/src/session/styles/StylesApi.d.ts +68 -17
  135. package/dist/src/session/styles/autoApply.d.ts +64 -53
  136. package/dist/src/session/styles/index.d.ts +3 -3
  137. package/dist/src/session/styles/predicate.d.ts +7 -0
  138. package/dist/src/session/styles/repaint.d.ts +16 -1
  139. package/dist/src/session/styles/sources.d.ts +1 -1
  140. package/dist/src/session/types.d.ts +625 -54
  141. package/dist/src/session/visibility/VisibilityApi.d.ts +38 -18
  142. package/dist/src/session/visibility/filter.d.ts +10 -0
  143. package/dist/src/simple/defineAlgorithm.d.ts +28 -0
  144. package/dist/src/simple/defineLayout.d.ts +35 -0
  145. package/dist/src/simple/defineLogDestination.d.ts +31 -0
  146. package/dist/src/simple/definePalette.d.ts +26 -0
  147. package/dist/src/simple/definition.d.ts +106 -0
  148. package/dist/src/simple/options.d.ts +33 -0
  149. package/dist/src/simple/source.d.ts +49 -0
  150. package/dist/src/simple/types.d.ts +366 -0
  151. package/dist/src/simple/view.d.ts +107 -0
  152. package/dist/webgpu.js +2 -2
  153. package/package.json +10 -12
  154. package/dist/chunks/GraphSession-BhuHSXIo.js +0 -12819
  155. package/dist/chunks/GraphStyle-Cwr55SAE.js +0 -65
  156. package/dist/chunks/algorithms-BJ6DQMOe.js +0 -3777
  157. package/dist/chunks/detect-fyuVnlCT.js +0 -88
  158. package/dist/chunks/interpolation-DY-PNpqX.js +0 -43
  159. package/dist/chunks/optionsFromZod-CKMYSwTz.js +0 -3636
  160. package/dist/chunks/paletteRegistry-BCFSwJGK.js +0 -1196
  161. package/dist/chunks/parse-BMTqt4SS.js +0 -3658
  162. package/dist/src/data/csv-variant-detection.d.ts +0 -29
  163. package/dist/src/data/ingest.d.ts +0 -104
@@ -1,33 +1,42 @@
1
- import { type DerivedGraph, type DuplicatePolicy, type GraphSnapshot } from "@graphty/graph-format";
1
+ import { type DerivedGraph, type GraphSnapshot } from "@graphty/graph-format";
2
2
  import type { EdgeId } from "../catalog/types";
3
3
  import type { AdHocData } from "../config";
4
+ import { WRITABLE_LANE } from "../data/lane";
4
5
  import type { ElementPositions } from "../data/positions";
5
- import { type ImportReport } from "../data/report";
6
- import { Edge, EdgeMap } from "../Edge";
7
- import type { LayoutEngine } from "../layout/LayoutEngine";
6
+ import type { ImportReport } from "../data/report";
7
+ import { Edge } from "../Edge";
8
+ import { type LayoutEngine } from "../layout/LayoutEngine";
8
9
  import { MeshCache } from "../meshes/MeshCache";
9
10
  import { Node, NodeIdType } from "../Node";
10
- import type { DirectionProvenance } from "../session/types";
11
+ import type { LaneStore } from "../session/GraphSession";
12
+ import type { Dispatcher, UndoableContext } from "../session/project/Dispatcher";
13
+ import { type AddEdgesOptions } from "../session/project/ingest";
14
+ import type { GraphSlice } from "../session/project/state";
15
+ import type { DirectionProvenance, HistoryCause, ReadonlyElementPositions } from "../session/types";
11
16
  import type { Styles } from "../Styles";
12
17
  import type { EventManager } from "./EventManager";
13
18
  import type { GraphContext } from "./GraphContext";
14
19
  import type { Manager } from "./interfaces";
15
- /** What a caller may say about one `addEdges` call that the configuration does not already say. */
16
- export interface AddEdgesOptions {
17
- /** The JMESPath expression naming the source endpoint, overriding the configured one. */
18
- readonly source?: string;
19
- /** The JMESPath expression naming the target endpoint, overriding the configured one. */
20
- readonly target?: string;
21
- /**
22
- * What to do with a record naming an ordered pair the graph already holds, overriding
23
- * `data.knownFields.repeatedEdges` for this call alone.
24
- *
25
- * The expand-a-node path passes `"first"`, because "fetch the neighbourhood of this node" is a
26
- * request that legitimately re-supplies edges the graph already has, and the element knows
27
- * that about its own call site.
28
- */
29
- readonly repeated?: DuplicatePolicy;
30
- }
20
+ export type { AddEdgesOptions } from "../session/project/ingest";
21
+ /**
22
+ * A data manager as its own session reads it: every store member, with the writable lane under
23
+ * `positions`, which the session's dispatcher writes when it places, pins or restores nodes. No
24
+ * entry point exports it; the manager's own `positions` is read-only.
25
+ * @param manager - The data manager.
26
+ * @returns The store the session is handed.
27
+ */
28
+ export declare function laneStoreOf(manager: DataManager): LaneStore;
29
+ /**
30
+ * A standalone renderer test's reach into a data manager's collections: registering a render
31
+ * object it built by hand, as ingest would have. No entry point exports it; the collections are
32
+ * read-only to everything else, and nodes and edges arrive through the data doors.
33
+ */
34
+ export declare const dataManagerInternals: {
35
+ /** Register a node under its id. */
36
+ adoptNode(manager: DataManager, node: Node): void;
37
+ /** Register an edge under its id, its endpoint pair and, when it has one, its row. */
38
+ adoptEdge(manager: DataManager, edge: Edge): void;
39
+ };
31
40
  /**
32
41
  * Manages all data operations for nodes and edges
33
42
  * Handles CRUD operations, caching, and data source loading
@@ -58,26 +67,38 @@ export interface AddEdgesOptions {
58
67
  export declare class DataManager implements Manager {
59
68
  private eventManager;
60
69
  private styles;
61
- nodes: Map<string | number, Node>;
70
+ private readonly nodeMap;
71
+ private readonly edgeMap;
72
+ private readonly edgeRows;
73
+ /**
74
+ * Every node the graph holds, keyed by id. Read-only: nodes arrive and leave through the data
75
+ * doors, which are undoable steps.
76
+ * @returns The nodes.
77
+ */
78
+ get nodes(): ReadonlyMap<string | number, Node>;
79
+ /** {@link DataManager.nodes}: the node map with no writer. */
80
+ private readonly nodeView;
62
81
  /**
63
82
  * Every edge the graph holds, keyed by `Edge.id`.
64
83
  *
65
84
  * The key type is `string` and not `string | number`, because `Edge.id` is the element's own
66
85
  * edge counter printed as a string and nothing else. While the key was widened, `getEdge(0)`
67
86
  * compiled, answered `undefined` for the edge whose id is `"0"`, and said nothing about it.
87
+ * @returns The edges.
68
88
  */
69
- edges: Map<string, Edge>;
89
+ get edges(): ReadonlyMap<string, Edge>;
90
+ /** {@link DataManager.edges}: the edge map with no writer. */
91
+ private readonly edgeView;
70
92
  /** Goes up on every edge added or removed, so a cache over the edge set knows it is stale. */
71
93
  edgeVersion: number;
72
94
  nodeCache: Map<NodeIdType, Node>;
73
- edgeCache: EdgeMap;
74
95
  /**
75
96
  * Render objects by their store edge index, so a freeze report's `edgeRemap` -- and a removal,
76
97
  * which hands back the incident edge indices and nothing else -- can find them in O(1). Sparse:
77
98
  * an index with no render object yet, or whose edge was removed, reads `undefined`.
99
+ * @returns The edges by row, read-only.
78
100
  */
79
- readonly edgesByIndex: (Edge | undefined)[];
80
- private logger;
101
+ get edgesByIndex(): readonly (Edge | undefined)[];
81
102
  /** The one graph-format builder and its cached snapshot; replaced only by `clear()`/`dispose()`. */
82
103
  private store;
83
104
  /**
@@ -91,7 +112,19 @@ export declare class DataManager implements Manager {
91
112
  * and a Clear never rewinds it.
92
113
  */
93
114
  private readonly inputs;
94
- graphResults?: AdHocData;
115
+ /**
116
+ * Graph-level results a plugin algorithm without a descriptor wrote, kept as the `graphResults`
117
+ * value of the graph. Read-only, except to a plugin while `algo.legacy` runs it: what it writes
118
+ * then is part of that command's step.
119
+ * @returns The value, or undefined when none was written.
120
+ */
121
+ get graphResults(): AdHocData | undefined;
122
+ /**
123
+ * Write graph-level results; only a plugin can, while `algo.legacy` runs it.
124
+ * @param value - The results.
125
+ * @throws A `GraphtyError` with `E_UNSUPPORTED` outside a plugin run.
126
+ */
127
+ set graphResults(value: AdHocData | undefined);
95
128
  meshCache: MeshCache;
96
129
  private graphContext;
97
130
  private shouldStartLayout;
@@ -106,29 +139,34 @@ export declare class DataManager implements Manager {
106
139
  * encoding of two ids is ambiguous for some pair of them.
107
140
  */
108
141
  private pendingByPair;
142
+ /** Turns records and data sources into the graph; this manager draws what it produces. */
143
+ private readonly ingest;
109
144
  /**
110
- * The store edge index each record identifier has already produced, when
111
- * `knownFields.edgeIdPath` names one. Empty when it does not, which is the default.
112
- */
113
- private edgesByRecordId;
114
- /** What the last load did, for `session.data.lastImport()`. Null until something has loaded. */
115
- private importReport;
116
- /**
117
- * The endpoint expressions the load in progress resolved, so a chunked load probes ONCE.
118
- *
119
- * A file that spells one chunk's edges `source`/`target` and the next chunk's `from`/`to` is a
120
- * broken file, and letting each chunk decide for itself makes the answer both unreportable and
121
- * dependent on how the file happened to be split.
145
+ * The graph primitives every write goes through. A data manager on its own has nothing to
146
+ * record into; the graph's session hands it its own in {@link DataManager.bindSession}.
122
147
  */
123
- private loadEndpoints;
124
- /** The tally the load in progress is counting into, or null outside a load. */
125
- private loadTally;
148
+ private graph;
149
+ /** The session's dispatcher, once bound: the data doors dispatch through it. */
150
+ private dispatcher;
151
+ /** The edges the last removal took out, for the doors that answer with them. */
152
+ private removedEdges;
153
+ /** Why rows are arriving: set while a dispatched command writes, for the `data-added` event. */
154
+ private cause;
126
155
  /**
127
156
  * Bumped by every REPLACING load as it is asked for, and by `supersedeLoads`. A load that
128
157
  * sees it move has been overtaken, and stops with `E_SUPERSEDED` rather than touching the
129
158
  * graph: see `addDataFromSource`.
130
159
  */
131
160
  private replaceGeneration;
161
+ /** The loads dispatched and not yet settled, so a newer replacing load can withdraw them. */
162
+ private readonly inFlight;
163
+ /**
164
+ * The id each load's events carry, by its source's configuration: the dispatcher hands the
165
+ * command on as a frozen copy, and `data.import` keeps only the configuration by reference.
166
+ */
167
+ private readonly loadIds;
168
+ /** The id of the import running now, for the events it emits. */
169
+ private loadId;
132
170
  /**
133
171
  * Creates an instance of DataManager
134
172
  * @param eventManager - Event manager for emitting data events
@@ -146,6 +184,11 @@ export declare class DataManager implements Manager {
146
184
  * @returns the snapshot
147
185
  */
148
186
  getSnapshot(): GraphSnapshot;
187
+ /**
188
+ * Whether the next {@link getSnapshot} would freeze a new snapshot.
189
+ * @returns True when the store is not settled.
190
+ */
191
+ get snapshotStale(): boolean;
149
192
  /**
150
193
  * The undirected view of a snapshot, built once per snapshot and cached.
151
194
  * @param snapshot - a snapshot this manager produced
@@ -160,9 +203,28 @@ export declare class DataManager implements Manager {
160
203
  * in one place and nothing is lost when the graph is frozen again. A row that no layout has
161
204
  * placed reads as NaN, never as the origin: zero is a real coordinate and "not placed yet" is
162
205
  * not.
206
+ *
207
+ * Read-only here: a write would move nodes with no step. The element's own engines reach the
208
+ * writable lane through `writableLane`; a consumer places nodes through
209
+ * `session.positions.set`.
210
+ * @returns the coordinates, read-only
211
+ */
212
+ get positions(): ReadonlyElementPositions;
213
+ /** The coordinates, read-only; reads whichever lane the store holds now. */
214
+ private readonly readonlyLane;
215
+ /**
216
+ * The writable lane, for the element's own engines and nodes. See `writableLane`.
163
217
  * @returns the live position array
164
218
  */
165
- get positions(): ElementPositions;
219
+ get [WRITABLE_LANE](): ElementPositions;
220
+ /**
221
+ * Whether a load from a data source is still streaming records in.
222
+ *
223
+ * A static layout reads it to tell a chunk of a load, after which the whole graph is arranged
224
+ * again, from a reader's add to a finished graph, after which existing nodes stay put.
225
+ * @returns true between a load's first chunk and its end
226
+ */
227
+ get isLoading(): boolean;
166
228
  /**
167
229
  * How many nodes the DATA arrived carrying a coordinate for.
168
230
  *
@@ -185,6 +247,87 @@ export declare class DataManager implements Manager {
185
247
  * @returns the report, or null when nothing has been loaded into this graph
186
248
  */
187
249
  get lastImport(): ImportReport | null;
250
+ /**
251
+ * Write through the session from here on: the data doors dispatch `data.apply` and
252
+ * `data.import`, and the session carries both out through this manager's ingest, over this
253
+ * manager's store.
254
+ * @param dispatcher - The session's dispatcher.
255
+ * @param hooks - What the graph does around a write.
256
+ * @param hooks.rowsAdded - Called by each command that adds rows, after it wrote them, with how
257
+ * that command starts work as its deferred members.
258
+ * @param hooks.loading - Called with true when an import starts reading and false when it stops.
259
+ * @param hooks.removing - Called with the nodes and edges a removal names, before it writes.
260
+ */
261
+ bindSession(dispatcher: Dispatcher, hooks: {
262
+ rowsAdded(after: UndoableContext["after"] | undefined): void;
263
+ loading(active: boolean): void;
264
+ removing(nodes: readonly NodeIdType[], edges: readonly EdgeId[]): void;
265
+ }): void;
266
+ /**
267
+ * Carry out one mutation through ingest, drawing what it adds as it goes.
268
+ * @param mutation - The mutation.
269
+ * @param writer - The command's writer.
270
+ */
271
+ private applyMutation;
272
+ /**
273
+ * The id a node is held under, for an id that may be spelled as the other type (see
274
+ * {@link DataManager.getNode}); an edge id is taken as it is.
275
+ * @param target - Node or edge.
276
+ * @param id - The id as given.
277
+ * @returns The id the graph holds it under, or the one given when it holds none.
278
+ */
279
+ private resolveId;
280
+ /**
281
+ * Strict state: the drawn maps keyed exactly like the `graph` slice. An edge the slice holds
282
+ * may instead be waiting for an endpoint that has not arrived.
283
+ * @param slice - The slice the last pass derived.
284
+ * @returns One sentence per problem; empty when there is none.
285
+ */
286
+ sliceProblems(slice: GraphSlice): string[];
287
+ /**
288
+ * Bring the render objects in line with the `graph` slice: what the derivation lane's `graph`
289
+ * hook runs, forward and on undo, redo and rollback alike. A node or edge the slice holds and
290
+ * nothing draws is built; one drawn that the slice no longer holds is torn down; one whose
291
+ * record changed is handed the new record. Forward adds were drawn as they were ingested, so
292
+ * for them this finds nothing to build.
293
+ * @param slice - The slice to draw.
294
+ * @param dirty - The slice's keys changed since the last pass.
295
+ * @param cause - What moved the state, for the events.
296
+ * @returns How many rows were built and torn down.
297
+ */
298
+ reconcile(slice: GraphSlice, dirty: ReadonlySet<string>, cause: HistoryCause): {
299
+ added: number;
300
+ removed: number;
301
+ };
302
+ /**
303
+ * Tear down nodes' render objects and every render edge attached to one of them, leaving the
304
+ * store alone: the store already reflects the state being drawn.
305
+ * @param ids - The nodes.
306
+ * @param slice - The slice being drawn, which may still hold an edge of a node going.
307
+ * @returns The ids of the edges torn down with them and not left waiting.
308
+ */
309
+ private dropRenderNodes;
310
+ /**
311
+ * Tear down what draws rows a forward removal took out of the store: the edges first, since an
312
+ * edge reads its endpoints' meshes while it goes, then the nodes. One `elements-removed`.
313
+ * @param nodes - The node ids removed.
314
+ * @param edges - The edge ids removed, including every edge attached to a removed node.
315
+ */
316
+ private dropRendered;
317
+ /** Tear down every render object: the graph was emptied. */
318
+ private dropEverythingRendered;
319
+ /**
320
+ * Take one node's render object out of every structure that holds it and free it. Its edges
321
+ * must already be gone.
322
+ * @param node - The node.
323
+ */
324
+ private disposeRenderNode;
325
+ /**
326
+ * What ingest needs from the render half: which edges exist (built or pending), and what to
327
+ * do with each record once the store holds it.
328
+ * @returns the host, reading this manager's fields lazily
329
+ */
330
+ private ingestHost;
188
331
  /**
189
332
  * Build the store, wiring its three freeze callbacks back into this manager.
190
333
  *
@@ -291,27 +434,27 @@ export declare class DataManager implements Manager {
291
434
  */
292
435
  addNode(node: AdHocData, idPath?: string): void;
293
436
  /**
294
- * The id `addNodes` reads off a node record.
295
- * @param node - the record
437
+ * Replace every node with these, as one step: a node the records name again keeps its row and
438
+ * its edges, and one they no longer name goes, with its edges. A set past the render ceiling
439
+ * is refused with `E_TOO_LARGE` and the step rolls back, so the graph keeps the nodes it had.
440
+ * @param nodes - the nodes the graph should hold afterwards
296
441
  * @param idPath - JMESPath expression to extract the id; the configured node id path when unset
297
- * @returns the node's id
298
- */
299
- nodeIdOf(node: Record<string | number, unknown>, idPath?: string): NodeIdType;
300
- /**
301
- * Refuse a replacing node set the renderer cannot hold, before the replace removes anything.
302
- *
303
- * The node half of what {@link setEdges} decides first: the new set is counted against an
304
- * emptied graph, so a refused replace keeps the nodes the graph had.
305
- * @param count - how many distinct nodes the graph would hold afterwards
306
- * @throws A `GraphtyError` with `E_TOO_LARGE` when `count` is past the ceiling
307
442
  */
308
- refuseNodeSetAboveCeiling(count: number): void;
443
+ setNodes(nodes: Record<string | number, unknown>[], idPath?: string): void;
309
444
  /**
310
445
  * Adds multiple nodes to the graph
311
446
  * @param nodes - Array of node data objects
312
447
  * @param idPath - JMESPath expression to extract node ID from data
313
448
  */
314
449
  addNodes(nodes: Record<string | number, unknown>[], idPath?: string): void;
450
+ /**
451
+ * Build the render object for a node the store has just taken.
452
+ * @param nodeId - the node id
453
+ * @param node - the raw record
454
+ * @param index - the row the store gave it; INVALID_INDEX for an id graph-format will not
455
+ * take, and the node renders anyway. See the class comment.
456
+ */
457
+ private buildNode;
315
458
  /**
316
459
  * Build the render objects for pending edges whose nodes now exist.
317
460
  *
@@ -320,7 +463,7 @@ export declare class DataManager implements Manager {
320
463
  */
321
464
  private processPendingEdges;
322
465
  /**
323
- * Record a freshly built render edge in all three of the places that index it.
466
+ * Record a freshly built render edge in both of the places that index it.
324
467
  * @param edge - the new render object
325
468
  * @param edgeIndex - the index the builder gave this edge. Never INVALID_INDEX: an edge whose
326
469
  * endpoint ids graph-format will not store is rejected before it reaches here
@@ -346,7 +489,7 @@ export declare class DataManager implements Manager {
346
489
  */
347
490
  getNode(nodeId: NodeIdType): Node | undefined;
348
491
  /**
349
- * Remove a node AND every edge attached to it.
492
+ * Remove a node AND every edge attached to it, as one undoable step.
350
493
  *
351
494
  * The cascade is what the name says, and it used to be missing: the store side already
352
495
  * tombstoned the incident edges, but their render objects survived with their meshes, their
@@ -362,11 +505,11 @@ export declare class DataManager implements Manager {
362
505
  */
363
506
  removeNodeAndIncidentEdges(nodeId: NodeIdType): readonly EdgeId[] | null;
364
507
  /**
365
- * Take a node out of the store and tear down every edge that was attached to it.
366
- * @param node - the node being removed
367
- * @returns the ids of the edges that went with it
508
+ * Carry out one mutation: through the session's dispatcher once bound, so it is a step, or
509
+ * straight through the primitives on a data manager with no session.
510
+ * @param mutation - The mutation.
368
511
  */
369
- private detachNodeFromStore;
512
+ private write;
370
513
  /**
371
514
  * Take one render edge out of every structure that holds it, and free its meshes.
372
515
  *
@@ -406,40 +549,17 @@ export declare class DataManager implements Manager {
406
549
  */
407
550
  addEdges(edges: Record<string | number, unknown>[], options?: AddEdgesOptions): void;
408
551
  /**
409
- * The endpoint expressions this batch is read with, resolved once per load rather than once
410
- * per batch when a load is in progress.
411
- * @param edges - the batch's records
412
- * @param options - the caller's overrides, if any
413
- * @returns the expressions
552
+ * Build the render object for an edge the store has just taken, or defer it until both
553
+ * endpoints have one.
554
+ * @param stored - the edge, its resolved endpoints and the row and counter the store gave it
414
555
  */
415
- private endpointsFor;
416
- /**
417
- * The edge a record repeats, or null when it repeats none.
418
- * @param sourceId - the source endpoint id
419
- * @param targetId - the target endpoint id
420
- * @param recordId - the value of `knownFields.edgeIdPath`, when one is configured
421
- * @returns the existing edge, or null
422
- */
423
- private knownEdgeFor;
556
+ private buildEdge;
424
557
  /**
425
558
  * The edge occupying one store row, whether or not its render object has been built.
426
559
  * @param edgeIndex - the row
427
560
  * @returns the existing edge, or null when the row is not one this manager holds
428
561
  */
429
562
  private existingAt;
430
- /**
431
- * Apply the repeat policy to one record that names an edge the graph already holds.
432
- * @param known - the edge already present
433
- * @param record - the repeating record
434
- * @param weight - the repeating record's resolved weight
435
- * @param policy - what to do about it
436
- * @param sourceId - the source endpoint id, for the error message
437
- * @param targetId - the target endpoint id, for the error message
438
- * @param tally - the load's counters
439
- * @returns true when the repeat has been dealt with and must not become an edge of its own
440
- * @throws A `GraphtyError` with `E_DUPLICATE_EDGE` under the `"error"` policy.
441
- */
442
- private mergeRepeat;
443
563
  /**
444
564
  * Gets an edge by its ID
445
565
  * @param edgeId - Edge identifier
@@ -451,6 +571,11 @@ export declare class DataManager implements Manager {
451
571
  *
452
572
  * Plural because "the edge between a and b" stopped being a single thing the moment parallel
453
573
  * edges became representable.
574
+ *
575
+ * Answered by the store: the builder's incidence lists name the live edges between the two
576
+ * rows, and `edgesByIndex` turns each into its render object. An edge whose render object is
577
+ * still pending is left out, and so, in an undirected graph, is an edge recorded the other way
578
+ * round -- the pair is ORDERED, the same question for either direction.
454
579
  * @param srcNodeId - Source node identifier
455
580
  * @param dstNodeId - Destination node identifier
456
581
  * @returns the edges, oldest first; empty when there are none
@@ -470,22 +595,6 @@ export declare class DataManager implements Manager {
470
595
  * whatever `addEdges` throws.
471
596
  */
472
597
  setEdges(edges: Record<string | number, unknown>[], options?: AddEdgesOptions): void;
473
- /**
474
- * How many edges a batch would add, by the same tests the ingest loop applies.
475
- *
476
- * A record whose endpoint ids graph-format will not store adds nothing (the loop rejects it).
477
- * Under the `keep` policy every other record is an edge. Under a folding policy a record that
478
- * repeats an edge the graph holds, or a record earlier in the same batch, folds into it and
479
- * adds nothing; a repeat is named the way `knownEdgeFor` names it, by record id when one is
480
- * configured and stored, else by the ordered endpoint pair.
481
- * @param edges - the batch
482
- * @param endpoints - the batch's endpoint expressions
483
- * @param policy - the repeat policy the batch is under
484
- * @param replacing - true when every held edge is about to be removed, so none of them can be
485
- * repeated
486
- * @returns the number of edges the batch would add
487
- */
488
- private edgesAdded;
489
598
  /**
490
599
  * Removes an edge from the graph
491
600
  * @param edgeId - Edge identifier to remove
@@ -493,47 +602,10 @@ export declare class DataManager implements Manager {
493
602
  */
494
603
  removeEdge(edgeId: string): boolean;
495
604
  /**
496
- * Adopt the direction a file declared, and say out loud when the element could not.
497
- *
498
- * The element reports the direction its DATA declares, so that a file which says it is
499
- * undirected is not counted, measured or offered algorithms as though it were a digraph. What
500
- * it must never do is overrule the consumer: `data.directed` set to a boolean settles the
501
- * question and locks the builder, and this reports that rather than fighting it.
502
- * @param type - the data source type, for the log line
503
- * @param declaration - what the file said, or null when it said nothing
504
- * @returns true once the question is settled and need not be asked again this import; false
505
- * while the source has still declared nothing
506
- */
507
- private applyDeclaredDirection;
508
- /**
509
- * Reserve a load's place in line, at the moment the caller asked for it.
510
- *
511
- * A caller that reads a file or sniffs a URL before it loads calls this FIRST, so a load that
512
- * was asked for later still wins however long the earlier one spends reading. A replacing load
513
- * supersedes every load reserved before it.
514
- * @param replace - Whether the load will replace the graph
515
- * @returns The generation to hand to `addDataFromSource` and `throwIfSuperseded`
516
- */
517
- beginLoad(replace: boolean): number;
518
- /**
519
- * Abandon every load in flight: each rejects with `E_SUPERSEDED` and adds nothing more.
520
- * The element's `clearData` calls this, so a load finishing after the graph was closed does
521
- * not bring its data back.
522
- */
523
- supersedeLoads(): void;
524
- /**
525
- * Throw `E_SUPERSEDED` when a load reserved at `generation` has been overtaken.
526
- * @param generation - What `beginLoad` returned for the load
527
- * @param type - The load's format, for the message
528
- */
529
- throwIfSuperseded(generation: number, type: string): void;
530
- /**
531
- * Loads data from a registered data source
532
- *
533
- * A REPLACING load reads the whole source into memory before it touches the store, and only
534
- * once the source has finished without an error does it clear the graph and add what it read.
535
- * A malformed or empty file therefore leaves the graph it would have replaced exactly as it
536
- * was. An additive load streams each chunk straight in, as it always has.
605
+ * Loads data from a registered data source, as one step: a `data.import` on its turn in the
606
+ * queue. A REPLACING load empties the graph in the same step, and a load that fails rolls the
607
+ * whole step back, so a malformed or empty file leaves the graph it would have replaced
608
+ * exactly as it was.
537
609
  *
538
610
  * A load that reads no node records and no edge records at all fails with `E_EMPTY_LOAD`
539
611
  * rather than completing with zero counts. A file of edges alone is not empty: its endpoints
@@ -550,54 +622,49 @@ export declare class DataManager implements Manager {
550
622
  * @param load.replace - Swap the graph for what the source holds, once it has all parsed
551
623
  * @param load.generation - The place `beginLoad` reserved for this load when the caller's call
552
624
  * was made; left unset, the load takes its place now
625
+ * @param load.coalesce - The key imports coalesce under while the first waits its turn
626
+ * @param load.setup - Declared at construction: it becomes the baseline
553
627
  */
554
628
  addDataFromSource(type: string, opts?: object, load?: {
555
629
  loadId?: number;
556
630
  replace?: boolean;
557
631
  generation?: number;
632
+ coalesce?: string;
633
+ setup?: boolean;
558
634
  }): Promise<void>;
559
635
  /**
560
- * Freeze one load's counters into the report a consumer reads, and keep it for `lastImport`.
561
- * @param format - the data source that read the file
562
- * @param tally - what the load counted
563
- * @returns the report
636
+ * Dispatch an import as one load: it carries its id into every event it emits, and it is
637
+ * withdrawn with `E_SUPERSEDED` once a replacing load asked for after it, or `clearData`,
638
+ * moves the generation on.
639
+ * @param command - The import.
640
+ * @param generation - What `beginLoad` returned when the load was asked for.
641
+ * @param loadId - The id its events carry.
564
642
  */
565
- private sealLoad;
643
+ private runLoad;
566
644
  /**
567
- * What the graph HOLDS right now, as the report and the session's own counts both mean it.
645
+ * Reserve a load's place in line, at the moment the caller asked for it.
568
646
  *
569
- * Read off the builder rather than off this manager's render maps, and that is the whole
570
- * point: an edge endpoint the file never declared as a node is created by the builder, so it
571
- * is in the graph and in `session.status.counts.nodes` while having no render `Node` and so no
572
- * entry in `nodes`. Counting the render objects made the report say two nodes for a load the
573
- * session reported three for -- one load, two numbers, disagreeing, which is the defect this
574
- * report exists to end rather than to repeat one level down.
575
- * @returns the node and edge counts the graph holds
647
+ * A caller that reads a file or sniffs a URL before it loads calls this FIRST, so a load that
648
+ * was asked for later still wins however long the earlier one spends reading. A replacing load
649
+ * supersedes every load reserved before it.
650
+ * @param replace - Whether the load will replace the graph
651
+ * @returns The generation to hand to `addDataFromSource` and `throwIfSuperseded`
576
652
  */
577
- private heldCounts;
653
+ beginLoad(replace: boolean): number;
578
654
  /**
579
- * Refuse to grow past what the renderer can draw, instead of freezing the tab.
580
- *
581
- * WHY A REFUSAL AND NOT A DEGRADED DRAW. The design says that above the render ceiling the
582
- * element draws a smaller render set, and above `edgesDrawn` it hides edges until the view
583
- * narrows. Neither exists yet. What exists is a renderer that, past these counts, exhausts
584
- * the renderer process and produces no further frame -- measured for issue #405 at 18,000
585
- * nodes / 180,000 edges on an RTX 4070 SUPER, where the renderer process reached 4.7 GB and
586
- * died while 17,000 / 170,000 loaded in 17 s. Until the degraded draw lands, the honest
587
- * behaviour at the ceiling is a coded error the consumer can show, so `DEFAULT_LIMITS` is
588
- * the number the element enforces rather than a number it merely publishes.
589
- *
590
- * `E_TOO_LARGE` is the code because the ceiling is a hard limit of this renderer, and the
591
- * caller's remedy is the one that code names: load a subset.
592
- * @param of - what is being counted
593
- * @param held - how many the graph holds already
594
- * @param adding - how many this call would add
595
- * @param limit - the most the renderer can draw
596
- * @throws A `GraphtyError` with `E_TOO_LARGE` when `held + adding` is past the limit
655
+ * Abandon every load in flight: each rejects with `E_SUPERSEDED`, its step rolled back, and
656
+ * adds nothing. The element's `clearData` calls this, so a load finishing after the graph was
657
+ * closed does not bring its data back.
597
658
  */
598
- private refuseAboveCeiling;
659
+ supersedeLoads(): void;
599
660
  /**
600
- * Clear all data
661
+ * Throw `E_SUPERSEDED` when a load reserved at `generation` has been overtaken.
662
+ * @param generation - What `beginLoad` returned for the load
663
+ * @param type - The load's format, for the message
664
+ */
665
+ throwIfSuperseded(generation: number, type: string): void;
666
+ /**
667
+ * Remove every node, edge, record and graph-level value, as one undoable step.
601
668
  */
602
669
  clear(): void;
603
670
  /**
@@ -605,9 +672,19 @@ export declare class DataManager implements Manager {
605
672
  * Called when layout has settled
606
673
  */
607
674
  startLabelAnimations(): void;
675
+ /**
676
+ * The node and edge counts the graph store holds: what `statistics()` and the stats panel
677
+ * report, including a pending edge and an endpoint no record declared as a node.
678
+ * @returns the node and edge counts
679
+ */
680
+ heldCounts(): {
681
+ nodes: number;
682
+ edges: number;
683
+ };
608
684
  /**
609
685
  * Get statistics about the data
610
- * @returns Object containing node count, edge count, and cached mesh count
686
+ * @returns the node and edge counts the graph holds -- the same numbers `statistics()` and the
687
+ * stats panel give -- and the cached mesh count
611
688
  */
612
689
  getStats(): {
613
690
  nodeCount: number;
@@ -4,6 +4,7 @@ import type { EdgeId, NodeId } from "../catalog/types";
4
4
  import type { ImportReport } from "../data/report";
5
5
  import type { DataLoadingErrorEvent, EdgeEvent, EventCallbackType, EventType, GraphErrorEvent, GraphEvent, NodeEvent, SelectionChangedEvent } from "../events";
6
6
  import type { Graph } from "../Graph";
7
+ import type { HistoryCause } from "../session/types";
7
8
  import type { GraphContext } from "./GraphContext";
8
9
  import type { Manager } from "./interfaces";
9
10
  /**
@@ -72,16 +73,18 @@ export declare class EventManager implements Manager {
72
73
  * Emits the removal event naming every node and edge one removal call took away.
73
74
  * @param nodes - the nodes that were removed
74
75
  * @param edges - every edge that was attached to one of them
76
+ * @param cause - what removed them, when it came through the history
75
77
  */
76
- emitElementsRemoved(nodes: NodeId[], edges: EdgeId[]): void;
78
+ emitElementsRemoved(nodes: NodeId[], edges: EdgeId[], cause?: HistoryCause): void;
77
79
  /**
78
80
  * Emits a data added event when nodes or edges are added
79
81
  * @param dataType - Type of data added (nodes or edges)
80
82
  * @param count - Number of items added
81
83
  * @param shouldStartLayout - Whether layout should be started
82
84
  * @param shouldZoomToFit - Whether to zoom to fit the data
85
+ * @param cause - what added them, when it came through the history
83
86
  */
84
- emitDataAdded(dataType: "nodes" | "edges", count: number, shouldStartLayout: boolean, shouldZoomToFit: boolean): void;
87
+ emitDataAdded(dataType: "nodes" | "edges", count: number, shouldStartLayout: boolean, shouldZoomToFit: boolean, cause?: HistoryCause): void;
85
88
  /**
86
89
  * Emit `snapshot-replaced` (graph-format design 14.4 rule 11).
87
90
  *