@graphty/graphty-element 2.6.2 → 3.0.1

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
@@ -15,15 +15,16 @@
15
15
  import type { DerivedGraph, GraphSnapshot, NodeId } from "@graphty/graph-format";
16
16
  import type { z } from "zod/v4";
17
17
  import type { AccelerationCapabilities, AccelerationPolicy, AccelerationStatus, GraphAccelerator } from "../acceleration";
18
- import type { AlgorithmKey, AttributeDescriptor, CatalogApi, DeprecatedCatalogMethod, EdgeId, RunId, Scope } from "../catalog/types";
18
+ import type { CameraState } from "../camera/types";
19
+ import type { AlgorithmKey, AttributeDescriptor, CatalogApi, DeprecatedCatalogMethod, EdgeId, LayoutId, RunId, Scope, SetId } from "../catalog/types";
19
20
  import type { DataConfig } from "../config/DataConfig";
20
- import type { ElementPositions } from "../data/positions";
21
+ import type { GraphBackgroundConfig, GraphSelectionStyleConfig, GraphSelectionStyleInput } from "../config/GraphStyle";
21
22
  import type { ImportReport } from "../data/report";
22
23
  import type { GraphtyError } from "../errors/GraphtyError";
23
24
  import type { CostEstimate, CostGateLimits, CostMeasurement, MachineCalibration } from "./cost";
24
- import type { Plan, SessionCommand } from "./planning";
25
+ import type { AlgorithmRunCommand, Plan, SessionCommand } from "./planning";
25
26
  import type { ResultsApi } from "./results";
26
- import type { Caveats, EngineVersions, Run, RunChange, RunExecutor, RunOptions, RunQueue, RunsApi } from "./runs";
27
+ import type { Caveats, EngineVersions, Run, RunChange, RunExecutor, RunOptions, RunQueue, RunRemoval, RunsApi } from "./runs";
27
28
  import type { ScopeApi } from "./scope/index";
28
29
  import type { SelectionApi, SelectionDelta, SelectionOwner } from "./selection";
29
30
  import type { SetChange, SetsApi } from "./sets/types";
@@ -213,13 +214,13 @@ export interface SessionGraphStore {
213
214
  * @returns the derived graph
214
215
  */
215
216
  undirected(snapshot: GraphSnapshot): DerivedGraph;
216
- /** The element-owned node coordinates, indexed by dense node index. */
217
- readonly positions: ElementPositions;
217
+ /** The element-owned node coordinates, indexed by dense node index, read-only. */
218
+ readonly positions: ReadonlyElementPositions;
218
219
  /**
219
220
  * How many nodes the DATA arrived carrying a coordinate for.
220
221
  *
221
222
  * THE HONEST ANSWER to "did the file that loaded this graph place its nodes", which
222
- * {@link ElementPositions.placedCount} cannot give: the position array is written by the
223
+ * {@link ReadonlyElementPositions.placedCount} cannot give: the position array is written by the
223
224
  * importer AND by every running layout, so a moment after a file with no coordinates loads,
224
225
  * every node carries a position because the layout put it there. This counts the importer's
225
226
  * own seed column, which nothing but the importer writes.
@@ -275,27 +276,20 @@ export interface SessionRecordSource {
275
276
  * Reading the graph.
276
277
  *
277
278
  * Every verb here is synchronous, because every verb here is either an O(1) lookup or a walk
278
- * whose answer is cached against the snapshot it was computed from. The verbs that must walk the
279
- * graph on every call -- id listings over a scope, neighbour pages, search -- are asynchronous by
280
- * construction and are not part of this surface.
281
- *
282
- * To list every record, resolve a scope for the ids and read each one here:
283
- *
284
- * ```ts
285
- * const { nodes, edges } = await session.scope.resolve("graph");
286
- * const nodeRecords = [...nodes].map((id) => session.data.node(id));
287
- * const edgeRecords = [...edges].map((id) => session.data.edge(id));
288
- * ```
289
- *
290
- * Every record carries the id the element stores it under, written after the record's own keys,
291
- * so a file row with its own `id` column cannot replace it.
279
+ * whose answer is cached against the snapshot it was computed from, except {@link nodes} and
280
+ * {@link edges}, which list every record and walk the graph to do it. The verbs that walk a part
281
+ * of the graph -- id listings over a scope, neighbour pages, search -- are asynchronous by
282
+ * construction and are not part of this surface yet.
292
283
  */
293
284
  export interface SessionDataApi {
294
- /** The store this session reads, whether it built it or was handed one. */
285
+ /** The store this session reads, read-only: its snapshot is the one {@link snapshot} returns. */
295
286
  readonly store: SessionGraphStore;
296
287
  /**
297
- * The current snapshot.
298
- * @returns the immutable graph-format snapshot
288
+ * The current snapshot. Its structure, id map and attribute columns are the graph's own,
289
+ * shared rather than copied; its `position` and `graphty.pinned` columns are copies taken
290
+ * now, because the graph's own are written by the layout every frame and a write into them
291
+ * would place nodes without a step. Place and pin through `session.positions`.
292
+ * @returns the sealed graph-format snapshot
299
293
  */
300
294
  snapshot(): GraphSnapshot;
301
295
  /**
@@ -316,6 +310,18 @@ export interface SessionDataApi {
316
310
  * @returns the record, or undefined when the graph has no such edge
317
311
  */
318
312
  edge(id: EdgeId): EdgeRecord | undefined;
313
+ /**
314
+ * Every node, in the graph's order: the records {@link node} reads one at a time. Walks the
315
+ * whole graph on every call, so read it when the graph changes, not every frame.
316
+ * @returns the records, deep-frozen
317
+ */
318
+ nodes(): readonly NodeRecord[];
319
+ /**
320
+ * Every edge, in the graph's order: the records {@link edge} reads one at a time. Walks the
321
+ * whole graph on every call, so read it when the graph changes, not every frame.
322
+ * @returns the records, deep-frozen
323
+ */
324
+ edges(): readonly EdgeRecord[];
319
325
  /**
320
326
  * What the last load did: which endpoint spelling the element resolved, how many repeated
321
327
  * edges it saw and what the policy did with them, and how many edges the graph actually holds.
@@ -325,6 +331,13 @@ export interface SessionDataApi {
325
331
  * @returns the report, or null when nothing has been loaded into this graph
326
332
  */
327
333
  lastImport(): ImportReport | null;
334
+ /**
335
+ * Where the graph was loaded from: the format, the name the reader knows the data by, the
336
+ * URL, and the file's size. It follows undo and redo like the graph does, so a top bar that
337
+ * names the dataset reads it again after either.
338
+ * @returns the source, or null when the graph was not loaded by an import, or was cleared
339
+ */
340
+ source(): DataSourceDescriptor | null;
328
341
  /**
329
342
  * Every attribute the graph's records carry, with its type, how complete it is and a few
330
343
  * sample values. Walked once per snapshot and cached.
@@ -342,6 +355,119 @@ export interface SessionDataApi {
342
355
  * @returns the fingerprint
343
356
  */
344
357
  fingerprint(): string;
358
+ /**
359
+ * Add node records, as one undoable step. A record's id is read through
360
+ * `data.knownFields.nodeIdPath`; a record whose id the graph already holds is skipped.
361
+ * @param records - The records.
362
+ * @returns Settles once the nodes are in the graph and drawn.
363
+ */
364
+ addNodes(records: readonly NodeRecordInput[]): Promise<void>;
365
+ /**
366
+ * Add edge records, as one undoable step. Endpoints are read through the configured edge id
367
+ * paths, the repeated-edge policy applies, and each edge is given an id.
368
+ * @param records - The records.
369
+ * @returns Settles once the edges are in the graph and drawn.
370
+ */
371
+ addEdges(records: readonly EdgeRecordInput[]): Promise<void>;
372
+ /**
373
+ * Change some attributes of existing nodes, as one undoable step. Keys not named are kept; an
374
+ * id the graph does not hold is skipped.
375
+ * @param rows - The new values, per node.
376
+ * @returns Settles once the change is drawn.
377
+ */
378
+ updateNodes(rows: readonly RowUpdate<NodeId>[]): Promise<void>;
379
+ /**
380
+ * Change some attributes of existing edges, as one undoable step.
381
+ * @param rows - The new values, per edge id.
382
+ * @returns Settles once the change is drawn.
383
+ */
384
+ updateEdges(rows: readonly RowUpdate<EdgeId>[]): Promise<void>;
385
+ /**
386
+ * Remove nodes, and every edge attached to one, as one undoable step. Undo puts them back at
387
+ * the rows they held, with their records, weights and edge ids.
388
+ * @param ids - The node ids; one the graph does not hold is skipped.
389
+ * @returns Settles once they are gone from the graph and the picture.
390
+ */
391
+ removeNodes(ids: readonly NodeId[]): Promise<void>;
392
+ /**
393
+ * Remove edges, as one undoable step.
394
+ * @param ids - The element-assigned edge ids; one the graph does not hold is skipped.
395
+ * @returns Settles once they are gone from the graph and the picture.
396
+ */
397
+ removeEdges(ids: readonly EdgeId[]): Promise<void>;
398
+ /**
399
+ * Remove every node, edge, record and graph-level value, as one undoable step.
400
+ * @returns Settles once the graph and the picture are empty.
401
+ */
402
+ clear(): Promise<void>;
403
+ /**
404
+ * Load a file, a URL or inline text through a registered data source, as one undoable step.
405
+ * It waits its turn behind loads and layouts already asked for. What was loaded, and from
406
+ * where, is kept: `lastImport()` and `source()` report it, and undo and redo never read the
407
+ * source again.
408
+ *
409
+ * Without a `type`, the format is detected the way `loadFromUrl` and `loadFromFile` detect
410
+ * it: from the file name or the URL's extension, then from the first bytes, fetching the URL
411
+ * once when its name says nothing. A format nothing recognises rejects with
412
+ * `E_UNKNOWN_FORMAT`, naming the formats this element reads.
413
+ * @param source - The data source's name, or none to detect it, and its options: inline
414
+ * `data`, a `url` or a `file`.
415
+ * @param options - Whether to replace the graph (the default) or add to it.
416
+ * @returns Settles once the last chunk is in the graph; rejects, recording nothing, when the
417
+ * load fails.
418
+ */
419
+ import(source: DataSourceInput, options?: ImportOptions): Promise<void>;
420
+ }
421
+ /**
422
+ * A source to import: the pair the element takes as `dataSource` and `dataSourceConfig`. `type`
423
+ * is a registered data source ("json", "csv", "graphml", ...), and `config` its options: inline
424
+ * `data`, a `url` or a `file`, and what the source reads besides.
425
+ */
426
+ export interface DataSourceInput {
427
+ /** The data source's name; detected from the file name, the URL or the content when absent. */
428
+ readonly type?: string;
429
+ /** Its options. */
430
+ readonly config: Readonly<Record<string, unknown>>;
431
+ /**
432
+ * What the reader calls the data, kept with the graph for `data.source()`. The file's name,
433
+ * or the last part of the URL, when absent.
434
+ */
435
+ readonly name?: string;
436
+ }
437
+ /**
438
+ * Where a graph was loaded from, as the graph keeps it: never the inline text or the file itself,
439
+ * which the loaded rows already hold.
440
+ */
441
+ export interface DataSourceDescriptor {
442
+ /** The data source that read it: the format named, or the one detected. */
443
+ readonly type?: string;
444
+ /** What the reader calls the data. */
445
+ readonly name?: string;
446
+ /** The file's size in bytes, when a file was read. */
447
+ readonly size?: number;
448
+ /** The source's options, without `data` and `file`: the `url`, and what the source reads besides. */
449
+ readonly config?: Readonly<Record<string, unknown>>;
450
+ }
451
+ /** How an import treats the graph already there. */
452
+ export interface ImportOptions {
453
+ /** `"replace"` (the default) empties the graph first, in the same step; `"merge"` adds to it. */
454
+ readonly mode?: "replace" | "merge";
455
+ /**
456
+ * `"recommended"` also chooses a layout for what was loaded, from its shape and its
457
+ * coordinates, in the same step; `"keep"` (the default) leaves the layout as it is.
458
+ */
459
+ readonly layout?: "recommended" | "keep";
460
+ }
461
+ /** A node record to add: its id is read through `data.knownFields.nodeIdPath`. */
462
+ export type NodeRecordInput = Readonly<Record<string, unknown>>;
463
+ /** An edge record to add: its endpoints are read through the edge id paths; its id is assigned. */
464
+ export type EdgeRecordInput = Readonly<Record<string, unknown>>;
465
+ /** New values for some attributes of one existing row; keys not named are left as they are. */
466
+ export interface RowUpdate<Id> {
467
+ /** The row's id. */
468
+ readonly id: Id;
469
+ /** The new values. */
470
+ readonly values: Readonly<Record<string, unknown>>;
345
471
  }
346
472
  /**
347
473
  * The part of the catalogue a session can answer today: the seven capability tables, which are
@@ -365,10 +491,66 @@ export interface SessionDataApi {
365
491
  * so implementing one of them means deleting its name there and nothing here.
366
492
  */
367
493
  export type SessionCatalogApi = Omit<CatalogApi, DeprecatedCatalogMethod>;
368
- /** The configuration a session carries. */
369
- export interface SessionConfig {
370
- /** The data configuration: id paths, weight paths, position scale, direction, id coercion. */
494
+ /**
495
+ * The project settings: the ones a project file saves, every one of them undoable.
496
+ *
497
+ * `data` is the element's data configuration in its own shape: the on-load `algorithms`, the
498
+ * `directed` policy, and `knownFields` with every known field (`nodeIdPath`, `nodeLabelPath`,
499
+ * `nodeWeightPath`, `nodeTimePath`, `edgeSrcIdPath`, `edgeDstIdPath`, `edgeIdPath`,
500
+ * `repeatedEdges`, `edgeWeightPath`, `edgeTimePath`, `positionScale`, `idCoercion`). A setting
501
+ * nobody has set reads as its default.
502
+ */
503
+ export interface ProjectConfig {
371
504
  readonly data: SessionDataConfig;
505
+ /** Whether the algorithms in `data.algorithms` run once data has loaded. */
506
+ readonly runAlgorithmsOnLoad: boolean;
507
+ /** What the graph is drawn against: a colour or a skybox. */
508
+ readonly background: GraphBackgroundConfig;
509
+ /** What a selected node's halo looks like. */
510
+ readonly selectionStyle: GraphSelectionStyleConfig;
511
+ /**
512
+ * The layout-behaviour settings a project file saves. The rest of the element's
513
+ * `layoutBehavior` (label declutter, pin on drag, throughput tuning) is a preference of the
514
+ * view and not a project setting.
515
+ */
516
+ readonly layoutBehavior: {
517
+ /** Simulation steps run before the first frame is drawn. */
518
+ readonly preSteps: number;
519
+ /** Simulation steps per frame. */
520
+ readonly stepMultiplier: number;
521
+ /** The movement below which a simulation counts as settled. */
522
+ readonly minDelta: number;
523
+ };
524
+ }
525
+ /**
526
+ * A partial {@link ProjectConfig}, nested: `{ data: { knownFields: { nodeIdPath: "key" } } }`.
527
+ * Plain objects are merged key by key; `data.algorithms`, `background` and `selectionStyle` are
528
+ * replaced whole. Setting a key to `undefined` returns it to its default.
529
+ */
530
+ export interface ProjectConfigPatch {
531
+ readonly data?: {
532
+ readonly algorithms?: SessionDataConfig["algorithms"];
533
+ readonly directed?: SessionDataConfig["directed"];
534
+ readonly knownFields?: Partial<SessionDataConfig["knownFields"]>;
535
+ };
536
+ readonly runAlgorithmsOnLoad?: boolean;
537
+ readonly background?: GraphBackgroundConfig;
538
+ readonly selectionStyle?: GraphSelectionStyleInput;
539
+ readonly layoutBehavior?: Partial<ProjectConfig["layoutBehavior"]>;
540
+ }
541
+ /**
542
+ * The session's settings as they are now: every project setting, read live, and the
543
+ * acceleration policy, which is a preference about this machine and not saved in a project.
544
+ */
545
+ export interface SessionConfig extends ProjectConfig {
546
+ /**
547
+ * Change project settings. One step, which undo takes back.
548
+ * @param values - The settings to change.
549
+ * @returns Settles once the step is recorded and the picture has caught up.
550
+ * @throws A `GraphtyError` (as a rejection) with `E_BAD_COMMAND` when a key is not a project
551
+ * setting or a value is one its setting refuses; nothing is changed then.
552
+ */
553
+ set(values: ProjectConfigPatch): Promise<void>;
372
554
  /** What the consumer asked of the hardware. */
373
555
  readonly acceleration: {
374
556
  /** Use an accelerator when one is available, never look, or refuse to run without one. */
@@ -425,6 +607,24 @@ export interface SessionEventMap {
425
607
  "capabilities:changed": {
426
608
  readonly capabilities: AccelerationCapabilities;
427
609
  };
610
+ /**
611
+ * The history changed: a step was recorded, merged, undone, redone, restored, evicted or
612
+ * cleared, or the pending work (and so what the next undo will do) changed. Fires
613
+ * synchronously after `project:changed`. Read `session.history` for the new state; its
614
+ * `version` has moved.
615
+ */
616
+ "history:changed": {
617
+ readonly reason: "record" | "merge" | "undo" | "redo" | "restore" | "evict" | "clear" | "pending" | "size";
618
+ };
619
+ /**
620
+ * Project state changed: the slices written and what wrote them. Fires synchronously, as
621
+ * soon as the state has changed and before the picture has caught up; the per-domain events
622
+ * (`style:changed` and the rest) follow once it has.
623
+ */
624
+ "project:changed": {
625
+ readonly slices: readonly ProjectSlice[];
626
+ readonly cause: HistoryCause;
627
+ };
428
628
  /**
429
629
  * A kept set was created, renamed, redefined or removed: one event per set a write touched,
430
630
  * after the write committed. A write that was refused publishes nothing.
@@ -434,6 +634,337 @@ export interface SessionEventMap {
434
634
  */
435
635
  "set:changed": SetChange;
436
636
  }
637
+ /**
638
+ * The parts of a project. Everything a project file saves lives in one of these, and a change
639
+ * to any of them is undoable; nothing outside them (camera, hover, the selection, a run still
640
+ * computing) is.
641
+ */
642
+ export type ProjectSlice = "graph" | "config" | "layout" | "pins" | "arrangement" | "runs" | "styles" | "visibility" | "sets" | "views";
643
+ /** What moved project state: a command, a history move, or a failed command being reverted. */
644
+ export type HistoryCause = "command" | "undo" | "redo" | "restore" | "rollback";
645
+ /** The id of one step in `session.history.steps`. */
646
+ export type HistoryStepId = string & {
647
+ readonly __brand: "HistoryStepId";
648
+ };
649
+ /** The id of one item in `session.history.pending`. */
650
+ export type PendingId = string & {
651
+ readonly __brand: "PendingId";
652
+ };
653
+ /** One undoable step: everything one command, gesture or transaction changed. Frozen. */
654
+ export interface HistoryStep {
655
+ /** Stable for the life of the step. */
656
+ readonly id: HistoryStepId;
657
+ /** What a history list shows, such as "Changed colour of Hubs". */
658
+ readonly label: string;
659
+ /** ISO 8601 of the last commit or merge into the step. */
660
+ readonly at: string;
661
+ /** The ops of the commands in the step, in the order they ran. Payloads are not kept for display. */
662
+ readonly ops: readonly SessionCommand["op"][];
663
+ /** The slices the step changed. */
664
+ readonly slices: readonly ProjectSlice[];
665
+ /** What the step retains on the side of the cursor it is on. */
666
+ readonly bytes: number;
667
+ /** Where the step came from, such as `{ via: "assistant" }`. */
668
+ readonly provenance: Readonly<Record<string, string>>;
669
+ }
670
+ /** Undoable work dispatched and not yet recorded: queued, waiting, or an open transaction. Frozen. */
671
+ export interface PendingStep {
672
+ /** Pass it to `history.cancel`. */
673
+ readonly id: PendingId;
674
+ /** The label the step will have. */
675
+ readonly label: string;
676
+ /** ISO 8601 of the dispatch. */
677
+ readonly since: string;
678
+ /** The runs this work is waiting on. */
679
+ readonly runIds: readonly RunId[];
680
+ }
681
+ /** What an undo, a redo or a restore did. */
682
+ export type HistoryOutcome = {
683
+ readonly kind: "undone" | "redone" | "restored";
684
+ readonly steps: readonly HistoryStep[];
685
+ } | {
686
+ readonly kind: "cancelled";
687
+ readonly pending: readonly PendingStep[];
688
+ } | {
689
+ readonly kind: "nothing";
690
+ };
691
+ /**
692
+ * The session's undo history. `steps`, `pending` and `nextUndo` are frozen values, the identical
693
+ * objects between changes; `version` moves on every `history:changed`, so a React host can
694
+ * subscribe with `useSyncExternalStore(subscribe, () => session.history.version)`.
695
+ */
696
+ export interface SessionHistory {
697
+ /** Bumped on every `history:changed`. */
698
+ readonly version: number;
699
+ /** Oldest first; `steps[position..]` have been undone and can be redone. */
700
+ readonly steps: readonly HistoryStep[];
701
+ /** How many steps are applied. */
702
+ readonly position: number;
703
+ /** Undoable work dispatched and not yet recorded, oldest first. */
704
+ readonly pending: readonly PendingStep[];
705
+ /** What the next `undo()` will do: cancel pending work, undo a step, or nothing (null). */
706
+ readonly nextUndo: {
707
+ readonly kind: "cancel";
708
+ readonly pending: readonly PendingStep[];
709
+ } | {
710
+ readonly kind: "undo";
711
+ readonly step: HistoryStep;
712
+ } | null;
713
+ /** What every step retains, in bytes. */
714
+ readonly bytes: number;
715
+ /**
716
+ * The byte budget. Default 256 MiB. When a record goes past it, or past `limitSteps`, the
717
+ * oldest steps (then the farthest redo steps) are dropped until the history is within 90% of
718
+ * both budgets, so the work of dropping is spread over many records. Lowering a budget below
719
+ * what the history holds trims it the same way at once.
720
+ */
721
+ limitBytes: number;
722
+ /**
723
+ * The step budget. Default 1000. Going past it trims the history to 90% of it, rounded down,
724
+ * as `limitBytes` describes: with a budget of 10, the eleventh step leaves 9.
725
+ */
726
+ limitSteps: number;
727
+ /**
728
+ * Move to the state just after a step, or to the baseline with `null`, as the equivalent run
729
+ * of undos or redos. Resolves once the picture matches the state.
730
+ * @param step - The step, or null for the state before every step.
731
+ * @returns What was done.
732
+ */
733
+ restoreTo(step: HistoryStepId | null): Promise<HistoryOutcome>;
734
+ /**
735
+ * Cancel a pending item, and every later-dispatched item that depends on what it writes.
736
+ * @param pending - The item.
737
+ * @returns Every item cancelled; empty when the id is not pending.
738
+ */
739
+ cancel(pending: PendingId): readonly PendingStep[];
740
+ /** Drop every step, cancelling pending work: the current state becomes the baseline. */
741
+ clear(): void;
742
+ }
743
+ /** Stamped on the step a transaction records. */
744
+ export interface TransactionOptions {
745
+ /** Where the step came from, such as `{ via: "assistant" }`. Shown in `HistoryStep.provenance`. */
746
+ readonly provenance?: Readonly<Record<string, string>>;
747
+ }
748
+ /**
749
+ * The session a transaction's callback works through: every verb of the session, and what it
750
+ * dispatches joins the transaction's step. It cannot undo, redo, read the history or dispose.
751
+ */
752
+ export type TransactionScope = Omit<GraphSession, "undo" | "redo" | "history" | "dispose">;
753
+ /**
754
+ * What `execute` returns, per op. No entry is wrapped in a promise, because a promise resolved
755
+ * with a `Run` would adopt it and yield the result instead of the handle.
756
+ */
757
+ export interface CommandOutcomeMap {
758
+ /** The run's handle; awaiting it yields the result. */
759
+ "algo.run": Run;
760
+ /** Settles once the plugin has run and everything it wrote is recorded as one step. */
761
+ "algo.legacy": Promise<void>;
762
+ /** What went with the run, once the removal is recorded. */
763
+ "algo.remove": Promise<RunRemoval>;
764
+ /** Settles once every member is recorded as one step and the pass that draws it has run. */
765
+ batch: Promise<void>;
766
+ /** Settles once the change is recorded and the pass that draws it has run. */
767
+ "data.apply": Promise<void>;
768
+ /** Settles once the last chunk is recorded and the pass that draws it has run. */
769
+ "data.import": Promise<void>;
770
+ /** Settles once the neighbourhood is recorded and the pass that draws it has run. */
771
+ "data.expand": Promise<void>;
772
+ /** Settles once the edit is recorded and the pass that repaints it has run. */
773
+ "style.patch": Promise<void>;
774
+ /** Settles once the edit is recorded and the pass that repaints it has run. */
775
+ "style.encode": Promise<void>;
776
+ /** Settles once the edit is recorded and the pass that repaints it has run. */
777
+ "style.template": Promise<void>;
778
+ /** Settles once the filter is recorded and the pass that evaluates the masks has run. */
779
+ "visibility.set": Promise<void>;
780
+ /** Settles once the window is recorded and the pass that evaluates the masks has run. */
781
+ "visibility.window": Promise<void>;
782
+ /** Settles once the flag is recorded and the pass that follows it has run. */
783
+ "visibility.context": Promise<void>;
784
+ /** The new set's id, once it is recorded. */
785
+ "set.create": Promise<SetId>;
786
+ /** Settles once the rename is recorded. */
787
+ "set.rename": Promise<void>;
788
+ /** Settles once the redefinition is recorded. */
789
+ "set.redefine": Promise<void>;
790
+ /** Settles once the member edit is recorded. */
791
+ "set.members": Promise<void>;
792
+ /** Settles once the removal is recorded. */
793
+ "set.remove": Promise<void>;
794
+ /** Settles once the restore is recorded. */
795
+ "set.restore": Promise<void>;
796
+ /** Settles once the views are recorded. */
797
+ "view.save": Promise<void>;
798
+ /** Settles once the removal is recorded. */
799
+ "view.remove": Promise<void>;
800
+ /** Settles once the camera has arrived. */
801
+ "view.camera": Promise<void>;
802
+ /** Settles once the settings are recorded and the picture has caught up. */
803
+ "config.set": Promise<void>;
804
+ /** Settles once the coordinates are recorded and the layout has taken them. */
805
+ "positions.set": Promise<void>;
806
+ /** Settles once the pins are recorded and the layout has taken them. */
807
+ "positions.pin": Promise<void>;
808
+ /** Settles once the choice is recorded and the layout has spent its pre-steps. */
809
+ "layout.set": Promise<void>;
810
+ /** Settles once the scope is recorded. */
811
+ "layout.scope": Promise<void>;
812
+ /** Settles once the switch is recorded and the layout has been rebuilt for it. */
813
+ "view.dimension": Promise<void>;
814
+ /** Settles once the layout has started or stopped moving. */
815
+ "layout.transport": Promise<void>;
816
+ /** Settles once the device session has started or ended. */
817
+ "view.immersive": Promise<void>;
818
+ }
819
+ /** One node's coordinates for `positions.set`, in scene units. */
820
+ export interface PositionEntry {
821
+ readonly id: NodeId;
822
+ readonly x: number;
823
+ readonly y: number;
824
+ /** Defaults to 0. */
825
+ readonly z?: number;
826
+ }
827
+ /**
828
+ * The node coordinates, read by dense node index: a row no layout has placed reads as unplaced
829
+ * rather than as the origin.
830
+ *
831
+ * Read-only. A consumer places and pins nodes through `session.positions.set`, `pin` and `unpin`,
832
+ * which are undoable steps; the array a layout writes every frame is the element's own.
833
+ */
834
+ export interface ReadonlyElementPositions {
835
+ /** Rows the coordinates can hold without growing. */
836
+ readonly capacity: number;
837
+ /** Rows in use: the node count of the current snapshot. */
838
+ readonly count: number;
839
+ /** Rows in use that hold a coordinate. */
840
+ readonly placedCount: number;
841
+ /** Rows in use that are pinned. */
842
+ readonly pinnedCount: number;
843
+ /** Moves whenever coordinates are written on purpose, so a reader can tell they changed. */
844
+ readonly generation: number;
845
+ /**
846
+ * Whether a row holds a coordinate.
847
+ * @param index - The dense node index.
848
+ * @returns False for an unplaced row or one past the rows in use.
849
+ */
850
+ isPlaced(index: number): boolean;
851
+ /**
852
+ * Whether a row is pinned.
853
+ * @param index - The dense node index.
854
+ * @returns False for an unpinned row or one past the rows in use.
855
+ */
856
+ isPinned(index: number): boolean;
857
+ /**
858
+ * Read a row's coordinates into an object the caller owns.
859
+ * @param index - The dense node index.
860
+ * @param out - Receives x, y and z in scene units; NaN for an unplaced row.
861
+ * @param out.x - Receives x.
862
+ * @param out.y - Receives y.
863
+ * @param out.z - Receives z.
864
+ */
865
+ read(index: number, out: {
866
+ x: number;
867
+ y: number;
868
+ z: number;
869
+ }): void;
870
+ }
871
+ /**
872
+ * Placing and pinning nodes, as undoable steps, beside the read-only coordinates.
873
+ *
874
+ * Coordinates a running layout writes are not steps: where the layout comes to rest is recorded
875
+ * into the step before it, so undo and redo restore where the nodes were without running the
876
+ * layout again.
877
+ */
878
+ export interface SessionPositions extends ReadonlyElementPositions {
879
+ /** The pinned node ids: the nodes no layout moves. */
880
+ readonly pinned: ReadonlySet<NodeId>;
881
+ /**
882
+ * Place nodes. One step; calls made one after another within the coalescing window are one.
883
+ * @param entries - The nodes and where to put them.
884
+ * @returns Settles once the step is recorded and the layout has taken the coordinates.
885
+ * @throws A `GraphtyError` (as a rejection) with `E_BAD_COMMAND` for a node the graph does not
886
+ * hold or a coordinate that is not a finite number; nothing is placed then.
887
+ */
888
+ set(entries: readonly PositionEntry[]): Promise<void>;
889
+ /**
890
+ * Pin nodes where they are. One step. A node the graph does not hold is skipped.
891
+ * @param ids - The nodes.
892
+ * @returns Settles once the step is recorded and the layout has taken the pins.
893
+ */
894
+ pin(ids: readonly NodeId[]): Promise<void>;
895
+ /**
896
+ * Release pinned nodes, so the layout arranges them again. One step.
897
+ * @param ids - The nodes.
898
+ * @returns Settles once the step is recorded and the layout has taken the change.
899
+ */
900
+ unpin(ids: readonly NodeId[]): Promise<void>;
901
+ }
902
+ /**
903
+ * Which layout draws the graph, and in how many dimensions: the project's `layout` slice.
904
+ *
905
+ * Choosing a layout and switching between 2D and 3D are undoable steps, and undo puts back the
906
+ * engine that was chosen with its own options, not the catalogue's default. Until one is chosen
907
+ * it reads the element's default, the `force` layout drawn by `ngraph` in 3D.
908
+ */
909
+ export interface SessionLayout {
910
+ /** The catalogue id, such as `"force"`. */
911
+ readonly id: LayoutId;
912
+ /** The engine that draws it, such as `"d3"`. */
913
+ readonly engine: string;
914
+ /** The options it was chosen with. */
915
+ readonly options: Readonly<Record<string, unknown>>;
916
+ /** Whether the graph is drawn in two dimensions or three. */
917
+ readonly dimension: "2d" | "3d";
918
+ /**
919
+ * Choose the layout. One step.
920
+ * @param id - The catalogue id; a registered engine name is read as the id it serves.
921
+ * @param options - The engine, when not the catalogue's default for `id`, and its options.
922
+ * @param options.engine - The engine that draws it, such as `"d3"`.
923
+ * @param options.options - The engine's options.
924
+ * @returns Settles once the step is recorded and the layout has taken its pre-steps.
925
+ * @throws A `GraphtyError` (as a rejection) with `E_UNKNOWN_LAYOUT`, `E_UNKNOWN_OPTION` or
926
+ * `E_OPTION_RANGE` when the renderer cannot build it; nothing is changed then.
927
+ */
928
+ set(id: LayoutId, options?: {
929
+ readonly engine?: string;
930
+ readonly options?: Readonly<Record<string, unknown>>;
931
+ }): Promise<void>;
932
+ /**
933
+ * Draw in 2D or 3D. One step; nothing is recorded when the graph is drawn so already.
934
+ * @param dimension - Which.
935
+ * @returns Settles once the step is recorded and the layout has been rebuilt for it.
936
+ */
937
+ setDimension(dimension: "2d" | "3d"): Promise<void>;
938
+ }
939
+ /**
940
+ * The saved camera views, read as a map from name to camera state.
941
+ *
942
+ * A saved view is a fixed position, not a rule: it does not recompute itself for a different
943
+ * graph the way a camera view does, which is why a name a camera view answers to is refused.
944
+ */
945
+ export interface SessionViews extends ReadonlyMap<string, CameraState> {
946
+ /**
947
+ * Keep camera states under names, replacing any view already saved under one. One step.
948
+ * @param views - The names and the camera states.
949
+ * @returns Settles once the step is recorded.
950
+ * @throws A `GraphtyError` (as a rejection) with `E_PROTECTED` when a camera view answers to
951
+ * a name, or `E_BAD_COMMAND` for an empty name; nothing is saved then.
952
+ */
953
+ save(views: readonly {
954
+ readonly name: string;
955
+ readonly camera: CameraState;
956
+ }[]): Promise<void>;
957
+ /**
958
+ * Forget saved views. One step.
959
+ * @param names - The names.
960
+ * @returns Settles once the step is recorded.
961
+ * @throws A `GraphtyError` (as a rejection) with `E_BAD_COMMAND` when a name is not saved;
962
+ * nothing is removed then.
963
+ */
964
+ remove(names: readonly string[]): Promise<void>;
965
+ }
966
+ /** What `execute` returns for one command. */
967
+ export type CommandOutcome<C extends SessionCommand> = CommandOutcomeMap[C["op"]];
437
968
  /**
438
969
  * A painting the element started for itself, and why it did not land.
439
970
  *
@@ -508,14 +1039,22 @@ export interface GraphSession {
508
1039
  */
509
1040
  readonly styles: StylesApi;
510
1041
  /**
511
- * The element-owned node coordinates: a stride-3 Float32Array indexed by dense node index,
512
- * where a row no layout has placed reads NaN rather than the origin.
1042
+ * The saved camera views, by name: camera states kept under a name of the consumer's
1043
+ * choosing. Saving and removing one are undoable steps; moving the camera to one is not.
1044
+ */
1045
+ readonly views: SessionViews;
1046
+ /** Which layout draws the graph, and in how many dimensions; choosing either is a step. */
1047
+ readonly layout: SessionLayout;
1048
+ /**
1049
+ * The element-owned node coordinates, read by dense node index, where a row no layout has
1050
+ * placed reads as unplaced rather than at the origin, with the verbs that place and pin nodes
1051
+ * as undoable steps.
513
1052
  *
514
- * The typed placement verbs of the design's positions API -- pinning, snapshot and restore,
515
- * per-id reads -- arrive with the layout work. This is the array itself, which is what a
516
- * layout, a drag and a GPU readback all write into.
1053
+ * Place and pin through `set`, `pin` and `unpin`; the coordinates themselves are read-only
1054
+ * here, because a layout, a drag and a GPU readback write them and a write made there is not a
1055
+ * step.
517
1056
  */
518
- readonly positions: ElementPositions;
1057
+ readonly positions: SessionPositions;
519
1058
  /**
520
1059
  * How many nodes the DATA arrived carrying a coordinate for.
521
1060
  *
@@ -529,7 +1068,7 @@ export interface GraphSession {
529
1068
  readonly status: SessionStatus;
530
1069
  /** Everything the element can offer, as data. */
531
1070
  readonly catalog: SessionCatalogApi;
532
- /** The configuration this session was built with. */
1071
+ /** The settings as they are now, and `set` to change the project ones. */
533
1072
  readonly config: SessionConfig;
534
1073
  /** What this machine can do, measured rather than guessed at by the consumer. */
535
1074
  readonly capabilities: AccelerationCapabilities;
@@ -550,8 +1089,11 @@ export interface GraphSession {
550
1089
  */
551
1090
  setAccelerator(accelerator: GraphAccelerator | null): void;
552
1091
  /**
553
- * The current snapshot, by reference: nothing is copied.
554
- * @returns the immutable graph-format snapshot
1092
+ * The current snapshot. Its structure, id map and attribute columns are the graph's own,
1093
+ * shared rather than copied; its `position` and `graphty.pinned` columns are copies taken
1094
+ * now, because the graph's own are written by the layout every frame and a write into them
1095
+ * would place nodes without a step. Place and pin through `session.positions`.
1096
+ * @returns the sealed graph-format snapshot
555
1097
  */
556
1098
  snapshot(): GraphSnapshot;
557
1099
  /**
@@ -568,7 +1110,44 @@ export interface GraphSession {
568
1110
  * @param options - The signal, the progress handler and how the call joins the queue.
569
1111
  * @returns The run, awaitable and watchable straight away.
570
1112
  */
571
- run(command: SessionCommand, options?: RunOptions): Run;
1113
+ run(command: AlgorithmRunCommand, options?: RunOptions): Run;
1114
+ /**
1115
+ * Do any command in the vocabulary (`COMMANDS` in `@graphty/graphty-element/commands`).
1116
+ *
1117
+ * Returns the op's outcome directly, not wrapped in a promise; every outcome is itself
1118
+ * awaitable (a `Run` for `algo.run`), so `await session.execute(...)` waits for the command,
1119
+ * and a caller that wants the run handle keeps the returned value without awaiting it.
1120
+ * @param command - The command.
1121
+ * @returns Its outcome.
1122
+ */
1123
+ execute<C extends SessionCommand>(command: C): CommandOutcome<C>;
1124
+ /**
1125
+ * Undo the last step, or cancel pending undoable work dispatched after it instead. Never
1126
+ * waits for pending work. Resolves once the picture matches the state.
1127
+ * @returns What was done; `{ kind: "nothing" }` when there was nothing to undo.
1128
+ */
1129
+ undo(): Promise<HistoryOutcome>;
1130
+ /**
1131
+ * Redo the last undone step. Resolves once the picture matches the state.
1132
+ * @returns What was done; `{ kind: "nothing" }` when there was nothing to redo.
1133
+ */
1134
+ redo(): Promise<HistoryOutcome>;
1135
+ /** Whether `undo()` would do something: undo a step or cancel pending work. */
1136
+ readonly canUndo: boolean;
1137
+ /** Whether `redo()` would do something. */
1138
+ readonly canRedo: boolean;
1139
+ /** The steps, the cursor, the pending work and the budget. */
1140
+ readonly history: SessionHistory;
1141
+ /**
1142
+ * Run `fn`, and record everything it dispatches through `tx` as one step. Throw, or abort
1143
+ * the transaction, to roll all of it back. A transaction that changed nothing records
1144
+ * nothing.
1145
+ * @param label - The step's label.
1146
+ * @param fn - The body; `signal` fires when the transaction is aborted.
1147
+ * @param options - Provenance stamped on the step.
1148
+ * @returns What `fn` returned, once the step is recorded and the picture has caught up.
1149
+ */
1150
+ transaction<T>(label: string, fn: (tx: TransactionScope, signal: AbortSignal) => T | Promise<T>, options?: TransactionOptions): Promise<T>;
572
1151
  /**
573
1152
  * What one command would cost, answered synchronously.
574
1153
  *
@@ -631,26 +1210,18 @@ export interface ElementSession extends GraphSession {
631
1210
  */
632
1211
  readonly paint: ElementPaint;
633
1212
  }
634
- /** What {@link createGraphSession} accepts. */
1213
+ /**
1214
+ * What {@link createGraphSession} accepts.
1215
+ *
1216
+ * The session is the only writer of its graph and its settings, which is what makes every change
1217
+ * undoable: hand data in through `session.data.import`, `addNodes` and `addEdges`, and settings
1218
+ * through `session.config.set`.
1219
+ */
635
1220
  export interface CreateGraphSessionOptions {
636
- /**
637
- * The store to read. When absent the session builds one of its own and disposes it with
638
- * itself.
639
- */
640
- readonly store?: SessionGraphStore;
641
- /** Where to read the attributes a record arrived with. Absent means the graph has none. */
642
- readonly records?: SessionRecordSource;
643
1221
  /** The configuration. Every part not given takes the element's own default. */
644
1222
  readonly config?: {
645
- /**
646
- * The data configuration, or a function that reads it.
647
- *
648
- * Hand in a FUNCTION when the host REPLACES its configuration object rather than mutating
649
- * it -- applying a new style template to the element does exactly that -- or the session
650
- * would go on answering from the configuration that was in force when it was built, and
651
- * would report a graph as undirected after it had been told otherwise.
652
- */
653
- readonly data?: SessionDataConfig | (() => SessionDataConfig);
1223
+ /** The data configuration the session starts from; change it later with `config.set`. */
1224
+ readonly data?: SessionDataConfig;
654
1225
  /** The acceleration policy and threshold. */
655
1226
  readonly acceleration?: {
656
1227
  /** Use an accelerator when available, never look, or refuse to run without one. */