@graphrefly/graphrefly 0.25.0 → 0.27.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 (231) hide show
  1. package/README.md +8 -0
  2. package/dist/ai-CaR_912Q.d.cts +1033 -0
  3. package/dist/ai-WlRltJV7.d.ts +1033 -0
  4. package/dist/audit-ClmqGOCx.d.cts +245 -0
  5. package/dist/audit-DRlSzBu9.d.ts +245 -0
  6. package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
  7. package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
  8. package/dist/chunk-APFNLIRG.js +62 -0
  9. package/dist/chunk-APFNLIRG.js.map +1 -0
  10. package/dist/chunk-AT5LKYNL.js +395 -0
  11. package/dist/chunk-AT5LKYNL.js.map +1 -0
  12. package/dist/{chunk-IAHGTNOZ.js → chunk-BQ6RQQFF.js} +351 -2095
  13. package/dist/chunk-BQ6RQQFF.js.map +1 -0
  14. package/dist/{chunk-L2GLW2U7.js → chunk-BVZYTZ5H.js} +9 -103
  15. package/dist/chunk-BVZYTZ5H.js.map +1 -0
  16. package/dist/{chunk-EVR6UFUV.js → chunk-DST5DKZS.js} +19 -15
  17. package/dist/{chunk-EVR6UFUV.js.map → chunk-DST5DKZS.js.map} +1 -1
  18. package/dist/{chunk-TKE3JGOH.js → chunk-GTE6PWRZ.js} +5 -692
  19. package/dist/chunk-GTE6PWRZ.js.map +1 -0
  20. package/dist/chunk-HXZEYDUR.js +94 -0
  21. package/dist/chunk-HXZEYDUR.js.map +1 -0
  22. package/dist/chunk-J22W6HV3.js +107 -0
  23. package/dist/chunk-J22W6HV3.js.map +1 -0
  24. package/dist/{chunk-PY4XCDLR.js → chunk-J2VBW3DZ.js} +6 -95
  25. package/dist/chunk-J2VBW3DZ.js.map +1 -0
  26. package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
  27. package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
  28. package/dist/chunk-JWBCY4NC.js +330 -0
  29. package/dist/chunk-JWBCY4NC.js.map +1 -0
  30. package/dist/chunk-K2AUJHVP.js +2251 -0
  31. package/dist/chunk-K2AUJHVP.js.map +1 -0
  32. package/dist/chunk-MJ2NKQQL.js +119 -0
  33. package/dist/chunk-MJ2NKQQL.js.map +1 -0
  34. package/dist/chunk-N6UR7YVY.js +198 -0
  35. package/dist/chunk-N6UR7YVY.js.map +1 -0
  36. package/dist/chunk-NC6S43JJ.js +456 -0
  37. package/dist/chunk-NC6S43JJ.js.map +1 -0
  38. package/dist/chunk-OFVJBJXR.js +98 -0
  39. package/dist/chunk-OFVJBJXR.js.map +1 -0
  40. package/dist/chunk-OHISZPOJ.js +97 -0
  41. package/dist/chunk-OHISZPOJ.js.map +1 -0
  42. package/dist/chunk-OU5CQKNW.js +102 -0
  43. package/dist/chunk-OU5CQKNW.js.map +1 -0
  44. package/dist/{chunk-XOFWRC73.js → chunk-PF7GRZMW.js} +316 -21
  45. package/dist/chunk-PF7GRZMW.js.map +1 -0
  46. package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
  47. package/dist/chunk-PHOUUNK7.js.map +1 -0
  48. package/dist/chunk-RNHBMHKA.js +1665 -0
  49. package/dist/chunk-RNHBMHKA.js.map +1 -0
  50. package/dist/chunk-SX52TAR4.js +110 -0
  51. package/dist/chunk-SX52TAR4.js.map +1 -0
  52. package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
  53. package/dist/chunk-WBZOVTYK.js +171 -0
  54. package/dist/chunk-WBZOVTYK.js.map +1 -0
  55. package/dist/chunk-WKNUIZOY.js +354 -0
  56. package/dist/chunk-WKNUIZOY.js.map +1 -0
  57. package/dist/chunk-X3VMZYBT.js +713 -0
  58. package/dist/chunk-X3VMZYBT.js.map +1 -0
  59. package/dist/chunk-X5R3GL6H.js +525 -0
  60. package/dist/chunk-X5R3GL6H.js.map +1 -0
  61. package/dist/chunk-XGPU467M.js +136 -0
  62. package/dist/chunk-XGPU467M.js.map +1 -0
  63. package/dist/compat/index.cjs +7656 -0
  64. package/dist/compat/index.cjs.map +1 -0
  65. package/dist/compat/index.d.cts +18 -0
  66. package/dist/compat/index.d.ts +18 -0
  67. package/dist/compat/index.js +50 -0
  68. package/dist/compat/index.js.map +1 -0
  69. package/dist/compat/jotai/index.cjs +2048 -0
  70. package/dist/compat/jotai/index.cjs.map +1 -0
  71. package/dist/compat/jotai/index.d.cts +2 -0
  72. package/dist/compat/jotai/index.d.ts +2 -0
  73. package/dist/compat/jotai/index.js +9 -0
  74. package/dist/compat/jotai/index.js.map +1 -0
  75. package/dist/compat/nanostores/index.cjs +2175 -0
  76. package/dist/compat/nanostores/index.cjs.map +1 -0
  77. package/dist/compat/nanostores/index.d.cts +2 -0
  78. package/dist/compat/nanostores/index.d.ts +2 -0
  79. package/dist/compat/nanostores/index.js +23 -0
  80. package/dist/compat/nanostores/index.js.map +1 -0
  81. package/dist/compat/nestjs/index.cjs +350 -16
  82. package/dist/compat/nestjs/index.cjs.map +1 -1
  83. package/dist/compat/nestjs/index.d.cts +6 -6
  84. package/dist/compat/nestjs/index.d.ts +6 -6
  85. package/dist/compat/nestjs/index.js +11 -9
  86. package/dist/compat/react/index.cjs +141 -0
  87. package/dist/compat/react/index.cjs.map +1 -0
  88. package/dist/compat/react/index.d.cts +2 -0
  89. package/dist/compat/react/index.d.ts +2 -0
  90. package/dist/compat/react/index.js +12 -0
  91. package/dist/compat/react/index.js.map +1 -0
  92. package/dist/compat/solid/index.cjs +128 -0
  93. package/dist/compat/solid/index.cjs.map +1 -0
  94. package/dist/compat/solid/index.d.cts +2 -0
  95. package/dist/compat/solid/index.d.ts +2 -0
  96. package/dist/compat/solid/index.js +12 -0
  97. package/dist/compat/solid/index.js.map +1 -0
  98. package/dist/compat/svelte/index.cjs +131 -0
  99. package/dist/compat/svelte/index.cjs.map +1 -0
  100. package/dist/compat/svelte/index.d.cts +2 -0
  101. package/dist/compat/svelte/index.d.ts +2 -0
  102. package/dist/compat/svelte/index.js +12 -0
  103. package/dist/compat/svelte/index.js.map +1 -0
  104. package/dist/compat/vue/index.cjs +146 -0
  105. package/dist/compat/vue/index.cjs.map +1 -0
  106. package/dist/compat/vue/index.d.cts +3 -0
  107. package/dist/compat/vue/index.d.ts +3 -0
  108. package/dist/compat/vue/index.js +12 -0
  109. package/dist/compat/vue/index.js.map +1 -0
  110. package/dist/compat/zustand/index.cjs +4931 -0
  111. package/dist/compat/zustand/index.cjs.map +1 -0
  112. package/dist/compat/zustand/index.d.cts +5 -0
  113. package/dist/compat/zustand/index.d.ts +5 -0
  114. package/dist/compat/zustand/index.js +12 -0
  115. package/dist/compat/zustand/index.js.map +1 -0
  116. package/dist/composite-C7PcQvcs.d.cts +303 -0
  117. package/dist/composite-aUCvjZVR.d.ts +303 -0
  118. package/dist/core/index.cjs +53 -4
  119. package/dist/core/index.cjs.map +1 -1
  120. package/dist/core/index.d.cts +4 -3
  121. package/dist/core/index.d.ts +4 -3
  122. package/dist/core/index.js +26 -24
  123. package/dist/demo-shell-BDkOptd6.d.ts +102 -0
  124. package/dist/demo-shell-Crid1WdR.d.cts +102 -0
  125. package/dist/extra/index.cjs +222 -110
  126. package/dist/extra/index.cjs.map +1 -1
  127. package/dist/extra/index.d.cts +6 -4
  128. package/dist/extra/index.d.ts +6 -4
  129. package/dist/extra/index.js +72 -65
  130. package/dist/extra/sources.cjs +2486 -0
  131. package/dist/extra/sources.cjs.map +1 -0
  132. package/dist/extra/sources.d.cts +465 -0
  133. package/dist/extra/sources.d.ts +465 -0
  134. package/dist/extra/sources.js +57 -0
  135. package/dist/extra/sources.js.map +1 -0
  136. package/dist/graph/index.cjs +408 -14
  137. package/dist/graph/index.cjs.map +1 -1
  138. package/dist/graph/index.d.cts +5 -5
  139. package/dist/graph/index.d.ts +5 -5
  140. package/dist/graph/index.js +13 -5
  141. package/dist/{graph-D-3JIQme.d.cts → graph-CCwGKLCm.d.ts} +195 -4
  142. package/dist/{graph-B6NFqv3z.d.ts → graph-DNCrvZSn.d.cts} +195 -4
  143. package/dist/index-3lsddbbS.d.ts +86 -0
  144. package/dist/index-B1tloyhO.d.cts +34 -0
  145. package/dist/{index-CYkjxu3s.d.ts → index-B6D3QNSA.d.ts} +33 -4
  146. package/dist/index-B6EhDnjH.d.cts +37 -0
  147. package/dist/index-B9B7_HEY.d.ts +37 -0
  148. package/dist/{index-Ds23Wvou.d.ts → index-BHlKbUwO.d.cts} +131 -883
  149. package/dist/{index-DiobMNwE.d.ts → index-BPVt8kqc.d.ts} +3 -3
  150. package/dist/index-BaSM3aYt.d.ts +195 -0
  151. package/dist/index-BuEoe-Qu.d.ts +121 -0
  152. package/dist/{index-Ch0IpIO0.d.cts → index-BwfLUNw4.d.ts} +131 -883
  153. package/dist/index-ByQxazQJ.d.cts +86 -0
  154. package/dist/index-C0svESO4.d.ts +127 -0
  155. package/dist/{index-OXImXMq6.d.ts → index-C8oil6M6.d.ts} +18 -196
  156. package/dist/{index-DKE1EATr.d.cts → index-CI3DprxP.d.cts} +18 -196
  157. package/dist/{index-AMWewNDe.d.cts → index-CO8uBlUh.d.cts} +33 -4
  158. package/dist/index-CxFrXH4m.d.ts +45 -0
  159. package/dist/index-D8wS_PeY.d.cts +121 -0
  160. package/dist/index-DO_6JN9Z.d.cts +127 -0
  161. package/dist/index-DVGiGFGT.d.cts +195 -0
  162. package/dist/index-DYme44FM.d.cts +44 -0
  163. package/dist/{index-J7Kc0oIQ.d.cts → index-DlLp-2Xn.d.cts} +3 -3
  164. package/dist/index-Dzk2hrlR.d.ts +44 -0
  165. package/dist/index-VHqptjhu.d.cts +45 -0
  166. package/dist/index-VdHQMPy1.d.ts +36 -0
  167. package/dist/index-Xi3u0HCQ.d.cts +36 -0
  168. package/dist/index-wEn0eFe8.d.ts +34 -0
  169. package/dist/index.cjs +1780 -176
  170. package/dist/index.cjs.map +1 -1
  171. package/dist/index.d.cts +784 -2082
  172. package/dist/index.d.ts +784 -2082
  173. package/dist/index.js +955 -4349
  174. package/dist/index.js.map +1 -1
  175. package/dist/memory-C6Z2tGpC.d.cts +139 -0
  176. package/dist/memory-li6FL5RM.d.ts +139 -0
  177. package/dist/messaging-Gt4LPbyA.d.cts +269 -0
  178. package/dist/messaging-XDoYablx.d.ts +269 -0
  179. package/dist/{meta-DWbkoq1s.d.cts → meta-BxCA7rcr.d.cts} +1 -1
  180. package/dist/{meta-CnkLA_43.d.ts → meta-CbznRPYJ.d.ts} +1 -1
  181. package/dist/{node-B-f-Lu-k.d.cts → node-BmerH3kS.d.cts} +26 -1
  182. package/dist/{node-B-f-Lu-k.d.ts → node-BmerH3kS.d.ts} +26 -1
  183. package/dist/{observable-uP-wy_uK.d.ts → observable-BgGUwcqp.d.ts} +1 -1
  184. package/dist/{observable-DBnrwcar.d.cts → observable-DJt_AxzQ.d.cts} +1 -1
  185. package/dist/patterns/ai.cjs +7930 -0
  186. package/dist/patterns/ai.cjs.map +1 -0
  187. package/dist/patterns/ai.d.cts +10 -0
  188. package/dist/patterns/ai.d.ts +10 -0
  189. package/dist/patterns/ai.js +71 -0
  190. package/dist/patterns/ai.js.map +1 -0
  191. package/dist/patterns/audit.cjs +5805 -0
  192. package/dist/patterns/audit.cjs.map +1 -0
  193. package/dist/patterns/audit.d.cts +6 -0
  194. package/dist/patterns/audit.d.ts +6 -0
  195. package/dist/patterns/audit.js +29 -0
  196. package/dist/patterns/audit.js.map +1 -0
  197. package/dist/patterns/demo-shell.cjs +5604 -0
  198. package/dist/patterns/demo-shell.cjs.map +1 -0
  199. package/dist/patterns/demo-shell.d.cts +6 -0
  200. package/dist/patterns/demo-shell.d.ts +6 -0
  201. package/dist/patterns/demo-shell.js +15 -0
  202. package/dist/patterns/demo-shell.js.map +1 -0
  203. package/dist/patterns/memory.cjs +5283 -0
  204. package/dist/patterns/memory.cjs.map +1 -0
  205. package/dist/patterns/memory.d.cts +5 -0
  206. package/dist/patterns/memory.d.ts +5 -0
  207. package/dist/patterns/memory.js +20 -0
  208. package/dist/patterns/memory.js.map +1 -0
  209. package/dist/patterns/reactive-layout/index.cjs +355 -13
  210. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  211. package/dist/patterns/reactive-layout/index.d.cts +6 -5
  212. package/dist/patterns/reactive-layout/index.d.ts +6 -5
  213. package/dist/patterns/reactive-layout/index.js +15 -12
  214. package/dist/reactive-layout-MQP--J3F.d.cts +183 -0
  215. package/dist/reactive-layout-u5Ulnqag.d.ts +183 -0
  216. package/dist/{storage-BuTdpCI1.d.cts → storage-CMjUUuxn.d.ts} +10 -2
  217. package/dist/{storage-F2X1U1x0.d.ts → storage-DdWlZo6U.d.cts} +10 -2
  218. package/dist/sugar-CCOxXK1e.d.ts +201 -0
  219. package/dist/sugar-D02n5JjF.d.cts +201 -0
  220. package/package.json +63 -3
  221. package/dist/chunk-5DJTTKX3.js.map +0 -1
  222. package/dist/chunk-IAHGTNOZ.js.map +0 -1
  223. package/dist/chunk-L2GLW2U7.js.map +0 -1
  224. package/dist/chunk-MW4VAKAO.js +0 -47
  225. package/dist/chunk-MW4VAKAO.js.map +0 -1
  226. package/dist/chunk-PY4XCDLR.js.map +0 -1
  227. package/dist/chunk-TKE3JGOH.js.map +0 -1
  228. package/dist/chunk-XOFWRC73.js.map +0 -1
  229. package/dist/index-BJB7t9gg.d.cts +0 -392
  230. package/dist/index-C-TXEa7C.d.ts +0 -392
  231. /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
@@ -1,31 +1,229 @@
1
1
  import {
2
2
  describeNode,
3
3
  resolveDescribeFields
4
- } from "./chunk-H4RVA4VE.js";
4
+ } from "./chunk-VYPWMZ6H.js";
5
5
  import {
6
6
  ResettableTimer,
7
7
  RingBuffer
8
8
  } from "./chunk-7TAQJHQV.js";
9
9
  import {
10
- COMPLETE,
11
- DATA,
12
- DIRTY,
13
- ERROR,
14
10
  GuardDenied,
15
- INVALIDATE,
16
11
  NodeImpl,
17
- PAUSE,
18
- RESOLVED,
19
- RESUME,
20
- TEARDOWN,
21
12
  batch,
22
13
  decodeEnvelope,
23
14
  defaultConfig,
24
15
  encodeEnvelope,
25
16
  isBatching,
26
17
  monotonicNs,
27
- state
28
- } from "./chunk-5DJTTKX3.js";
18
+ producer,
19
+ state,
20
+ wallClockNs
21
+ } from "./chunk-PHOUUNK7.js";
22
+ import {
23
+ COMPLETE,
24
+ DATA,
25
+ DIRTY,
26
+ ERROR,
27
+ INVALIDATE,
28
+ PAUSE,
29
+ RESOLVED,
30
+ RESUME,
31
+ TEARDOWN
32
+ } from "./chunk-SX52TAR4.js";
33
+
34
+ // src/graph/explain.ts
35
+ function explainPath(described, from, to, opts = {}) {
36
+ const fromExists = from in described.nodes;
37
+ const toExists = to in described.nodes;
38
+ if (!fromExists) return makeFailure(from, to, "no-such-from");
39
+ if (!toExists) return makeFailure(from, to, "no-such-to");
40
+ const maxDepth = opts.maxDepth;
41
+ if (maxDepth != null && (!Number.isInteger(maxDepth) || maxDepth < 0)) {
42
+ throw new Error(`explainPath: maxDepth must be an integer >= 0`);
43
+ }
44
+ if (from === to) {
45
+ if (opts.findCycle === true) {
46
+ const cycle = findShortestCycle(described, from, opts);
47
+ if (cycle != null) return cycle;
48
+ }
49
+ const step = buildStep(from, described.nodes[from], 0, opts);
50
+ return makeSuccess(from, to, [step]);
51
+ }
52
+ if (maxDepth === 0) return makeFailure(from, to, "no-path");
53
+ const result = bfsShortestPath(described, from, to, maxDepth);
54
+ if (!result.found) {
55
+ return makeFailure(from, to, result.truncated ? "max-depth-exceeded" : "no-path");
56
+ }
57
+ return makeSuccess(from, to, materializeSteps(described, result.pathOrder, opts));
58
+ }
59
+ function bfsShortestPath(described, from, to, maxDepth) {
60
+ const pred = /* @__PURE__ */ new Map();
61
+ const queue = [{ path: to, depth: 0 }];
62
+ const visited = /* @__PURE__ */ new Set([to]);
63
+ let head = 0;
64
+ let truncated = false;
65
+ while (head < queue.length) {
66
+ const cur = queue[head++];
67
+ if (cur.path === from) break;
68
+ if (maxDepth != null && cur.depth >= maxDepth) {
69
+ const node2 = described.nodes[cur.path];
70
+ if (node2?.deps && node2.deps.length > 0) truncated = true;
71
+ continue;
72
+ }
73
+ const node = described.nodes[cur.path];
74
+ if (node == null) continue;
75
+ const deps = node.deps ?? [];
76
+ const slots = /* @__PURE__ */ new Map();
77
+ for (let i = 0; i < deps.length; i++) {
78
+ const dep = deps[i];
79
+ if (!dep) continue;
80
+ let arr = slots.get(dep);
81
+ if (arr == null) {
82
+ arr = [];
83
+ slots.set(dep, arr);
84
+ }
85
+ arr.push(i);
86
+ }
87
+ for (const [dep, indices] of slots) {
88
+ if (visited.has(dep)) continue;
89
+ visited.add(dep);
90
+ pred.set(dep, { from: cur.path, depIndices: indices });
91
+ queue.push({ path: dep, depth: cur.depth + 1 });
92
+ }
93
+ }
94
+ if (!pred.has(from)) {
95
+ return { found: false, pathOrder: [], truncated };
96
+ }
97
+ const pathOrder = [{ path: from }];
98
+ let cursor = from;
99
+ while (cursor !== to) {
100
+ const p = pred.get(cursor);
101
+ if (p == null) return { found: false, pathOrder: [], truncated: false };
102
+ pathOrder[pathOrder.length - 1].depIndices = p.depIndices;
103
+ pathOrder.push({ path: p.from });
104
+ cursor = p.from;
105
+ }
106
+ return { found: true, pathOrder, truncated: false };
107
+ }
108
+ function findShortestCycle(described, start, opts) {
109
+ const startNode = described.nodes[start];
110
+ if (startNode == null) return null;
111
+ const startDeps = startNode.deps ?? [];
112
+ const selfSlots = [];
113
+ for (let i = 0; i < startDeps.length; i++) if (startDeps[i] === start) selfSlots.push(i);
114
+ if (selfSlots.length > 0) {
115
+ const step0 = buildStep(start, startNode, 0, opts);
116
+ step0.dep_index = selfSlots[0];
117
+ const step1 = buildStep(start, startNode, 1, opts);
118
+ return makeSuccess(start, start, [step0, step1]);
119
+ }
120
+ let best = null;
121
+ for (let i = 0; i < startDeps.length; i++) {
122
+ const dep = startDeps[i];
123
+ if (!dep || dep === start) continue;
124
+ const sub = bfsShortestPath(described, dep, start, opts.maxDepth);
125
+ if (!sub.found) continue;
126
+ if (best == null || sub.pathOrder.length < best.pathOrder.length) {
127
+ best = sub;
128
+ best = {
129
+ found: true,
130
+ pathOrder: [{ path: start, depIndices: [i] }, ...sub.pathOrder],
131
+ truncated: false
132
+ };
133
+ }
134
+ }
135
+ if (best == null) return null;
136
+ return makeSuccess(start, start, materializeSteps(described, best.pathOrder, opts));
137
+ }
138
+ function materializeSteps(described, pathOrder, opts) {
139
+ return pathOrder.map((entry, i) => {
140
+ const node = described.nodes[entry.path];
141
+ const step = buildStep(entry.path, node, i, opts);
142
+ if (entry.depIndices != null && entry.depIndices.length > 0) {
143
+ step.dep_index = entry.depIndices[0];
144
+ if (entry.depIndices.length > 1) step.dep_indices = [...entry.depIndices];
145
+ }
146
+ return step;
147
+ });
148
+ }
149
+ function buildStep(path, node, hop, opts) {
150
+ const step = {
151
+ path,
152
+ type: node.type,
153
+ hop
154
+ };
155
+ if (node.status !== void 0) step.status = node.status;
156
+ if ("value" in node) step.value = node.value;
157
+ if (node.v != null) step.v = node.v;
158
+ const annotation = opts.annotations?.get(path) ?? node.reason;
159
+ if (annotation != null) step.reason = annotation;
160
+ const lastMutation = opts.lastMutations?.get(path) ?? node.lastMutation;
161
+ if (lastMutation != null) step.lastMutation = lastMutation;
162
+ return step;
163
+ }
164
+ function makeSuccess(from, to, steps) {
165
+ return finalize(from, to, true, "ok", steps);
166
+ }
167
+ function makeFailure(from, to, reason) {
168
+ return finalize(from, to, false, reason, []);
169
+ }
170
+ function finalize(from, to, found, reason, steps) {
171
+ const text = renderChain(from, to, found, reason, steps);
172
+ return {
173
+ from,
174
+ to,
175
+ found,
176
+ reason,
177
+ steps,
178
+ text,
179
+ toJSON() {
180
+ return { from, to, found, reason, steps };
181
+ }
182
+ };
183
+ }
184
+ function renderChain(from, to, found, reason, steps) {
185
+ if (!found) {
186
+ switch (reason) {
187
+ case "no-such-from":
188
+ return `explainPath: no node named "${from}"`;
189
+ case "no-such-to":
190
+ return `explainPath: no node named "${to}"`;
191
+ case "max-depth-exceeded":
192
+ return `explainPath: no path from "${from}" to "${to}" within maxDepth`;
193
+ default:
194
+ return `explainPath: no path from "${from}" to "${to}"`;
195
+ }
196
+ }
197
+ const lines = [`Causal path: ${from} \u2192 ${to} (${steps.length} step(s))`];
198
+ for (const step of steps) {
199
+ const arrow = step.hop === 0 ? "\xB7" : "\u2193";
200
+ const head = ` ${arrow} ${step.path} (${step.type}${step.status ? `/${step.status}` : ""})`;
201
+ lines.push(head);
202
+ if ("value" in step) {
203
+ lines.push(` value: ${formatValue(step.value)}`);
204
+ }
205
+ if (step.reason != null) {
206
+ lines.push(` reason: ${step.reason}`);
207
+ }
208
+ if (step.lastMutation != null) {
209
+ const a = step.lastMutation.actor;
210
+ lines.push(` actor: ${a.type}${a.id ? `:${a.id}` : ""}`);
211
+ }
212
+ }
213
+ return lines.join("\n");
214
+ }
215
+ function formatValue(v) {
216
+ if (v === void 0) return "<sentinel>";
217
+ if (v === null) return "null";
218
+ if (typeof v === "string") return JSON.stringify(v);
219
+ if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
220
+ try {
221
+ const s = JSON.stringify(v);
222
+ return s.length > 80 ? `${s.slice(0, 77)}...` : s;
223
+ } catch {
224
+ return String(v);
225
+ }
226
+ }
29
227
 
30
228
  // src/extra/utils/sizeof.ts
31
229
  var OVERHEAD = {
@@ -660,6 +858,20 @@ var Graph = class _Graph {
660
858
  _parent = void 0;
661
859
  _storageDisposers = /* @__PURE__ */ new Set();
662
860
  _disposers = /* @__PURE__ */ new Set();
861
+ /**
862
+ * @internal Lazy `TopologyEvent` producer. Created on first `.topology`
863
+ * access. Zero cost until something subscribes — producer fn only runs when
864
+ * the first sink attaches, registering one handler into
865
+ * {@link Graph._topologyEmitters}.
866
+ */
867
+ _topology;
868
+ /**
869
+ * @internal Active emit handlers for the topology producer. Each entry is
870
+ * the closure registered by the producer fn on activation; cleared on
871
+ * deactivation. `_emitTopology` broadcasts through every entry (there is at
872
+ * most one per activation cycle of the producer).
873
+ */
874
+ _topologyEmitters = /* @__PURE__ */ new Set();
663
875
  /**
664
876
  * @param name - Non-empty graph id (must not contain `::` and must not
665
877
  * equal the reserved meta segment `__meta__`).
@@ -699,6 +911,55 @@ var Graph = class _Graph {
699
911
  return out;
700
912
  }
701
913
  // ——————————————————————————————————————————————————————————————
914
+ // Topology companion (structural-change event stream)
915
+ // ——————————————————————————————————————————————————————————————
916
+ /**
917
+ * Reactive stream of structural changes to this graph's own registry
918
+ * (add / mount / remove). Value mutations live on `observe()`; this
919
+ * companion only fires when the topology shape changes.
920
+ *
921
+ * Lazy: the underlying node is created on first access and activates when
922
+ * something subscribes. No emission replay — late subscribers do not
923
+ * receive historical events and should snapshot via {@link Graph.describe}
924
+ * before listening for incremental changes. Events that fire while the
925
+ * producer has zero subscribers are dropped (no retention).
926
+ *
927
+ * Own-graph only: a parent's `topology` does NOT emit for structural
928
+ * changes inside a mounted child. Transitive consumers subscribe to each
929
+ * child's topology separately (recurse through `topology`'s own "added"
930
+ * events with `nodeKind: "mount"` to discover new children).
931
+ *
932
+ * See {@link TopologyEvent} for payload shape.
933
+ *
934
+ * @category observability
935
+ */
936
+ get topology() {
937
+ if (this._topology == null) {
938
+ this._topology = producer(
939
+ (actions) => {
940
+ const handler = (event) => {
941
+ actions.emit(event);
942
+ };
943
+ this._topologyEmitters.add(handler);
944
+ return () => {
945
+ this._topologyEmitters.delete(handler);
946
+ };
947
+ },
948
+ { name: `${this.name}_topology` }
949
+ );
950
+ }
951
+ return this._topology;
952
+ }
953
+ /**
954
+ * @internal Fire a {@link TopologyEvent} to every active subscriber of
955
+ * `this.topology`. No-op when the topology node has never been accessed or
956
+ * currently has no sinks — zero cost for graphs nobody observes.
957
+ */
958
+ _emitTopology(event) {
959
+ if (this._topology == null || this._topologyEmitters.size === 0) return;
960
+ for (const h of this._topologyEmitters) h(event);
961
+ }
962
+ // ——————————————————————————————————————————————————————————————
702
963
  // Node registry
703
964
  // ——————————————————————————————————————————————————————————————
704
965
  /**
@@ -728,6 +989,7 @@ var Graph = class _Graph {
728
989
  }
729
990
  this._nodes.set(name, node);
730
991
  this._nodeToName.set(node, name);
992
+ this._emitTopology({ kind: "added", name, nodeKind: "node" });
731
993
  return node;
732
994
  }
733
995
  /**
@@ -768,22 +1030,23 @@ var Graph = class _Graph {
768
1030
  assertRegisterableName(name, this.name, "remove");
769
1031
  const child = this._mounts.get(name);
770
1032
  if (child) {
771
- const audit = { kind: "mount", nodes: [], mounts: [] };
1033
+ const audit2 = { kind: "mount", nodes: [], mounts: [] };
772
1034
  const targets = [];
773
1035
  child._collectObserveTargets("", targets);
774
1036
  for (const [p, n] of targets) {
775
1037
  if (!p.includes(`${PATH_SEP}${GRAPH_META_SEGMENT}${PATH_SEP}`)) {
776
- audit.nodes.push(p);
1038
+ audit2.nodes.push(p);
777
1039
  }
778
1040
  void n;
779
1041
  }
780
- audit.nodes.sort();
781
- audit.mounts.push(name);
782
- audit.mounts.push(...child._collectSubgraphs(`${name}${PATH_SEP}`));
1042
+ audit2.nodes.sort();
1043
+ audit2.mounts.push(name);
1044
+ audit2.mounts.push(...child._collectSubgraphs(`${name}${PATH_SEP}`));
783
1045
  this._mounts.delete(name);
784
1046
  child._parent = void 0;
785
1047
  teardownMountedGraph(child);
786
- return audit;
1048
+ this._emitTopology({ kind: "removed", name, nodeKind: "mount", audit: audit2 });
1049
+ return audit2;
787
1050
  }
788
1051
  const node = this._nodes.get(name);
789
1052
  if (!node) {
@@ -792,7 +1055,9 @@ var Graph = class _Graph {
792
1055
  this._nodes.delete(name);
793
1056
  this._nodeToName.delete(node);
794
1057
  node.down([[TEARDOWN]], { internal: true });
795
- return { kind: "node", nodes: [name], mounts: [] };
1058
+ const audit = { kind: "node", nodes: [name], mounts: [] };
1059
+ this._emitTopology({ kind: "removed", name, nodeKind: "node", audit });
1060
+ return audit;
796
1061
  }
797
1062
  /**
798
1063
  * Bulk remove — invokes {@link Graph.remove} for every local name matching
@@ -1021,6 +1286,7 @@ var Graph = class _Graph {
1021
1286
  }
1022
1287
  this._mounts.set(name, child);
1023
1288
  child._parent = this;
1289
+ this._emitTopology({ kind: "added", name, nodeKind: "mount" });
1024
1290
  return child;
1025
1291
  }
1026
1292
  /**
@@ -1311,6 +1577,33 @@ var Graph = class _Graph {
1311
1577
  }
1312
1578
  return reachable(this.describe(), from, direction, opts);
1313
1579
  }
1580
+ /**
1581
+ * Causal walkback: shortest dep-chain from `from` to `to`, enriched with
1582
+ * each node's value, status, last-mutation actor, and reasoning annotation
1583
+ * from {@link Graph.trace}. Wraps {@link explainPath} (roadmap §9.2).
1584
+ *
1585
+ * @param from - Upstream node (the cause).
1586
+ * @param to - Downstream node (the effect).
1587
+ * @param opts - Optional `maxDepth` and `findCycle`. When `findCycle:true`
1588
+ * and `from === to`, returns the shortest cycle through other nodes
1589
+ * (useful for diagnosing feedback loops, COMPOSITION-GUIDE §7).
1590
+ * Annotations and lastMutations are collected automatically from the
1591
+ * live graph.
1592
+ */
1593
+ explain(from, to, opts) {
1594
+ const described = this.describe({ detail: "full" });
1595
+ const annotations = new Map(this._annotations);
1596
+ const lastMutations = /* @__PURE__ */ new Map();
1597
+ for (const [path, n] of Object.entries(described.nodes)) {
1598
+ if (n.lastMutation != null) lastMutations.set(path, n.lastMutation);
1599
+ }
1600
+ return explainPath(described, from, to, {
1601
+ ...opts?.maxDepth != null ? { maxDepth: opts.maxDepth } : {},
1602
+ ...opts?.findCycle === true ? { findCycle: true } : {},
1603
+ annotations,
1604
+ lastMutations
1605
+ });
1606
+ }
1314
1607
  /**
1315
1608
  * @internal Collect all qualified paths in this graph tree matching a
1316
1609
  * glob pattern. Used by scoped autoCheckpoint subscription.
@@ -1989,7 +2282,7 @@ var Graph = class _Graph {
1989
2282
  return;
1990
2283
  }
1991
2284
  const nextSeq = s.seq + 1;
1992
- const timestamp_ns = monotonicNs();
2285
+ const timestamp_ns = wallClockNs();
1993
2286
  const isFirst = s.lastSnapshot == null;
1994
2287
  const shouldCompact = isFirst || nextSeq % s.compactEvery === 0;
1995
2288
  const record = shouldCompact ? {
@@ -2405,13 +2698,15 @@ function reachable(described, from, direction, options = {}) {
2405
2698
  }
2406
2699
 
2407
2700
  export {
2701
+ explainPath,
2408
2702
  OVERHEAD,
2409
2703
  SIZEOF_SYMBOL,
2410
2704
  sizeof,
2411
2705
  graphProfile,
2412
2706
  GRAPH_META_SEGMENT,
2707
+ SNAPSHOT_VERSION,
2413
2708
  Graph,
2414
2709
  diffForWAL,
2415
2710
  reachable
2416
2711
  };
2417
- //# sourceMappingURL=chunk-XOFWRC73.js.map
2712
+ //# sourceMappingURL=chunk-PF7GRZMW.js.map