@graphrefly/graphrefly 0.21.0 → 0.23.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 (101) hide show
  1. package/README.md +7 -5
  2. package/dist/chunk-263BEJJO.js +115 -0
  3. package/dist/chunk-263BEJJO.js.map +1 -0
  4. package/dist/chunk-2GQLMQVJ.js +47 -0
  5. package/dist/chunk-2GQLMQVJ.js.map +1 -0
  6. package/dist/chunk-32N5A454.js +36 -0
  7. package/dist/chunk-32N5A454.js.map +1 -0
  8. package/dist/chunk-7TAQJHQV.js +103 -0
  9. package/dist/chunk-7TAQJHQV.js.map +1 -0
  10. package/dist/{chunk-VOQFK7YN.js → chunk-CWYPA63G.js} +109 -259
  11. package/dist/chunk-CWYPA63G.js.map +1 -0
  12. package/dist/{chunk-7IGHIFTT.js → chunk-HVBX5KIW.js} +15 -26
  13. package/dist/chunk-HVBX5KIW.js.map +1 -0
  14. package/dist/chunk-JFONSPNF.js +391 -0
  15. package/dist/chunk-JFONSPNF.js.map +1 -0
  16. package/dist/chunk-NZMBRXQV.js +2330 -0
  17. package/dist/chunk-NZMBRXQV.js.map +1 -0
  18. package/dist/{chunk-XWBVAO2R.js → chunk-PNUZM7PC.js} +20 -30
  19. package/dist/chunk-PNUZM7PC.js.map +1 -0
  20. package/dist/{chunk-ZTCDY5NQ.js → chunk-PX6PDUJ5.js} +34 -50
  21. package/dist/chunk-PX6PDUJ5.js.map +1 -0
  22. package/dist/chunk-XRFJJ2IU.js +2417 -0
  23. package/dist/chunk-XRFJJ2IU.js.map +1 -0
  24. package/dist/chunk-XTLYW4FR.js +6829 -0
  25. package/dist/chunk-XTLYW4FR.js.map +1 -0
  26. package/dist/compat/nestjs/index.cjs +3489 -2286
  27. package/dist/compat/nestjs/index.cjs.map +1 -1
  28. package/dist/compat/nestjs/index.d.cts +6 -4
  29. package/dist/compat/nestjs/index.d.ts +6 -4
  30. package/dist/compat/nestjs/index.js +10 -8
  31. package/dist/core/index.cjs +1706 -1217
  32. package/dist/core/index.cjs.map +1 -1
  33. package/dist/core/index.d.cts +3 -2
  34. package/dist/core/index.d.ts +3 -2
  35. package/dist/core/index.js +37 -34
  36. package/dist/extra/index.cjs +7519 -6125
  37. package/dist/extra/index.cjs.map +1 -1
  38. package/dist/extra/index.d.cts +4 -4
  39. package/dist/extra/index.d.ts +4 -4
  40. package/dist/extra/index.js +63 -34
  41. package/dist/graph/index.cjs +3199 -2212
  42. package/dist/graph/index.cjs.map +1 -1
  43. package/dist/graph/index.d.cts +5 -3
  44. package/dist/graph/index.d.ts +5 -3
  45. package/dist/graph/index.js +24 -11
  46. package/dist/graph-BtdSRHUc.d.cts +1128 -0
  47. package/dist/graph-CEO2FkLY.d.ts +1128 -0
  48. package/dist/{index-DuN3bhtm.d.ts → index-B0tfuXwV.d.cts} +1697 -586
  49. package/dist/index-BFGjXbiP.d.cts +315 -0
  50. package/dist/{index-CgSiUouz.d.ts → index-BPlWVAKY.d.cts} +4 -4
  51. package/dist/index-BUj3ASVe.d.cts +406 -0
  52. package/dist/{index-VHA43cGP.d.cts → index-C59uSJAH.d.cts} +2 -2
  53. package/dist/index-CkElcUY6.d.ts +315 -0
  54. package/dist/index-DSPc5rkv.d.ts +406 -0
  55. package/dist/{index-BjtlNirP.d.cts → index-DgscL7v0.d.ts} +4 -4
  56. package/dist/{index-SFzE_KTa.d.cts → index-RXN94sHK.d.ts} +1697 -586
  57. package/dist/{index-8a605sg9.d.ts → index-jEtF4N7L.d.ts} +2 -2
  58. package/dist/index.cjs +9947 -7949
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.d.cts +214 -37
  61. package/dist/index.d.ts +214 -37
  62. package/dist/index.js +919 -648
  63. package/dist/index.js.map +1 -1
  64. package/dist/meta-3QjzotRv.d.ts +41 -0
  65. package/dist/meta-B-Lbs4-O.d.cts +41 -0
  66. package/dist/node-C7PD3sn9.d.cts +1188 -0
  67. package/dist/node-C7PD3sn9.d.ts +1188 -0
  68. package/dist/{observable-DcBwQY7t.d.ts → observable-EyO-moQY.d.ts} +1 -1
  69. package/dist/{observable-C8Kx_O6k.d.cts → observable-axpzv1K2.d.cts} +1 -1
  70. package/dist/patterns/reactive-layout/index.cjs +3205 -2138
  71. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  72. package/dist/patterns/reactive-layout/index.d.cts +5 -3
  73. package/dist/patterns/reactive-layout/index.d.ts +5 -3
  74. package/dist/patterns/reactive-layout/index.js +7 -4
  75. package/dist/storage-CHT5WE9m.d.ts +182 -0
  76. package/dist/storage-DIgAr7M_.d.cts +182 -0
  77. package/package.json +2 -1
  78. package/dist/chunk-2UDLYZHT.js +0 -2117
  79. package/dist/chunk-2UDLYZHT.js.map +0 -1
  80. package/dist/chunk-4MQ2J6IG.js +0 -1631
  81. package/dist/chunk-4MQ2J6IG.js.map +0 -1
  82. package/dist/chunk-7IGHIFTT.js.map +0 -1
  83. package/dist/chunk-DOSLSFKL.js +0 -162
  84. package/dist/chunk-DOSLSFKL.js.map +0 -1
  85. package/dist/chunk-ECN37NVS.js +0 -6227
  86. package/dist/chunk-ECN37NVS.js.map +0 -1
  87. package/dist/chunk-G66H6ZRK.js +0 -111
  88. package/dist/chunk-G66H6ZRK.js.map +0 -1
  89. package/dist/chunk-VOQFK7YN.js.map +0 -1
  90. package/dist/chunk-WZ2Z2CRV.js +0 -32
  91. package/dist/chunk-WZ2Z2CRV.js.map +0 -1
  92. package/dist/chunk-XWBVAO2R.js.map +0 -1
  93. package/dist/chunk-ZTCDY5NQ.js.map +0 -1
  94. package/dist/graph-KsTe57nI.d.cts +0 -750
  95. package/dist/graph-mILUUqW8.d.ts +0 -750
  96. package/dist/index-B2SvPEbc.d.ts +0 -257
  97. package/dist/index-BHfg_Ez3.d.ts +0 -629
  98. package/dist/index-Bc_diYYJ.d.cts +0 -629
  99. package/dist/index-UudxGnzc.d.cts +0 -257
  100. package/dist/meta-BnG7XAaE.d.cts +0 -778
  101. package/dist/meta-BnG7XAaE.d.ts +0 -778
@@ -0,0 +1,1128 @@
1
+ import { k as GraphReFlyConfig, a6 as VersioningLevel, N as Node, A as Actor, t as Messages, K as NodeSink } from './node-C7PD3sn9.js';
2
+ import { b as DescribeNodeOutput, D as DescribeDetail, a as DescribeField } from './meta-3QjzotRv.js';
3
+ import { a as StorageTier, S as StorageHandle } from './storage-CHT5WE9m.js';
4
+
5
+ /**
6
+ * Graph profiling and inspection utilities.
7
+ *
8
+ * Provides per-node memory estimation, connectivity stats, and hotspot
9
+ * detection. Non-invasive — reads from `describe()` and node internals
10
+ * without modifying state.
11
+ *
12
+ * @module
13
+ */
14
+
15
+ /** Per-node profile entry. */
16
+ interface NodeProfile {
17
+ /** Qualified path within the graph. */
18
+ path: string;
19
+ /** Node type (state, derived, producer, effect). */
20
+ type: string;
21
+ /** Node status (disconnected, dirty, settled, errored, completed). */
22
+ status: string;
23
+ /** Approximate retained bytes for the node's cached value. */
24
+ valueSizeBytes: number;
25
+ /** Number of downstream subscribers (sinks). */
26
+ subscriberCount: number;
27
+ /** Number of upstream dependencies. */
28
+ depCount: number;
29
+ /**
30
+ * True if this is an effect node with no external subscribers — a classic
31
+ * leak pattern. See {@link GraphProfileResult.orphans} for the broader
32
+ * orphan-node detection across `derived` / `producer` / `effect`.
33
+ */
34
+ isOrphanEffect: boolean;
35
+ /**
36
+ * Orphan category (batch 8 Unit 13 D). `null` when the node is healthy.
37
+ * - `"orphan-effect"` — effect with zero subscribers (pre-existing class).
38
+ * - `"idle-derived"` — derived with zero subscribers (wasted compute path
39
+ * if it ever activates; may indicate a factory forgot keepalive).
40
+ * - `"idle-producer"` — producer with zero subscribers (no external
41
+ * consumer; may be an over-eager factory or forgotten cleanup).
42
+ */
43
+ orphanKind: "orphan-effect" | "idle-derived" | "idle-producer" | null;
44
+ }
45
+ /** Aggregate graph profile. */
46
+ interface GraphProfileResult {
47
+ /** Total node count. */
48
+ nodeCount: number;
49
+ /** Total edge count. */
50
+ edgeCount: number;
51
+ /** Subgraph count. */
52
+ subgraphCount: number;
53
+ /** All node profiles. */
54
+ nodes: NodeProfile[];
55
+ /** Total approximate value memory across all nodes. */
56
+ totalValueSizeBytes: number;
57
+ /**
58
+ * Top-N hotspots by dimension. Each list is sorted descending. See
59
+ * {@link GraphProfileOptions.topN} for the cap (default 10).
60
+ */
61
+ hotspots: {
62
+ byValueSize: NodeProfile[];
63
+ bySubscriberCount: NodeProfile[];
64
+ byDepCount: NodeProfile[];
65
+ };
66
+ /**
67
+ * Every orphan across types — `effect`, `derived`, `producer` with zero
68
+ * subscribers. See {@link NodeProfile.orphanKind} for category.
69
+ */
70
+ orphans: NodeProfile[];
71
+ /** Effect nodes with no external subscribers (legacy; subset of `orphans`). */
72
+ orphanEffects: NodeProfile[];
73
+ }
74
+ /** Options for {@link graphProfile}. */
75
+ interface GraphProfileOptions {
76
+ /** Limit hotspot list (default 10). */
77
+ topN?: number;
78
+ }
79
+ /**
80
+ * Profile a graph's memory and connectivity characteristics.
81
+ *
82
+ * Uses `describe({ detail: "standard" })` for node metadata and direct
83
+ * `NodeImpl` access for subscriber counts and cached values.
84
+ *
85
+ * @param graph - The graph to profile.
86
+ * @param opts - Optional configuration.
87
+ * @returns Aggregate profile with per-node details, hotspots (multi-dim), and orphans.
88
+ */
89
+ declare function graphProfile(graph: Graph, opts?: GraphProfileOptions): GraphProfileResult;
90
+
91
+ /**
92
+ * Reserved segment for meta companion paths: `nodeName::__meta__::metaKey` (GRAPHREFLY-SPEC §3.6).
93
+ * Forbidden as a local node or mount name.
94
+ */
95
+ declare const GRAPH_META_SEGMENT = "__meta__";
96
+ /**
97
+ * Options for {@link Graph}. Named fields documented below; the open index
98
+ * signature is preserved so callers can stash extension data on the graph
99
+ * without losing type discipline on the reserved names.
100
+ *
101
+ * - `config` — bind this graph to a specific {@link GraphReFlyConfig} for
102
+ * tier/metaPassthrough/inspector lookups. Defaults to the singleton
103
+ * `defaultConfig` exported from `core/node.ts`.
104
+ * - `versioning` — convenience for `graph.setVersioning(level)` at
105
+ * construction time. Monotonic bulk-apply; see {@link Graph.setVersioning}.
106
+ * - `factories` — reserved for future per-graph factory registration;
107
+ * currently factories flow through `Graph.fromSnapshot(data, {factories})`.
108
+ */
109
+ interface GraphOptions {
110
+ config?: GraphReFlyConfig;
111
+ versioning?: VersioningLevel;
112
+ factories?: Record<string, GraphNodeFactory>;
113
+ /**
114
+ * Capacity of the reasoning-trace ring buffer. Default: `1000`. Set lower
115
+ * to reduce memory; higher for audit-heavy workloads. Set at construction
116
+ * time — not mutable afterward (ring buffers can't resize cleanly).
117
+ */
118
+ traceCapacity?: number;
119
+ [key: string]: unknown;
120
+ }
121
+ /** Filter for {@link Graph.describe} — object-style partial match or predicate. */
122
+ type DescribeFilter = Partial<Pick<DescribeNodeOutput, "type" | "status">> | {
123
+ type?: DescribeNodeOutput["type"];
124
+ status?: DescribeNodeOutput["status"];
125
+ /** Keep nodes whose `deps` includes this qualified path. */
126
+ depsIncludes?: string;
127
+ /** Snake-case alias for `depsIncludes` (Python parity). */
128
+ deps_includes?: string;
129
+ /** Keep nodes whose `meta` contains this key. */
130
+ metaHas?: string;
131
+ /** Snake-case alias for `metaHas` (Python parity). */
132
+ meta_has?: string;
133
+ } | ((node: DescribeNodeOutput) => boolean) | ((nodePath: string, node: DescribeNodeOutput) => boolean);
134
+ /** Options for {@link Graph.signal} and {@link Graph.set} (actor context, internal lifecycle). */
135
+ type GraphActorOptions = {
136
+ actor?: Actor;
137
+ /**
138
+ * When `true`, skips node guards (graph lifecycle TEARDOWN, unmount teardown, etc.).
139
+ */
140
+ internal?: boolean;
141
+ };
142
+ /** Options for {@link Graph.describe} (Phase 3.3b progressive disclosure). */
143
+ type GraphDescribeOptions = {
144
+ actor?: Actor;
145
+ /**
146
+ * Node filter. Filters operate on whatever fields the chosen `detail` level
147
+ * provides. For `metaHas` and `status` filters, use `detail: "standard"` or
148
+ * higher — at `"minimal"` those fields are absent and the filter silently
149
+ * excludes all nodes.
150
+ */
151
+ filter?: DescribeFilter;
152
+ /**
153
+ * Detail level (Phase 3.3b). Default: `"minimal"`.
154
+ * - `"minimal"` — type + deps only
155
+ * - `"standard"` — type, status, value, deps, meta, versioning (`v`)
156
+ * - `"full"` — standard + guard, lastMutation
157
+ */
158
+ detail?: DescribeDetail;
159
+ /**
160
+ * Explicit field selection (GraphQL-style). Overrides `detail` when provided.
161
+ * Dotted paths like `"meta.label"` select specific meta keys.
162
+ */
163
+ fields?: DescribeField[];
164
+ /**
165
+ * Output format.
166
+ * - `undefined` / omitted — return the full {@link GraphDescribeOutput} object.
167
+ * - `"spec"` — GraphSpec input format (object; no status/value, deps as edges).
168
+ * - `"json"` — stable JSON **text** with sorted keys.
169
+ * - `"pretty"` — human-readable plaintext (optionally colorized; see
170
+ * `colorize` / `indent` / `logger` / `includeEdges` / `includeSubgraphs`).
171
+ * - `"mermaid"` — Mermaid flowchart text.
172
+ * - `"d2"` — D2 diagram text.
173
+ */
174
+ format?: "spec" | "json" | "pretty" | "mermaid" | "d2";
175
+ /** Pretty/diagram render: direction for diagram formats (default `LR`). */
176
+ direction?: GraphDiagramDirection;
177
+ /** Pretty/JSON render: indent (default 2 for JSON, ignored for pretty). */
178
+ indent?: number;
179
+ /** Pretty render: optional logger hook; fires with the rendered text before return. */
180
+ logger?: (text: string) => void;
181
+ /** Pretty render: include an Edges section (default `true`). */
182
+ includeEdges?: boolean;
183
+ /** Pretty render: include a Subgraphs section (default `true`). */
184
+ includeSubgraphs?: boolean;
185
+ };
186
+ /** JSON snapshot from {@link Graph.describe} (GRAPHREFLY-SPEC §3.6, Appendix B). */
187
+ type GraphDescribeOutput = {
188
+ name: string;
189
+ nodes: Record<string, DescribeNodeOutput>;
190
+ edges: ReadonlyArray<{
191
+ from: string;
192
+ to: string;
193
+ }>;
194
+ subgraphs: string[];
195
+ /**
196
+ * Re-read the live graph with higher detail (Phase 3.3b).
197
+ * Returns a new `GraphDescribeOutput`; the original remains a snapshot.
198
+ * Present on live describe results; absent on deserialized snapshots.
199
+ */
200
+ expand?: (detailOrFields: DescribeDetail | DescribeField[]) => GraphDescribeOutput;
201
+ };
202
+ /**
203
+ * Persisted graph snapshot: {@link GraphDescribeOutput} plus optional format version
204
+ * ({@link Graph.snapshot}, {@link Graph.restore}, {@link Graph.fromSnapshot}, {@link Graph.toObject},
205
+ * {@link Graph.toJSONString} — §3.8).
206
+ */
207
+ type GraphPersistSnapshot = GraphDescribeOutput & {
208
+ version?: number;
209
+ };
210
+ type GraphFactoryContext = {
211
+ path: string;
212
+ type: DescribeNodeOutput["type"];
213
+ value: unknown;
214
+ meta: Record<string, unknown>;
215
+ deps: readonly string[];
216
+ resolvedDeps: readonly Node[];
217
+ };
218
+ type GraphNodeFactory = (name: string, context: GraphFactoryContext) => Node;
219
+ /**
220
+ * Checkpoint record shape passed to `StorageTier.save`. Written by
221
+ * {@link Graph.attachStorage} per-tier according to each tier's
222
+ * `compactEvery` cadence.
223
+ *
224
+ * `mode: "full"` → full snapshot. Baseline anchor emitted on the first save
225
+ * and every `compactEvery`-th save thereafter. Sufficient to recover state
226
+ * on its own without WAL replay.
227
+ * `mode: "diff"` → delta payload only, relative to this tier's most recent
228
+ * `"full"` baseline. Between compacts. Wire-efficient; requires WAL replay
229
+ * over the preceding `"full"` record to reconstruct state.
230
+ *
231
+ * Every record includes `seq` (per-tier monotonic counter), `timestamp_ns`
232
+ * (wall-clock at flush time), and `format_version` (envelope version for
233
+ * cross-version WAL replay).
234
+ */
235
+ type GraphCheckpointRecord = {
236
+ seq: number;
237
+ timestamp_ns: number;
238
+ format_version: number;
239
+ } & ({
240
+ mode: "full";
241
+ snapshot: GraphPersistSnapshot;
242
+ } | {
243
+ mode: "diff";
244
+ diff: GraphWALDiff;
245
+ });
246
+ /** Options for {@link Graph.attachStorage}. */
247
+ type GraphAttachStorageOptions = {
248
+ /**
249
+ * Before the first save, attempt to restore from the first tier whose
250
+ * `load(graph.name)` hits. Runs asynchronously in the background for
251
+ * async tiers; errors surface via `onError`. Default `false`.
252
+ */
253
+ autoRestore?: boolean;
254
+ /**
255
+ * Limit the subscription surface (scoped observe). By default
256
+ * `attachStorage` observes every node in the graph tree; on large graphs
257
+ * that's thousands of subscriptions just for tier-gating. Pass a path
258
+ * list (or a single glob) to observe only those nodes.
259
+ */
260
+ paths?: readonly string[] | string;
261
+ /** Pre-save path-level filter — skip records triggered by paths that fail this predicate. */
262
+ filter?: (name: string, described: DescribeNodeOutput) => boolean;
263
+ /** Surfaced on tier save errors and autoRestore failures. */
264
+ onError?: (error: unknown, tier: StorageTier) => void;
265
+ };
266
+ /** Direction options for diagram export helpers. */
267
+ type GraphDiagramDirection = "TD" | "LR" | "BT" | "RL";
268
+ /** Options for {@link Graph.toMermaid} / {@link Graph.toD2}. */
269
+ type GraphDiagramOptions = {
270
+ /**
271
+ * Diagram flow direction.
272
+ * - `TD`: top-down
273
+ * - `LR`: left-right (default)
274
+ * - `BT`: bottom-top
275
+ * - `RL`: right-left
276
+ */
277
+ direction?: GraphDiagramDirection;
278
+ };
279
+ /**
280
+ * Option shapes that trigger structured-mode dispatch in {@link Graph.observe}.
281
+ * Presence of any of these fields (truthy) → returns {@link ObserveResult};
282
+ * otherwise `observe()` returns the raw-stream variants.
283
+ */
284
+ type StructuredTriggers = {
285
+ structured?: true;
286
+ timeline?: true;
287
+ causal?: true;
288
+ derived?: true;
289
+ format?: "pretty" | "json";
290
+ detail?: "minimal" | "full";
291
+ };
292
+ /** {@link Graph.observe} on a single node or meta path — sink receives plain message batches. */
293
+ type GraphObserveOne = {
294
+ subscribe(sink: NodeSink): () => void;
295
+ /** Send messages upstream toward the observed node's sources (e.g. PAUSE/RESUME). */
296
+ up(messages: Messages): void;
297
+ };
298
+ /**
299
+ * {@link Graph.observe} on the whole graph — sink receives each batch with the qualified source path.
300
+ * Subscription order follows code-point sort on paths (mounts-first walk, then sorted locals/meta).
301
+ */
302
+ type GraphObserveAll = {
303
+ subscribe(sink: (nodePath: string, messages: Messages) => void): () => void;
304
+ /** Send messages upstream toward a specific observed node's sources (e.g. PAUSE/RESUME). */
305
+ up(path: string, messages: Messages): void;
306
+ };
307
+ /**
308
+ * Detail level for `observe()` progressive disclosure (Phase 3.3b).
309
+ * - `"minimal"` — DATA events only, no timestamps, no causal info.
310
+ * - `"standard"` — all message types (DATA, DIRTY, RESOLVED, INVALIDATE,
311
+ * PAUSE, RESUME, COMPLETE, ERROR, TEARDOWN).
312
+ * - `"full"` — standard + timeline + causal + derived.
313
+ */
314
+ type ObserveDetail = "minimal" | "standard" | "full";
315
+ /** Options for structured observation modes on {@link Graph.observe}. */
316
+ type ObserveOptions = {
317
+ actor?: Actor;
318
+ /** Return an {@link ObserveResult} accumulator instead of a raw stream. */
319
+ structured?: boolean;
320
+ /** Include causal trace info (which dep triggered each recomputation). */
321
+ causal?: boolean;
322
+ /** Include timestamps and batch context on each event. */
323
+ timeline?: boolean;
324
+ /** Include per-evaluation dep snapshots for compute/derived nodes. */
325
+ derived?: boolean;
326
+ /**
327
+ * Detail level (Phase 3.3b). Individual flags (`causal`, `timeline`, `derived`)
328
+ * override. `"full"` implies all three plus structured.
329
+ * `"minimal"` filters to DATA-only events.
330
+ */
331
+ detail?: ObserveDetail;
332
+ /**
333
+ * When set, auto-enables structured mode and attaches a logger.
334
+ * `"pretty"` renders colored one-line output; `"json"` emits one JSON object per event.
335
+ */
336
+ format?: "pretty" | "json";
337
+ /** Sink for rendered lines (`console.log` by default). Only used when `format` is set. */
338
+ logger?: (line: string, event: ObserveEvent) => void;
339
+ /** Keep only these event types in formatted output. Only used when `format` is set. */
340
+ includeTypes?: ObserveEvent["type"][];
341
+ /** Exclude these event types from formatted output. Only used when `format` is set. */
342
+ excludeTypes?: ObserveEvent["type"][];
343
+ /** Built-in color preset (`ansi` default) or explicit color tokens. Only used when `format` is set. */
344
+ theme?: ObserveThemeName | ObserveTheme;
345
+ /**
346
+ * Cap the `events` buffer. When set, the result uses a {@link RingBuffer}
347
+ * under the hood: oldest events are dropped on overflow. Unbounded when
348
+ * omitted (default).
349
+ */
350
+ maxEvents?: number;
351
+ };
352
+ /** Accumulated observation result (structured mode). */
353
+ type ObserveResult<T = unknown> = AsyncIterable<ObserveEvent> & {
354
+ /** Latest DATA value by observed path. */
355
+ readonly values: Record<string, T>;
356
+ /** Number of DIRTY messages received. */
357
+ readonly dirtyCount: number;
358
+ /** Number of RESOLVED messages received. */
359
+ readonly resolvedCount: number;
360
+ /** Number of INVALIDATE messages received (tier 1 cache-clear). */
361
+ readonly invalidateCount: number;
362
+ /** Number of PAUSE messages received (tier 2 backpressure). */
363
+ readonly pauseCount: number;
364
+ /** Number of RESUME messages received (tier 2 backpressure). */
365
+ readonly resumeCount: number;
366
+ /** Number of TEARDOWN messages received (tier 5 permanent cleanup). */
367
+ readonly teardownCount: number;
368
+ /**
369
+ * All events in order — ring-buffered when `options.maxEvents` is set,
370
+ * unbounded otherwise. Always materialized as an `ObserveEvent[]`
371
+ * snapshot on read.
372
+ */
373
+ readonly events: ObserveEvent[];
374
+ /** True if any observed node sent COMPLETE without prior ERROR on that node. */
375
+ readonly anyCompletedCleanly: boolean;
376
+ /** True if any observed node sent ERROR. */
377
+ readonly anyErrored: boolean;
378
+ /** True if at least one COMPLETE received and no ERROR from any observed node. */
379
+ readonly completedWithoutErrors: boolean;
380
+ /**
381
+ * Attach a live listener that fires for each event as it arrives.
382
+ * Returns an unsubscribe fn. Independent of the `events` buffer.
383
+ */
384
+ onEvent(listener: (event: ObserveEvent) => void): () => void;
385
+ /** Stop observing. */
386
+ dispose(): void;
387
+ /**
388
+ * Resubscribe with higher detail (Phase 3.3b).
389
+ * Disposes current observation, returns new `ObserveResult` with merged options.
390
+ */
391
+ expand(extra: Partial<Pick<ObserveOptions, "causal" | "timeline" | "derived">> | ObserveDetail): ObserveResult<T>;
392
+ };
393
+ /** Fields common to every {@link ObserveEvent} variant. */
394
+ interface ObserveEventBase {
395
+ path?: string;
396
+ /** Optional `timeline` context — wall-clock when `options.timeline === true`. */
397
+ timestamp_ns?: number;
398
+ in_batch?: boolean;
399
+ /** Monotonically increasing counter per subscribe-callback invocation. All events in one delivery share the same id. */
400
+ batch_id?: number;
401
+ }
402
+ /** Optional `causal` context present on `data`/`resolved`/`derived` events. */
403
+ interface ObserveCausalContext {
404
+ trigger_dep_index?: number;
405
+ trigger_dep_name?: string;
406
+ /**
407
+ * V0 version of the triggering dep at observation time (§6.0b).
408
+ * This is the dep's post-emission version (after its own `advanceVersion`),
409
+ * not the pre-emission version that caused this node's recomputation.
410
+ */
411
+ trigger_version?: {
412
+ id: string;
413
+ version: number;
414
+ };
415
+ /**
416
+ * One scalar per dep: the last value that arrived in the current wave,
417
+ * or the pre-wave cached value for deps that didn't fire. Convenient
418
+ * for single-value-wave tooling (the common case).
419
+ */
420
+ dep_values?: unknown[];
421
+ /**
422
+ * Full per-dep batches for the wave that fired the fn — `dep_batches[i]`
423
+ * is the array of values dep `i` delivered this wave (`undefined` for
424
+ * deps that didn't fire). Use this to distinguish a single-value wave
425
+ * from a multi-value wave; `dep_values` compresses each batch to its
426
+ * last element and hides that difference.
427
+ */
428
+ dep_batches?: ReadonlyArray<ReadonlyArray<unknown> | undefined>;
429
+ }
430
+ /** A single event in the structured observation log (discriminated on `type`). */
431
+ type ObserveEvent = (ObserveEventBase & ObserveCausalContext & {
432
+ type: "data";
433
+ data: unknown;
434
+ }) | (ObserveEventBase & {
435
+ type: "dirty";
436
+ }) | (ObserveEventBase & ObserveCausalContext & {
437
+ type: "resolved";
438
+ }) | (ObserveEventBase & {
439
+ type: "invalidate";
440
+ }) | (ObserveEventBase & {
441
+ type: "pause";
442
+ lockId: unknown;
443
+ }) | (ObserveEventBase & {
444
+ type: "resume";
445
+ lockId: unknown;
446
+ }) | (ObserveEventBase & {
447
+ type: "complete";
448
+ }) | (ObserveEventBase & {
449
+ type: "error";
450
+ data: unknown;
451
+ }) | (ObserveEventBase & {
452
+ type: "teardown";
453
+ }) | (ObserveEventBase & ObserveCausalContext & {
454
+ type: "derived";
455
+ dep_values: unknown[];
456
+ });
457
+ /** Built-in color preset names for observe `format` rendering. */
458
+ type ObserveThemeName = "none" | "ansi";
459
+ /** ANSI/style overrides for observe `format` event rendering. */
460
+ type ObserveTheme = Partial<Record<ObserveEvent["type"] | "path" | "reset", string>>;
461
+ /**
462
+ * Named container for nodes and explicit edges (GRAPHREFLY-SPEC §3.1–§3.7).
463
+ *
464
+ * Qualified paths use `::` as the segment separator (for example `parent::child::node`).
465
+ *
466
+ * Edges are pure wires: `connect` only validates wiring — the target must already list the source in
467
+ * its dependency array; no transforms run on the edge.
468
+ *
469
+ * @example
470
+ * ```ts
471
+ * import { Graph, state } from "@graphrefly/graphrefly-ts";
472
+ *
473
+ * const g = new Graph("app");
474
+ * g.add("counter", state(0));
475
+ * ```
476
+ *
477
+ * @category graph
478
+ */
479
+ declare class Graph {
480
+ readonly name: string;
481
+ readonly opts: Readonly<GraphOptions>;
482
+ /** Protocol config bound to this graph (defaults to `defaultConfig`). */
483
+ readonly config: GraphReFlyConfig;
484
+ /** @internal — exposed for {@link teardownMountedGraph} and cross-graph helpers. */
485
+ readonly _nodes: Map<string, Node<unknown>>;
486
+ /**
487
+ * @internal Reverse lookup for duplicate-instance detection in
488
+ * {@link Graph.add} — O(1) replacement for an O(n) scan of `_nodes`.
489
+ * Weak so nodes can be GC'd after `remove()` even if a caller keeps the
490
+ * map alive via some unusual pattern.
491
+ */
492
+ private readonly _nodeToName;
493
+ /** @internal — exposed for {@link teardownMountedGraph}. */
494
+ readonly _mounts: Map<string, Graph>;
495
+ /**
496
+ * @internal Parent graph if this instance is mounted. `undefined` when
497
+ * this is the root or when the graph has been unmounted. Used for
498
+ * reparenting rejection + O(depth) ancestor walks.
499
+ */
500
+ _parent: Graph | undefined;
501
+ private readonly _storageDisposers;
502
+ private readonly _disposers;
503
+ /**
504
+ * @param name - Non-empty graph id (must not contain `::` and must not
505
+ * equal the reserved meta segment `__meta__`).
506
+ * @param opts - See {@link GraphOptions}. Stored frozen on the instance.
507
+ */
508
+ constructor(name: string, opts?: GraphOptions);
509
+ /**
510
+ * Walk ancestors up through `_parent`. Returns the chain starting at this
511
+ * instance, ending at the root (a graph with no parent). O(depth).
512
+ *
513
+ * @param includeSelf - Include `this` in the chain (default `true`).
514
+ */
515
+ ancestors(includeSelf?: boolean): Graph[];
516
+ /**
517
+ * Registers a node under a local name. Fails if the name is already used,
518
+ * reserved by a mount, the same node instance is already registered, or
519
+ * the node is torn down.
520
+ *
521
+ * Returns the registered node so callers can chain:
522
+ * `const counter = g.add("counter", state(0))`.
523
+ *
524
+ * @param name - Local key (no `::`).
525
+ * @param node - Node instance to own.
526
+ */
527
+ add<T extends Node>(name: string, node: T): T;
528
+ /**
529
+ * Bulk-apply a minimum versioning level to every currently-registered node
530
+ * in this graph (roadmap §6.0). `_applyVersioning` is monotonic — nodes
531
+ * already at a higher level are untouched. The method refuses to run
532
+ * mid-wave; invoke at setup time before any external subscribers attach.
533
+ *
534
+ * **Not** a default-for-future-adds mechanism — that's what
535
+ * `config.defaultVersioning` is for. Nodes added after this call do NOT
536
+ * automatically inherit `level`; register new nodes with their own
537
+ * `opts.versioning` or set `config.defaultVersioning` before construction.
538
+ *
539
+ * **Scope:** local only. Does not propagate to mounted subgraphs.
540
+ *
541
+ * @param level - `0` for V0, `1` for V1, or `undefined` to no-op.
542
+ */
543
+ setVersioning(level: VersioningLevel | undefined): void;
544
+ /**
545
+ * Unregisters a node or unmounts a subgraph and sends `[[TEARDOWN]]` to the
546
+ * removed node or recursively through the mounted subtree (§3.2).
547
+ *
548
+ * @param name - Local mount or node name.
549
+ * @returns Audit record of what was removed: `{kind, nodes, mounts}`.
550
+ * `kind: "node"` → `nodes: [name]`, `mounts: []`. `kind: "mount"` →
551
+ * `nodes` lists every primary node torn down across the subtree (sorted
552
+ * qualified paths relative to the unmounted subgraph) and `mounts` lists
553
+ * the mounted subgraphs in depth-first order including `name` itself.
554
+ */
555
+ remove(name: string): GraphRemoveAudit;
556
+ /**
557
+ * Bulk remove — invokes {@link Graph.remove} for every local name matching
558
+ * `filter`. Audit records merge into a single result. Mounted subgraphs
559
+ * are included via `filter` receiving the mount name; internal subtree
560
+ * entries are not walked directly (use describe + scan for tree-level
561
+ * queries).
562
+ *
563
+ * @param filter - Predicate or glob. Glob strings support `*` within a
564
+ * segment and `**` across segments (same grammar as `restore({only})`).
565
+ * @returns Combined audit of all nodes + mounts removed.
566
+ */
567
+ removeAll(filter: ((name: string) => boolean) | string): GraphRemoveAudit;
568
+ /**
569
+ * Iterable over locally-registered `[localName, Node]` pairs (sorted).
570
+ * Does not recurse into mounts.
571
+ */
572
+ [Symbol.iterator](): IterableIterator<[string, Node]>;
573
+ /**
574
+ * Returns a node by local name or `::` qualified path.
575
+ * Local names are looked up directly; paths with `::` delegate to {@link resolve}.
576
+ *
577
+ * @param name - Local name or qualified path.
578
+ */
579
+ node(name: string): Node;
580
+ /**
581
+ * Reads `graph.node(name).get()` — accepts `::` qualified paths (§3.2).
582
+ *
583
+ * @param name - Local name or qualified path.
584
+ * @returns Cached value or `undefined`.
585
+ */
586
+ get(name: string): unknown;
587
+ /**
588
+ * Shorthand for `graph.node(name).down([[DATA, value]], { actor })` — accepts `::` qualified paths (§3.2).
589
+ *
590
+ * @param name - Local name or qualified path.
591
+ * @param value - Next `DATA` payload.
592
+ * @param options - Optional `actor` and `internal` guard bypass.
593
+ */
594
+ set(name: string, value: unknown, options?: GraphActorOptions): void;
595
+ /**
596
+ * Atomic multi-node DATA write. Wraps every {@link Graph.set} call in a
597
+ * single `batch(...)` so downstream dependents see one coalesced wave
598
+ * instead of N cascading ones.
599
+ *
600
+ * @param entries - `{name → value}` map or `[name, value]` pairs.
601
+ * @param options - Passed to each underlying `set` call (same `actor` + `internal` semantics).
602
+ */
603
+ setAll(entries: Record<string, unknown> | Iterable<readonly [string, unknown]>, options?: GraphActorOptions): void;
604
+ /**
605
+ * Emit a single `[[INVALIDATE]]` (tier 1) on a node. Thin wrapper over
606
+ * `node.down([[INVALIDATE]], …)` matching the {@link Graph.set} ergonomics.
607
+ */
608
+ invalidate(name: string, options?: GraphActorOptions): void;
609
+ /**
610
+ * Emit a single `[[ERROR, err]]` (tier 4) on a node.
611
+ */
612
+ error(name: string, err: unknown, options?: GraphActorOptions): void;
613
+ /**
614
+ * Emit a single `[[COMPLETE]]` (tier 4) on a node, declaring the stream
615
+ * cleanly finished. Distinct from {@link Graph.remove} (which emits
616
+ * TEARDOWN and unregisters the node).
617
+ */
618
+ complete(name: string, options?: GraphActorOptions): void;
619
+ /**
620
+ * Returns the full edge list for this graph tree, derived on demand from
621
+ * each registered node's `_deps` (no stored registry). Local-only
622
+ * (non-recursive) by default to match the historical `edges()` surface;
623
+ * pass `{recursive: true}` to include mounted subgraphs with qualified
624
+ * paths relative to this graph.
625
+ *
626
+ * Use {@link Graph.describe} for full-tree snapshots with edges already
627
+ * qualified and paired with node metadata.
628
+ */
629
+ edges(opts?: {
630
+ recursive?: boolean;
631
+ }): ReadonlyArray<[string, string]>;
632
+ /**
633
+ * Embed a child graph at a local mount name (§3.4). Child nodes are reachable via
634
+ * {@link Graph.resolve} using `::` delimited paths (§3.5). Lifecycle
635
+ * {@link Graph.signal} visits mounted subgraphs recursively.
636
+ *
637
+ * Rejects: same name as existing node or mount, self-mount, mount cycles,
638
+ * and the same child graph instance mounted twice on one parent.
639
+ *
640
+ * @param name - Local mount point.
641
+ * @param child - Nested `Graph` instance.
642
+ * @returns The mounted `child`, for chaining.
643
+ */
644
+ mount<G extends Graph>(name: string, child: G): G;
645
+ /**
646
+ * Look up a node by qualified path (§3.5). Segments are separated by `::`.
647
+ *
648
+ * If the first segment equals this graph's {@link Graph.name}, it is stripped
649
+ * (so `root.resolve("app::a")` works when `root.name === "app"`). The strip
650
+ * is applied **recursively** when descending into mounted children, so
651
+ * `child.resolve("child::x")` also works when `child.name === "child"`.
652
+ *
653
+ * @param path - Qualified `::` path or local name.
654
+ * @returns The resolved `Node`.
655
+ */
656
+ resolve(path: string): Node;
657
+ /**
658
+ * Non-throwing {@link Graph.resolve}. Returns `undefined` instead of
659
+ * throwing when the path does not resolve to a node.
660
+ */
661
+ tryResolve(path: string): Node | undefined;
662
+ private _resolveFromSegments;
663
+ /**
664
+ * Resolve `::__meta__::key` segments from a registered primary node (possibly chained).
665
+ */
666
+ private _resolveMetaChainFromNode;
667
+ /**
668
+ * Deliver a message batch to every registered node in this graph and, recursively,
669
+ * in mounted child graphs (§3.7). Recurses into mounts first, then delivers to
670
+ * local nodes (sorted by name). Each {@link Node} receives at most one delivery
671
+ * per call (deduped by reference).
672
+ *
673
+ * **Primary-vs-meta filter asymmetry (intentional):** primary nodes receive the
674
+ * unfiltered `messages` batch — that's the canonical data-plane flow. Companion
675
+ * `meta` nodes receive a filtered subset keyed by the per-type `metaPassthrough`
676
+ * flag on {@link GraphReFlyConfig}. Built-in defaults: PAUSE / RESUME / DATA /
677
+ * RESOLVED pass through to meta; INVALIDATE / COMPLETE / ERROR / TEARDOWN do
678
+ * not.
679
+ *
680
+ * **Where lifecycle terminals reach meta:**
681
+ * - **TEARDOWN** — primary's `_emit` cascades to meta children directly (see
682
+ * `core/node.ts` "Meta TEARDOWN fan-out" block) so meta is torn down with
683
+ * its primary regardless of the signal-level filter.
684
+ * - **COMPLETE / ERROR / INVALIDATE** — scoped to primaries on the broadcast
685
+ * path. Meta companions are an attribution side-channel, not a lifecycle
686
+ * participant; address meta directly via `meta.down(...)` if you need to
687
+ * forward these. Audit confirmed 2026-04-17: no current meta consumer
688
+ * relies on broadcast COMPLETE/ERROR/INVALIDATE delivery.
689
+ *
690
+ * @param messages - Batch to deliver to every registered node (and mounts, recursively).
691
+ * @param options - Optional `actor` / `internal` for transport.
692
+ */
693
+ signal(messages: Messages, options?: GraphActorOptions): void;
694
+ private _signalDeliver;
695
+ private _signalMetaSubtree;
696
+ /**
697
+ * Static structure snapshot: qualified node keys, edges, mount names (GRAPHREFLY-SPEC §3.6, Appendix B).
698
+ *
699
+ * `format` controls the return type:
700
+ * - omitted or `"spec"` → {@link GraphDescribeOutput} object.
701
+ * - `"json"` / `"pretty"` / `"mermaid"` / `"d2"` → rendered string.
702
+ *
703
+ * @param options - Optional `actor` for guard-scoped visibility, `filter` for
704
+ * selective output, or `format` to render.
705
+ *
706
+ * @example
707
+ * ```ts
708
+ * graph.describe() // full snapshot object
709
+ * graph.describe({ filter: { status: "errored" } }) // filtered object
710
+ * graph.describe({ format: "pretty" }) // human-readable text
711
+ * graph.describe({ format: "mermaid" }) // Mermaid flowchart
712
+ * graph.describe({ format: "d2", direction: "TD" }) // D2 top-down
713
+ * ```
714
+ */
715
+ describe(options: GraphDescribeOptions & {
716
+ format: "json" | "pretty" | "mermaid" | "d2";
717
+ }): string;
718
+ describe(options?: GraphDescribeOptions): GraphDescribeOutput;
719
+ private _collectSubgraphs;
720
+ /**
721
+ * Snapshot-based resource profile: per-node stats, orphan effect detection,
722
+ * memory hotspots. Zero runtime overhead — walks nodes on demand.
723
+ *
724
+ * @param opts - Optional `topN` for hotspot limit (default 10).
725
+ * @returns Aggregate profile with per-node details, hotspots, and orphan effects.
726
+ */
727
+ resourceProfile(opts?: GraphProfileOptions): GraphProfileResult;
728
+ /**
729
+ * Reachability query rooted at `from`. Instance convenience — wraps
730
+ * `reachable(this.describe(), from, direction, opts)`. See
731
+ * {@link reachable} for semantics.
732
+ */
733
+ reachable(from: string, direction: ReachableDirection, opts: ReachableOptions & {
734
+ withDetail: true;
735
+ }): ReachableResult;
736
+ reachable(from: string, direction: ReachableDirection, opts?: ReachableOptions): string[];
737
+ /**
738
+ * @internal Collect all qualified paths in this graph tree matching a
739
+ * glob pattern. Used by scoped autoCheckpoint subscription.
740
+ */
741
+ private _pathsMatching;
742
+ private _collectObserveTargets;
743
+ private _appendMetaObserveTargets;
744
+ /**
745
+ * Live message stream from one node (or meta path), or from the whole graph (§3.6).
746
+ *
747
+ * Two modes dispatched on first argument:
748
+ * - `observe(path, options?)` — one node. Returns {@link GraphObserveOne}
749
+ * (raw stream), or {@link ObserveResult} when `options` requests structured
750
+ * accumulation (`structured`, `timeline`, `causal`, `derived`, `format`,
751
+ * `detail: "minimal"|"full"`).
752
+ * - `observe(options?)` — all nodes. Returns {@link GraphObserveAll} (raw),
753
+ * or {@link ObserveResult} under the same structured trigger conditions.
754
+ *
755
+ * Structured mode subscribes in sorted path order (code-point). Inspector
756
+ * extras (`causal`/`derived`) require `graph.config.inspectorEnabled`;
757
+ * when disabled, those fields silently drop and the rest still works.
758
+ *
759
+ * `ObserveResult` is also an `AsyncIterable<ObserveEvent>` — use
760
+ * `for await (const ev of result)` for pull-based consumption.
761
+ */
762
+ observe(path: string, options?: ObserveOptions & StructuredTriggers): ObserveResult;
763
+ observe(path: string, options?: ObserveOptions): GraphObserveOne;
764
+ observe(options: ObserveOptions & StructuredTriggers): ObserveResult;
765
+ observe(options?: ObserveOptions): GraphObserveAll;
766
+ /** Dispatch helper — builds a unified observer + its expand closure. */
767
+ private _buildStructuredObserver;
768
+ /**
769
+ * Unified observer builder — replaces the four ex-creators
770
+ * (`_createObserveResult` / `...ForAll` / `_createFallback…`). Accepts a
771
+ * list of `[path, node]` targets (single-element for one-node observe,
772
+ * N-element for all-nodes). Inspector hooks attach per-target when
773
+ * `causal`/`derived` requested AND `config.inspectorEnabled`; otherwise
774
+ * those fields gracefully drop.
775
+ *
776
+ * Events flow through a `recordEvent()` helper so the format logger,
777
+ * ring-buffer, and async-iterable hooks all share one push path.
778
+ */
779
+ private _createObserveResult;
780
+ /**
781
+ * Attach format-rendering logger to an ObserveResult by subscribing to its
782
+ * event stream (no monkey-patching). Renders each event per `format` and
783
+ * `theme`, filtered by `includeTypes` / `excludeTypes`.
784
+ */
785
+ private _attachFormatLogger;
786
+ /**
787
+ * Register a cleanup function to be called on {@link Graph.destroy}.
788
+ *
789
+ * Factories use this to attach teardown logic for internal nodes, keepalive
790
+ * subscriptions, or other resources that are not registered on the graph and
791
+ * would otherwise leak on repeated create/destroy cycles.
792
+ *
793
+ * Returns a removal function — call it to unregister the disposer early.
794
+ */
795
+ addDisposer(fn: () => void): () => void;
796
+ /**
797
+ * Drains disposers (registered via {@link addDisposer}), then sends `[[TEARDOWN]]` to all
798
+ * nodes and clears registries on this graph and every mounted subgraph (§3.7).
799
+ * The instance is left empty and may be reused with {@link Graph.add}.
800
+ */
801
+ destroy(): void;
802
+ /** Clear structure after parent already signaled TEARDOWN through this subtree. */
803
+ private _destroyClearOnly;
804
+ /**
805
+ * Serializes structure and current values to JSON-shaped data (§3.8). Same
806
+ * information as {@link Graph.describe} plus a `version` field for format
807
+ * evolution.
808
+ *
809
+ * The overload path supports three outputs:
810
+ * - no arg → `GraphPersistSnapshot` (plain JS object).
811
+ * - `{format: "json-string"}` → deterministic JSON `string`
812
+ * (key-sorted; safe for hashing or file write).
813
+ * - `{format: "bytes", codec: name}` → `Uint8Array` wrapped in the v1
814
+ * envelope from {@link encodeEnvelope}. The codec must be registered
815
+ * on this graph's {@link GraphReFlyConfig} via `config.registerCodec`.
816
+ * Paired with {@link Graph.decode} for auto-dispatch on the read side.
817
+ */
818
+ snapshot(): GraphPersistSnapshot;
819
+ snapshot(opts: {
820
+ format: "json-string";
821
+ }): string;
822
+ snapshot(opts: {
823
+ format: "bytes";
824
+ codec: string;
825
+ }): Uint8Array;
826
+ /**
827
+ * Auto-dispatch a byte buffer produced by {@link Graph.snapshot} with
828
+ * `{format: "bytes", codec: name}`. Reads the v1 envelope, resolves the
829
+ * named codec on `config` (defaults to `defaultConfig`), and returns the
830
+ * decoded snapshot. Combine with {@link Graph.fromSnapshot} to rehydrate
831
+ * a full graph topology from bytes.
832
+ *
833
+ * @throws If the envelope is malformed or the named codec isn't
834
+ * registered on the target config.
835
+ */
836
+ static decode(bytes: Uint8Array, opts?: {
837
+ config?: GraphReFlyConfig;
838
+ }): GraphPersistSnapshot;
839
+ /**
840
+ * Apply persisted values onto an existing graph whose topology matches the snapshot
841
+ * (§3.8). Only {@link DescribeNodeOutput.type} `state` entries with a `value` field
842
+ * are written by default; `derived` / `operator` / `effect` are always skipped so
843
+ * deps drive recomputation. `producer` entries are skipped unless `includeProducers`
844
+ * is set (producers recompute on activation, so restoring is usually a no-op
845
+ * overwritten on the next wave — opt in for audit / forensic round-trip use cases).
846
+ * Unknown paths are ignored.
847
+ *
848
+ * @param data - Snapshot envelope with matching `name` and node slices.
849
+ * @throws If `data.name` does not equal {@link Graph.name}.
850
+ */
851
+ restore(data: GraphPersistSnapshot, options?: {
852
+ only?: string | readonly string[];
853
+ /**
854
+ * Fires per failing write. Default behavior (omitted) is silent —
855
+ * missing paths and guard denials are swallowed to match the
856
+ * historical semantics. Provide a callback to surface failures
857
+ * without aborting the remaining restores.
858
+ */
859
+ onError?: (path: string, err: unknown) => void;
860
+ /**
861
+ * Restore `producer` node values alongside `state`. Default `false`:
862
+ * producers are reactive sources whose value recomputes on
863
+ * activation, so restoring from a snapshot is usually a no-op
864
+ * overwritten on the next wave. Audit / forensic round-trip use
865
+ * cases that need the stored value to survive restoration can
866
+ * opt in. Does not change `derived` / `effect` handling — those
867
+ * are always skipped.
868
+ */
869
+ includeProducers?: boolean;
870
+ }): void;
871
+ /**
872
+ * Creates a graph named from the snapshot, optionally runs `build` to register nodes
873
+ * and mounts, then {@link Graph.restore} values (§3.8).
874
+ *
875
+ * @param data - Snapshot envelope (`version` checked).
876
+ * @param opts - Either a legacy `build(g)` callback, or an options object:
877
+ * - `build?` — topology constructor; skips auto-hydration when present.
878
+ * - `factories?` — map from glob pattern to {@link GraphNodeFactory},
879
+ * used by auto-hydration to reconstruct non-state nodes. Per-call (no
880
+ * process-global registry). First matching pattern wins.
881
+ * @returns Hydrated `Graph` instance.
882
+ */
883
+ static fromSnapshot(data: GraphPersistSnapshot, opts?: ((g: Graph) => void) | {
884
+ build?: (g: Graph) => void;
885
+ factories?: Record<string, GraphNodeFactory>;
886
+ }): Graph;
887
+ /**
888
+ * ECMAScript `JSON.stringify` hook — returns the same object as
889
+ * {@link Graph.snapshot}. Makes `JSON.stringify(graph)` "just work"
890
+ * without double-encoding.
891
+ */
892
+ toJSON(): GraphPersistSnapshot;
893
+ /**
894
+ * Unified persistence surface (§3.8). Cascades snapshot records through
895
+ * one or more {@link StorageTier}s, each with its own `debounceMs` /
896
+ * `compactEvery` cadence and independent diff baseline.
897
+ *
898
+ * Subscription gates on {@link messageTier} ≥ 3 (DATA/RESOLVED/terminal),
899
+ * never on tier-0/1/2 control waves (START/DIRTY/INVALIDATE/PAUSE/RESUME)
900
+ * or tier-5 TEARDOWN (graceful shutdown is the caller's responsibility).
901
+ *
902
+ * Per-tier cadence lets the hot tier stay sync while cold tiers absorb
903
+ * async writes without blocking the hot path. Each tier holds its own
904
+ * `{lastSnapshot, lastVersionFingerprint}` so cold-tier diff baselines
905
+ * aren't polluted by hot-tier flushes. Tiers with `debounceMs === 0`
906
+ * share a single snapshot computation per observe event; debounced tiers
907
+ * compute their own snapshot when their timer fires.
908
+ */
909
+ attachStorage(tiers: readonly StorageTier[], options?: GraphAttachStorageOptions): StorageHandle;
910
+ /**
911
+ * Try tiers in order (hottest first); apply the first record that hits
912
+ * via {@link Graph.restore}. Returns `true` if any tier produced a
913
+ * restorable snapshot, `false` if all missed.
914
+ *
915
+ * Resilience: a tier that returns data which cannot be restored (load
916
+ * throws, shape unrecognized, or `restore()` itself throws) does not abort
917
+ * the cascade — the error is routed through `onError` (if supplied) and
918
+ * the next colder tier is tried. This mirrors how a multi-tier cache
919
+ * falls through on a corrupt hot entry.
920
+ *
921
+ * Note: `restore()` mutates state incrementally. If a restore throws
922
+ * partway through, the graph may hold a mixed state (some slices from
923
+ * the bad tier, some pre-existing). A subsequent successful tier's
924
+ * `restore()` overwrites the overlapping slices.
925
+ *
926
+ * Internal helper shared by {@link Graph.attachStorage}'s `autoRestore`
927
+ * option and the static {@link Graph.fromStorage} factory.
928
+ */
929
+ private _cascadeRestore;
930
+ /**
931
+ * Construct a fresh {@link Graph} pre-hydrated from the first tier that
932
+ * hits. Delegates topology reconstruction to {@link Graph.fromSnapshot}
933
+ * on `"full"` records and direct {@link Graph.restore} on bare snapshots.
934
+ *
935
+ * Always asynchronous — awaits `tier.load()` for async tier support even
936
+ * when all tiers are sync. Callers that know they only pass sync tiers
937
+ * can safely `await` immediately.
938
+ *
939
+ * @throws If no tier holds a restorable record matching `name` *and* no
940
+ * `factories` override is provided for dynamic nodes.
941
+ */
942
+ static fromStorage(name: string, tiers: readonly StorageTier[], opts?: GraphOptions & {
943
+ factories?: Record<string, GraphNodeFactory>;
944
+ /**
945
+ * Called when a tier throws during `load()` or when
946
+ * {@link Graph.fromSnapshot} rejects a tier's record. The cascade
947
+ * falls through to the next colder tier regardless.
948
+ */
949
+ onError?: (err: unknown, tier: StorageTier) => void;
950
+ }): Promise<Graph>;
951
+ private _annotations;
952
+ private readonly _traceRing;
953
+ /**
954
+ * Unified reasoning trace: write annotations or read the ring buffer.
955
+ *
956
+ * Write: `graph.trace("path", "reason")` — attaches a reasoning annotation
957
+ * to a node, capturing *why* an AI agent set a value. Unknown paths are
958
+ * silently dropped (matching `observe` resilience). No-op when
959
+ * `config.inspectorEnabled` is `false`.
960
+ *
961
+ * Read: `graph.trace()` — returns a chronological log of all annotations.
962
+ * Returns `[]` when `config.inspectorEnabled` is `false`.
963
+ */
964
+ trace(path: string, reason: string, opts?: {
965
+ actor?: Actor;
966
+ }): void;
967
+ trace(): readonly TraceEntry[];
968
+ /**
969
+ * Latest reason annotation attached to `path` via {@link Graph.trace},
970
+ * or `undefined` if none. `describe()` surfaces this via the `reason`
971
+ * field on each node entry (when present).
972
+ */
973
+ annotation(path: string): string | undefined;
974
+ /**
975
+ * Clear all reasoning-trace state (both the per-path annotations map and
976
+ * the ring buffer). Useful for long-running processes that want periodic
977
+ * resets, or tests that need a clean slate.
978
+ */
979
+ clearTrace(): void;
980
+ /**
981
+ * Remove trace entries matching `predicate`. Returns the number of
982
+ * entries removed. Does not touch the per-path annotations map — call
983
+ * {@link Graph.clearTrace} for a full reset.
984
+ */
985
+ pruneTrace(predicate: (entry: TraceEntry) => boolean): number;
986
+ /**
987
+ * Computes structural + value diff between two {@link Graph.describe} snapshots.
988
+ *
989
+ * @param a - Earlier describe output.
990
+ * @param b - Later describe output.
991
+ * @returns Added/removed nodes, changed fields, and edge deltas.
992
+ */
993
+ static diff(a: GraphDescribeOutput, b: GraphDescribeOutput): GraphDiffResult;
994
+ }
995
+ /** Entry in the reasoning trace ring buffer (roadmap 3.3). */
996
+ type TraceEntry = {
997
+ path: string;
998
+ reason: string;
999
+ timestamp_ns: number;
1000
+ /**
1001
+ * Actor that produced the annotation (optional). Enables multi-agent
1002
+ * attribution: distinguish "LLM set this rootCause" from "human approved
1003
+ * this intervention" in the trace log.
1004
+ */
1005
+ actor?: Actor;
1006
+ };
1007
+ /** Result of {@link Graph.diff}. */
1008
+ type GraphDiffResult = {
1009
+ nodesAdded: string[];
1010
+ nodesRemoved: string[];
1011
+ nodesChanged: GraphDiffChange[];
1012
+ /**
1013
+ * V0 version bumps (same `v.id`, different `v.version`). Surfaced even
1014
+ * when values are identical — the bump itself is audit-meaningful.
1015
+ */
1016
+ versionChanges: GraphVersionChange[];
1017
+ edgesAdded: Array<{
1018
+ from: string;
1019
+ to: string;
1020
+ }>;
1021
+ edgesRemoved: Array<{
1022
+ from: string;
1023
+ to: string;
1024
+ }>;
1025
+ subgraphsAdded: string[];
1026
+ subgraphsRemoved: string[];
1027
+ };
1028
+ /**
1029
+ * WAL-oriented diff — extends {@link GraphDiffResult} with the full node
1030
+ * slice for each added path so {@link replayWAL} can reconstruct nodes added
1031
+ * between full anchors (topology mutations inside a `compactEvery` window).
1032
+ *
1033
+ * `Graph.diff()` returns the audit shape (no payload); `attachStorage` writes
1034
+ * this WAL shape. The two shapes stay structurally compatible — `GraphWALDiff`
1035
+ * is a superset.
1036
+ */
1037
+ type GraphWALDiff = GraphDiffResult & {
1038
+ /**
1039
+ * Full node slices for every path in `nodesAdded`, keyed by path. Applied
1040
+ * verbatim to `snapshot.nodes[path]` during replay.
1041
+ */
1042
+ nodesAddedFull: Record<string, DescribeNodeOutput>;
1043
+ };
1044
+ /**
1045
+ * Build a WAL-ready diff between two snapshots: the structural diff from
1046
+ * {@link Graph.diff} plus the full node slice for each added path (pulled
1047
+ * from `b.nodes`). Callers that only need the audit shape should use
1048
+ * `Graph.diff` directly.
1049
+ */
1050
+ declare function diffForWAL(a: GraphDescribeOutput, b: GraphDescribeOutput): GraphWALDiff;
1051
+ /** A single field change within a diff. */
1052
+ type GraphDiffChange = {
1053
+ path: string;
1054
+ field: string;
1055
+ from: unknown;
1056
+ to: unknown;
1057
+ };
1058
+ /** A single V0 version bump within a diff. */
1059
+ type GraphVersionChange = {
1060
+ path: string;
1061
+ id: string;
1062
+ from: number;
1063
+ to: number;
1064
+ };
1065
+ /** Audit record returned by {@link Graph.remove}. */
1066
+ type GraphRemoveAudit = {
1067
+ /** Whether the removed entry was a local node or a mount. */
1068
+ kind: "node" | "mount";
1069
+ /**
1070
+ * Primary nodes torn down by this `remove()`. For `kind: "node"` contains
1071
+ * just the removed name; for `kind: "mount"` lists every primary node in
1072
+ * the unmounted subtree (qualified paths relative to the mount point,
1073
+ * sorted).
1074
+ */
1075
+ nodes: string[];
1076
+ /**
1077
+ * Mounted subgraphs that were unmounted. For `kind: "node"` this is empty;
1078
+ * for `kind: "mount"` starts with the top-level mount name and lists its
1079
+ * descendants in depth-first order.
1080
+ */
1081
+ mounts: string[];
1082
+ };
1083
+ /** Direction for {@link reachable} graph traversal. */
1084
+ type ReachableDirection = "upstream" | "downstream";
1085
+ /** Options for {@link reachable}. */
1086
+ type ReachableOptions = {
1087
+ /** Maximum hop depth from `from` (0 returns `[]`). Omit for unbounded traversal. */
1088
+ maxDepth?: number;
1089
+ /**
1090
+ * Traverse both directions in one pass (union of upstream + downstream).
1091
+ * Ignores the `direction` arg when set.
1092
+ */
1093
+ both?: boolean;
1094
+ /**
1095
+ * Return the richer {@link ReachableResult} shape (paths + per-path
1096
+ * hop depth + truncation flag) instead of the flat sorted string array.
1097
+ */
1098
+ withDetail?: boolean;
1099
+ };
1100
+ /** Rich reachable result (opt-in via `{withDetail: true}`). */
1101
+ type ReachableResult = {
1102
+ /** Reachable paths, sorted lexicographically. */
1103
+ paths: string[];
1104
+ /** Hop depth from `from` to each reachable path. */
1105
+ depths: Map<string, number>;
1106
+ /** True when traversal hit `maxDepth` and some neighbors were not explored. */
1107
+ truncated: boolean;
1108
+ };
1109
+ /**
1110
+ * Reachability query over a {@link Graph.describe} snapshot.
1111
+ *
1112
+ * Traversal follows `deps` (upstream) and reverse-`deps` (downstream). Edges
1113
+ * are derived from deps post Unit 7, so `edges[]` in the snapshot is
1114
+ * redundant with deps — it's walked defensively in case a caller supplied a
1115
+ * pre-Unit-7 snapshot.
1116
+ *
1117
+ * @param described - `graph.describe()` output to traverse.
1118
+ * @param from - Start path (qualified node path).
1119
+ * @param direction - Traversal direction (ignored when `opts.both` is `true`).
1120
+ * @param options - Optional `maxDepth`, `both`, `withDetail`.
1121
+ * @returns Sorted paths (flat) — or {@link ReachableResult} when `withDetail: true`.
1122
+ */
1123
+ declare function reachable(described: GraphDescribeOutput, from: string, direction: ReachableDirection, options?: ReachableOptions & {
1124
+ withDetail: true;
1125
+ }): ReachableResult;
1126
+ declare function reachable(described: GraphDescribeOutput, from: string, direction: ReachableDirection, options?: ReachableOptions): string[];
1127
+
1128
+ export { diffForWAL as A, graphProfile as B, reachable as C, type DescribeFilter as D, Graph as G, type NodeProfile as N, type ObserveDetail as O, type ReachableDirection as R, type TraceEntry as T, type GraphOptions as a, type GraphAttachStorageOptions as b, type GraphProfileResult as c, type GraphProfileOptions as d, GRAPH_META_SEGMENT as e, type GraphActorOptions as f, type GraphCheckpointRecord as g, type GraphDescribeOptions as h, type GraphDescribeOutput as i, type GraphDiagramDirection as j, type GraphDiagramOptions as k, type GraphDiffChange as l, type GraphDiffResult as m, type GraphFactoryContext as n, type GraphNodeFactory as o, type GraphObserveAll as p, type GraphObserveOne as q, type GraphPersistSnapshot as r, type GraphVersionChange as s, type GraphWALDiff as t, type ObserveEvent as u, type ObserveOptions as v, type ObserveResult as w, type ObserveTheme as x, type ObserveThemeName as y, type ReachableOptions as z };