@graphrefly/ts 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/index.cjs +9015 -0
  3. package/dist/adapters/index.cjs.map +1 -0
  4. package/dist/adapters/index.d.cts +678 -0
  5. package/dist/adapters/index.d.ts +678 -0
  6. package/dist/adapters/index.js +2894 -0
  7. package/dist/adapters/index.js.map +1 -0
  8. package/dist/adapters/observe-storage.cjs +260 -0
  9. package/dist/adapters/observe-storage.cjs.map +1 -0
  10. package/dist/adapters/observe-storage.d.cts +77 -0
  11. package/dist/adapters/observe-storage.d.ts +77 -0
  12. package/dist/adapters/observe-storage.js +161 -0
  13. package/dist/adapters/observe-storage.js.map +1 -0
  14. package/dist/append-log-DisvEReb.d.cts +189 -0
  15. package/dist/append-log-DzKMmjxx.d.ts +189 -0
  16. package/dist/chunk-2ILL7HQI.js +1189 -0
  17. package/dist/chunk-2ILL7HQI.js.map +1 -0
  18. package/dist/chunk-4VLAQHZI.js +330 -0
  19. package/dist/chunk-4VLAQHZI.js.map +1 -0
  20. package/dist/chunk-6PHB5CJS.js +229 -0
  21. package/dist/chunk-6PHB5CJS.js.map +1 -0
  22. package/dist/chunk-COHO25CZ.js +2449 -0
  23. package/dist/chunk-COHO25CZ.js.map +1 -0
  24. package/dist/chunk-D6BG7U6A.js +161 -0
  25. package/dist/chunk-D6BG7U6A.js.map +1 -0
  26. package/dist/chunk-DJC4CHLQ.js +818 -0
  27. package/dist/chunk-DJC4CHLQ.js.map +1 -0
  28. package/dist/chunk-DK554R7P.js +67 -0
  29. package/dist/chunk-DK554R7P.js.map +1 -0
  30. package/dist/chunk-DKP56CSW.js +322 -0
  31. package/dist/chunk-DKP56CSW.js.map +1 -0
  32. package/dist/chunk-G4M3NHRJ.js +688 -0
  33. package/dist/chunk-G4M3NHRJ.js.map +1 -0
  34. package/dist/chunk-GAJW5I5P.js +1 -0
  35. package/dist/chunk-GAJW5I5P.js.map +1 -0
  36. package/dist/chunk-GDL26N2T.js +282 -0
  37. package/dist/chunk-GDL26N2T.js.map +1 -0
  38. package/dist/chunk-GTPCOEOZ.js +741 -0
  39. package/dist/chunk-GTPCOEOZ.js.map +1 -0
  40. package/dist/chunk-H2HTHFVN.js +1 -0
  41. package/dist/chunk-H2HTHFVN.js.map +1 -0
  42. package/dist/chunk-HDRL4VQQ.js +218 -0
  43. package/dist/chunk-HDRL4VQQ.js.map +1 -0
  44. package/dist/chunk-I3IHOHCJ.js +2267 -0
  45. package/dist/chunk-I3IHOHCJ.js.map +1 -0
  46. package/dist/chunk-JIMUDQN3.js +965 -0
  47. package/dist/chunk-JIMUDQN3.js.map +1 -0
  48. package/dist/chunk-JR4IKCR2.js +462 -0
  49. package/dist/chunk-JR4IKCR2.js.map +1 -0
  50. package/dist/chunk-K3FXTC3I.js +165 -0
  51. package/dist/chunk-K3FXTC3I.js.map +1 -0
  52. package/dist/chunk-OOEN33FB.js +65 -0
  53. package/dist/chunk-OOEN33FB.js.map +1 -0
  54. package/dist/chunk-PKVBHGBM.js +554 -0
  55. package/dist/chunk-PKVBHGBM.js.map +1 -0
  56. package/dist/chunk-RIIOUTGM.js +1857 -0
  57. package/dist/chunk-RIIOUTGM.js.map +1 -0
  58. package/dist/chunk-SCRFRCGR.js +33 -0
  59. package/dist/chunk-SCRFRCGR.js.map +1 -0
  60. package/dist/chunk-SWTLEQL6.js +53 -0
  61. package/dist/chunk-SWTLEQL6.js.map +1 -0
  62. package/dist/chunk-SZAETNNA.js +1 -0
  63. package/dist/chunk-SZAETNNA.js.map +1 -0
  64. package/dist/chunk-TEW47IVR.js +49 -0
  65. package/dist/chunk-TEW47IVR.js.map +1 -0
  66. package/dist/chunk-Y3ZLRGHC.js +1482 -0
  67. package/dist/chunk-Y3ZLRGHC.js.map +1 -0
  68. package/dist/chunk-Z2ANQ6JW.js +149 -0
  69. package/dist/chunk-Z2ANQ6JW.js.map +1 -0
  70. package/dist/codec-BB7p8fJc.d.cts +38 -0
  71. package/dist/codec-BB7p8fJc.d.ts +38 -0
  72. package/dist/composition/index.cjs +2505 -0
  73. package/dist/composition/index.cjs.map +1 -0
  74. package/dist/composition/index.d.cts +95 -0
  75. package/dist/composition/index.d.ts +95 -0
  76. package/dist/composition/index.js +19 -0
  77. package/dist/composition/index.js.map +1 -0
  78. package/dist/core/index.cjs +2475 -0
  79. package/dist/core/index.cjs.map +1 -0
  80. package/dist/core/index.d.cts +25 -0
  81. package/dist/core/index.d.ts +25 -0
  82. package/dist/core/index.js +74 -0
  83. package/dist/core/index.js.map +1 -0
  84. package/dist/cqrs/index.cjs +595 -0
  85. package/dist/cqrs/index.cjs.map +1 -0
  86. package/dist/cqrs/index.d.cts +200 -0
  87. package/dist/cqrs/index.d.ts +200 -0
  88. package/dist/cqrs/index.js +557 -0
  89. package/dist/cqrs/index.js.map +1 -0
  90. package/dist/data-structures/index.cjs +4277 -0
  91. package/dist/data-structures/index.cjs.map +1 -0
  92. package/dist/data-structures/index.d.cts +22 -0
  93. package/dist/data-structures/index.d.ts +22 -0
  94. package/dist/data-structures/index.js +31 -0
  95. package/dist/data-structures/index.js.map +1 -0
  96. package/dist/describe-BZb7AS2y.d.ts +57 -0
  97. package/dist/describe-Ciu8SUnN.d.cts +57 -0
  98. package/dist/graph/index.cjs +7832 -0
  99. package/dist/graph/index.cjs.map +1 -0
  100. package/dist/graph/index.d.cts +251 -0
  101. package/dist/graph/index.d.ts +251 -0
  102. package/dist/graph/index.js +131 -0
  103. package/dist/graph/index.js.map +1 -0
  104. package/dist/graph-DfdF9zy4.d.ts +666 -0
  105. package/dist/graph-s23RbbFO.d.cts +666 -0
  106. package/dist/index-CAEmLCYF.d.cts +166 -0
  107. package/dist/index-SnzZu3x7.d.ts +166 -0
  108. package/dist/index.cjs +15409 -0
  109. package/dist/index.cjs.map +1 -0
  110. package/dist/index.d.cts +23 -0
  111. package/dist/index.d.ts +23 -0
  112. package/dist/index.js +582 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/messages-BZqrGGm1.d.cts +55 -0
  115. package/dist/messages-BZqrGGm1.d.ts +55 -0
  116. package/dist/messaging/index.cjs +818 -0
  117. package/dist/messaging/index.cjs.map +1 -0
  118. package/dist/messaging/index.d.cts +235 -0
  119. package/dist/messaging/index.d.ts +235 -0
  120. package/dist/messaging/index.js +767 -0
  121. package/dist/messaging/index.js.map +1 -0
  122. package/dist/observe-event-log-0SVsx7JG.d.cts +88 -0
  123. package/dist/observe-event-log-Dnm76owp.d.ts +88 -0
  124. package/dist/operators/index.cjs +3774 -0
  125. package/dist/operators/index.cjs.map +1 -0
  126. package/dist/operators/index.d.cts +308 -0
  127. package/dist/operators/index.d.ts +308 -0
  128. package/dist/operators/index.js +112 -0
  129. package/dist/operators/index.js.map +1 -0
  130. package/dist/orchestration/index.cjs +3541 -0
  131. package/dist/orchestration/index.cjs.map +1 -0
  132. package/dist/orchestration/index.d.cts +302 -0
  133. package/dist/orchestration/index.d.ts +302 -0
  134. package/dist/orchestration/index.js +1004 -0
  135. package/dist/orchestration/index.js.map +1 -0
  136. package/dist/patterns/index.cjs +1045 -0
  137. package/dist/patterns/index.cjs.map +1 -0
  138. package/dist/patterns/index.d.cts +39 -0
  139. package/dist/patterns/index.d.ts +39 -0
  140. package/dist/patterns/index.js +33 -0
  141. package/dist/patterns/index.js.map +1 -0
  142. package/dist/reactive-collection-BxBqtIOE.d.cts +344 -0
  143. package/dist/reactive-collection-Cb1II1Fi.d.ts +344 -0
  144. package/dist/reactive-collection-storage-BNiEc-Gd.d.ts +217 -0
  145. package/dist/reactive-collection-storage-D-KmjE0J.d.cts +217 -0
  146. package/dist/reactive-map-BcB4KsQR.d.ts +256 -0
  147. package/dist/reactive-map-D-g3dv8I.d.cts +256 -0
  148. package/dist/read-through-B1CYPfq_.d.cts +82 -0
  149. package/dist/read-through-DwyJhGs1.d.ts +82 -0
  150. package/dist/render/index.cjs +250 -0
  151. package/dist/render/index.cjs.map +1 -0
  152. package/dist/render/index.d.cts +58 -0
  153. package/dist/render/index.d.ts +58 -0
  154. package/dist/render/index.js +20 -0
  155. package/dist/render/index.js.map +1 -0
  156. package/dist/resilience-Dig3Q7n0.d.cts +45 -0
  157. package/dist/resilience-Dig3Q7n0.d.ts +45 -0
  158. package/dist/semantic-memory-graph-BYoIlP35.d.cts +356 -0
  159. package/dist/semantic-memory-graph-CxyXLms3.d.ts +356 -0
  160. package/dist/solutions/index.cjs +3249 -0
  161. package/dist/solutions/index.cjs.map +1 -0
  162. package/dist/solutions/index.d.cts +520 -0
  163. package/dist/solutions/index.d.ts +520 -0
  164. package/dist/solutions/index.js +31 -0
  165. package/dist/solutions/index.js.map +1 -0
  166. package/dist/sources/browser.cjs +3095 -0
  167. package/dist/sources/browser.cjs.map +1 -0
  168. package/dist/sources/browser.d.cts +39 -0
  169. package/dist/sources/browser.d.ts +39 -0
  170. package/dist/sources/browser.js +137 -0
  171. package/dist/sources/browser.js.map +1 -0
  172. package/dist/sources/index.cjs +3021 -0
  173. package/dist/sources/index.cjs.map +1 -0
  174. package/dist/sources/index.d.cts +7 -0
  175. package/dist/sources/index.d.ts +7 -0
  176. package/dist/sources/index.js +63 -0
  177. package/dist/sources/index.js.map +1 -0
  178. package/dist/sources/node.cjs +675 -0
  179. package/dist/sources/node.cjs.map +1 -0
  180. package/dist/sources/node.d.cts +109 -0
  181. package/dist/sources/node.d.ts +109 -0
  182. package/dist/sources/node.js +639 -0
  183. package/dist/sources/node.js.map +1 -0
  184. package/dist/storage/browser.cjs +777 -0
  185. package/dist/storage/browser.cjs.map +1 -0
  186. package/dist/storage/browser.d.cts +40 -0
  187. package/dist/storage/browser.d.ts +40 -0
  188. package/dist/storage/browser.js +275 -0
  189. package/dist/storage/browser.js.map +1 -0
  190. package/dist/storage/index.cjs +1989 -0
  191. package/dist/storage/index.cjs.map +1 -0
  192. package/dist/storage/index.d.cts +92 -0
  193. package/dist/storage/index.d.ts +92 -0
  194. package/dist/storage/index.js +161 -0
  195. package/dist/storage/index.js.map +1 -0
  196. package/dist/storage/node.cjs +898 -0
  197. package/dist/storage/node.cjs.map +1 -0
  198. package/dist/storage/node.d.cts +66 -0
  199. package/dist/storage/node.d.ts +66 -0
  200. package/dist/storage/node.js +402 -0
  201. package/dist/storage/node.js.map +1 -0
  202. package/dist/testing/index.cjs +95 -0
  203. package/dist/testing/index.cjs.map +1 -0
  204. package/dist/testing/index.d.cts +20 -0
  205. package/dist/testing/index.d.ts +20 -0
  206. package/dist/testing/index.js +8 -0
  207. package/dist/testing/index.js.map +1 -0
  208. package/dist/types-bNMSWKqF.d.cts +732 -0
  209. package/dist/types-h12mNYbq.d.ts +732 -0
  210. package/package.json +250 -0
@@ -0,0 +1,1189 @@
1
+ import {
2
+ GRAPH_CHECKPOINT_VERSION,
3
+ checkpointBackendStateOfNode,
4
+ checkpointTerminal,
5
+ checkpointValue,
6
+ initNodeWithCore,
7
+ toCheckpointJson
8
+ } from "./chunk-PKVBHGBM.js";
9
+ import {
10
+ EnvironmentDrivers,
11
+ Node,
12
+ NodeCore,
13
+ batch,
14
+ checkpointStateOfNode,
15
+ defaultDispatcher,
16
+ getNodeOwner,
17
+ isNodeActiveForRelease,
18
+ isNodeRuntimeQuiescentForRelease,
19
+ isNodeRuntimeReleased,
20
+ releaseRuntimeOfNode,
21
+ setNodeOwner,
22
+ setNodeTopologyDepsChangedObserver,
23
+ subscriberCountOfNode,
24
+ withEnvironmentDrivers,
25
+ withNodeCore
26
+ } from "./chunk-I3IHOHCJ.js";
27
+ import {
28
+ assertStrictJsonObject,
29
+ stableJsonString,
30
+ strictCanonicalJsonBytes
31
+ } from "./chunk-4VLAQHZI.js";
32
+ import {
33
+ depCount,
34
+ depLatest
35
+ } from "./chunk-SWTLEQL6.js";
36
+ import {
37
+ SENTINEL,
38
+ errorPayload,
39
+ messageTier
40
+ } from "./chunk-DK554R7P.js";
41
+
42
+ // src/graph/blueprint.ts
43
+ var GRAPH_BLUEPRINT_VERSION = "graphrefly.blueprint.v1";
44
+ function normalizeTopologyMeta(meta, label = "meta", kind = "graph meta") {
45
+ try {
46
+ return assertStrictJsonObject(meta, label);
47
+ } catch (error) {
48
+ const message = error instanceof Error ? error.message : String(error);
49
+ throw new TypeError(`${label}: ${kind} must be strict JSON-compatible data (D177): ${message}`);
50
+ }
51
+ }
52
+ function normalizeTopology(snapshot) {
53
+ return normalizeTopologySnapshot(snapshot, /* @__PURE__ */ new WeakSet(), "$");
54
+ }
55
+ function normalizeTopologySnapshot(snapshot, seen, path) {
56
+ if (snapshot === null || typeof snapshot !== "object") {
57
+ throw new TypeError(`normalizeTopology: snapshot at ${path} must be an object`);
58
+ }
59
+ if (seen.has(snapshot)) {
60
+ throw new TypeError(`normalizeTopology: circular subgraph reference at ${path}`);
61
+ }
62
+ seen.add(snapshot);
63
+ try {
64
+ const nodes = mapDense(snapshot.nodes, `${path}.nodes`, (node, index) => {
65
+ const nodePath = `${path}.nodes[${index}]`;
66
+ assertTopologyObject(node, nodePath);
67
+ const id = topologyString(node.id, `${nodePath}.id`);
68
+ const factory = topologyString(node.factory, `${nodePath}.factory`);
69
+ const out2 = {
70
+ id,
71
+ factory,
72
+ deps: mapDense(
73
+ node.deps,
74
+ `${labelForNode(id)}.deps`,
75
+ (dep, depIndex) => topologyString(dep, `${labelForNode(id)}.deps[${depIndex}]`)
76
+ )
77
+ };
78
+ if (node.name !== void 0) {
79
+ out2.name = topologyString(node.name, `${nodePath}.name`);
80
+ }
81
+ if (node.meta !== void 0) {
82
+ out2.meta = normalizeTopologyMeta(node.meta, `${labelForNode(id)}.meta`);
83
+ }
84
+ return out2;
85
+ }).sort(compareNodes);
86
+ const out = {
87
+ nodes,
88
+ edges: deriveEdges(nodes)
89
+ };
90
+ if (snapshot.name !== void 0) {
91
+ out.name = topologyString(snapshot.name, `${path}.name`);
92
+ }
93
+ if (snapshot.subgraphs !== void 0) {
94
+ out.subgraphs = mapDense(
95
+ snapshot.subgraphs,
96
+ `${path}.subgraphs`,
97
+ (subgraph, index) => normalizeTopologySnapshot(subgraph, seen, `${path}.subgraphs[${index}]`)
98
+ ).sort(compareTopologies);
99
+ }
100
+ return out;
101
+ } finally {
102
+ seen.delete(snapshot);
103
+ }
104
+ }
105
+ function mapDense(values, path, mapper) {
106
+ if (!Array.isArray(values)) {
107
+ throw new TypeError(`normalizeTopology: ${path} must be an array`);
108
+ }
109
+ const out = [];
110
+ for (let i = 0; i < values.length; i += 1) {
111
+ if (!(i in values)) {
112
+ throw new TypeError(`normalizeTopology: sparse array hole at ${path}[${i}]`);
113
+ }
114
+ out.push(mapper(values[i], i));
115
+ }
116
+ return out;
117
+ }
118
+ function assertTopologyObject(value, path) {
119
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
120
+ throw new TypeError(`normalizeTopology: ${path} must be an object`);
121
+ }
122
+ }
123
+ function topologyString(value, path) {
124
+ if (typeof value !== "string") {
125
+ throw new TypeError(`normalizeTopology: ${path} must be a string`);
126
+ }
127
+ return value;
128
+ }
129
+ function canonicalTopologyJson(snapshot) {
130
+ return stableJsonString(normalizeTopology(snapshot));
131
+ }
132
+ function canonicalTopologyBytes(snapshot) {
133
+ return strictCanonicalJsonBytes(normalizeTopology(snapshot));
134
+ }
135
+ function withBlueprintHash(blueprint, options) {
136
+ if (typeof options.algorithm !== "string" || options.algorithm.length === 0) {
137
+ throw new TypeError("withBlueprintHash: algorithm must be a non-empty string");
138
+ }
139
+ const topology = normalizeTopology(blueprint.topology);
140
+ const withHash = (value2) => {
141
+ if (typeof value2 !== "string" || value2.length === 0) {
142
+ throw new TypeError("withBlueprintHash: hash value must be a non-empty string");
143
+ }
144
+ return {
145
+ ...blueprint,
146
+ topology,
147
+ hash: {
148
+ kind: "topology",
149
+ algorithm: options.algorithm,
150
+ input: "strictCanonicalTopologyBytes",
151
+ value: value2
152
+ }
153
+ };
154
+ };
155
+ const value = options.hash(canonicalTopologyBytes(topology));
156
+ if (typeof value !== "string" || value.length === 0) {
157
+ const maybeThenable = value;
158
+ if (maybeThenable === null || maybeThenable === void 0 || typeof maybeThenable.then !== "function") {
159
+ throw new TypeError("withBlueprintHash: hash value must be a non-empty string");
160
+ }
161
+ return value.then(withHash);
162
+ }
163
+ return withHash(value);
164
+ }
165
+ function withBlueprintProvenance(blueprint, provenance) {
166
+ return {
167
+ ...blueprint,
168
+ provenance: normalizeTopologyMeta(provenance, "graph blueprint provenance", "provenance")
169
+ };
170
+ }
171
+ function graphBlueprintDiagnostics(topology) {
172
+ const issues = [];
173
+ collectDiagnostics(topology, issues);
174
+ issues.sort(compareIssues);
175
+ return { ok: !issues.some((issue) => issue.severity === "error"), issues };
176
+ }
177
+ function collectDiagnostics(topology, issues) {
178
+ const seen = /* @__PURE__ */ new Set();
179
+ const duplicateIds = /* @__PURE__ */ new Set();
180
+ for (const node of topology.nodes) {
181
+ if (seen.has(node.id)) duplicateIds.add(node.id);
182
+ seen.add(node.id);
183
+ }
184
+ for (const id of duplicateIds) {
185
+ issues.push({
186
+ severity: "error",
187
+ code: "duplicate-node-id",
188
+ nodeId: id,
189
+ message: `duplicate topology node id '${id}'`
190
+ });
191
+ }
192
+ const dependents = /* @__PURE__ */ new Map();
193
+ for (const node of topology.nodes) dependents.set(node.id, 0);
194
+ for (const node of topology.nodes) {
195
+ for (const dep of node.deps) {
196
+ if (!seen.has(dep)) {
197
+ issues.push({
198
+ severity: "error",
199
+ code: "dangling-dep",
200
+ nodeId: node.id,
201
+ from: dep,
202
+ to: node.id,
203
+ message: `node '${node.id}' depends on missing node '${dep}'`
204
+ });
205
+ continue;
206
+ }
207
+ dependents.set(dep, (dependents.get(dep) ?? 0) + 1);
208
+ }
209
+ }
210
+ for (const node of topology.nodes) {
211
+ if (node.deps.length === 0 && (dependents.get(node.id) ?? 0) === 0) {
212
+ issues.push({
213
+ severity: "warning",
214
+ code: "island-node",
215
+ nodeId: node.id,
216
+ message: `node '${node.id}' has no deps and no dependents`
217
+ });
218
+ }
219
+ }
220
+ for (const subgraph of topology.subgraphs ?? []) collectDiagnostics(subgraph, issues);
221
+ }
222
+ function deriveEdges(nodes) {
223
+ const seen = /* @__PURE__ */ new Set();
224
+ const edges = [];
225
+ for (const node of nodes) {
226
+ for (const from of node.deps) {
227
+ const key = `${from}\0${node.id}`;
228
+ if (seen.has(key)) continue;
229
+ seen.add(key);
230
+ edges.push({ from, to: node.id });
231
+ }
232
+ }
233
+ return edges.sort(compareEdges);
234
+ }
235
+ function labelForNode(id) {
236
+ return id === "" ? "node" : `node '${id}'`;
237
+ }
238
+ function compareText(a, b) {
239
+ return a < b ? -1 : a > b ? 1 : 0;
240
+ }
241
+ function compareNodes(a, b) {
242
+ return compareText(a.id, b.id);
243
+ }
244
+ function compareEdges(a, b) {
245
+ return compareText(a.from, b.from) || compareText(a.to, b.to);
246
+ }
247
+ function compareTopologies(a, b) {
248
+ return compareText(stableJsonString(a), stableJsonString(b));
249
+ }
250
+ function compareIssues(a, b) {
251
+ return compareText(a.code, b.code) || compareText(a.nodeId ?? "", b.nodeId ?? "") || compareText(a.from ?? "", b.from ?? "") || compareText(a.to ?? "", b.to ?? "");
252
+ }
253
+
254
+ // src/graph/describe.ts
255
+ function topologyFromDescribe(snapshot) {
256
+ const nodes = snapshot.nodes.map((node) => {
257
+ const topologyNode = {
258
+ id: node.id,
259
+ factory: node.factory,
260
+ deps: [...node.deps]
261
+ };
262
+ if (node.name !== void 0) topologyNode.name = node.name;
263
+ if (node.meta !== void 0) topologyNode.meta = cloneTopologyMeta(node.meta);
264
+ return topologyNode;
265
+ });
266
+ const out = {
267
+ nodes,
268
+ edges: snapshot.edges.map((edge) => ({ from: edge.from, to: edge.to }))
269
+ };
270
+ if (snapshot.name !== void 0) out.name = snapshot.name;
271
+ if (snapshot.subgraphs !== void 0)
272
+ out.subgraphs = snapshot.subgraphs.map(topologyFromDescribe);
273
+ return out;
274
+ }
275
+ function cloneTopologyMeta(meta) {
276
+ return cloneTopologyValue(meta, /* @__PURE__ */ new WeakMap());
277
+ }
278
+ function cloneTopologyValue(value, seen) {
279
+ if (value === null) return null;
280
+ const kind = typeof value;
281
+ if (kind === "string" || kind === "boolean") return value;
282
+ if (kind === "number") {
283
+ if (!Number.isFinite(value)) {
284
+ throw new Error("topology(): meta must be finite JSON-compatible data (D39/D173)");
285
+ }
286
+ return value;
287
+ }
288
+ if (kind !== "object") {
289
+ throw new Error("topology(): meta must be JSON-compatible data (D39/D173)");
290
+ }
291
+ const objectValue = value;
292
+ const cached = seen.get(objectValue);
293
+ if (cached !== void 0) return cached;
294
+ if (Array.isArray(value)) {
295
+ const out2 = new Array(value.length);
296
+ seen.set(objectValue, out2);
297
+ for (let i = 0; i < value.length; i += 1) {
298
+ if (!(i in value)) {
299
+ throw new Error("topology(): meta arrays must be dense JSON-compatible data (D39/D173)");
300
+ }
301
+ out2[i] = cloneTopologyValue(value[i], seen);
302
+ }
303
+ return out2;
304
+ }
305
+ const proto = Object.getPrototypeOf(objectValue);
306
+ if (proto !== Object.prototype && proto !== null) {
307
+ throw new Error("topology(): meta must be plain JSON-compatible data (D39/D173)");
308
+ }
309
+ const out = {};
310
+ seen.set(objectValue, out);
311
+ for (const [key, item] of Object.entries(value))
312
+ out[key] = cloneTopologyValue(item, seen);
313
+ return out;
314
+ }
315
+
316
+ // src/graph/graph.ts
317
+ var restoreRegistrars = /* @__PURE__ */ new WeakMap();
318
+ var lifecycleRegistrars = /* @__PURE__ */ new WeakMap();
319
+ function nodeOwner(n) {
320
+ return getNodeOwner(n);
321
+ }
322
+ function assertGraphLocalNode(owner, n, label) {
323
+ if (isNodeRuntimeReleased(n)) {
324
+ throw new Error(`${label} has been released from its graph lifecycle (D122)`);
325
+ }
326
+ const existing = nodeOwner(n);
327
+ if (existing !== void 0 && existing !== owner) {
328
+ throw new Error(
329
+ `${label} belongs to a different graph; cross-graph deps require a wire bridge`
330
+ );
331
+ }
332
+ }
333
+ var StateNode = class extends Node {
334
+ set(v) {
335
+ this.down([["DATA", v]]);
336
+ }
337
+ };
338
+ var GraphTopologyGroup = class {
339
+ name;
340
+ _graph;
341
+ _members = [];
342
+ _released = false;
343
+ constructor(graph2, opts = {}) {
344
+ this._graph = graph2;
345
+ this.name = opts.name;
346
+ }
347
+ get released() {
348
+ return this._released;
349
+ }
350
+ add(node) {
351
+ this._assertLive();
352
+ const lifecycle = lifecycleRegistrars.get(this._graph);
353
+ if (lifecycle === void 0) throw new Error("topologyGroup: graph lifecycle unavailable");
354
+ lifecycle.assertRegisteredNode(node, `topology group '${this.name ?? "group"}' member`);
355
+ if (!this._members.includes(node)) this._members.push(node);
356
+ return node;
357
+ }
358
+ node(deps = [], fn = null, opts = {}) {
359
+ this._assertLive();
360
+ return this.add(this._graph.node(deps, fn, opts));
361
+ }
362
+ state(initial, opts = {}) {
363
+ this._assertLive();
364
+ return this.add(this._graph.state(initial, opts));
365
+ }
366
+ producer(fn, opts = {}) {
367
+ this._assertLive();
368
+ return this.add(this._graph.producer(fn, opts));
369
+ }
370
+ derived(deps, fn, opts = {}) {
371
+ this._assertLive();
372
+ return this.add(this._graph.derived(deps, fn, opts));
373
+ }
374
+ effect(deps, fn, opts = {}) {
375
+ this._assertLive();
376
+ return this.add(this._graph.effect(deps, fn, opts));
377
+ }
378
+ initNode(op, deps, opts = {}) {
379
+ this._assertLive();
380
+ return this.add(this._graph.initNode(op, deps, opts));
381
+ }
382
+ release(opts = {}) {
383
+ if (this._released) return;
384
+ const lifecycle = lifecycleRegistrars.get(this._graph);
385
+ if (lifecycle === void 0) throw new Error("topologyGroup: graph lifecycle unavailable");
386
+ lifecycle.releaseNodes([...this._members], {
387
+ reason: opts.reason ?? this.name
388
+ });
389
+ this._members.length = 0;
390
+ this._released = true;
391
+ }
392
+ _assertLive() {
393
+ if (this._released) {
394
+ throw new Error(`topology group '${this.name ?? "group"}' has been released (D152)`);
395
+ }
396
+ }
397
+ };
398
+ var Graph = class {
399
+ name;
400
+ _dispatcher;
401
+ _versioning;
402
+ _environment;
403
+ _core = new NodeCore();
404
+ _entries = /* @__PURE__ */ new Map();
405
+ _byId = /* @__PURE__ */ new Map();
406
+ _retiredIds = /* @__PURE__ */ new Set();
407
+ _mounts = [];
408
+ _seq = 0;
409
+ _clock = 0;
410
+ // graph-local monotonic clock for observe seq (D26)
411
+ _topologyObserverSeq = 0;
412
+ _topologyObservers = /* @__PURE__ */ new Map();
413
+ _topologyDelivering = false;
414
+ _topologyQueue = [];
415
+ // D51: stable synthetic ids for unregistered live deps (runtime *Map inners) auto-discovered by
416
+ // describe(). WeakMap-cached so successive describes agree + the inner's id is freed when it is.
417
+ // A dedicated counter (NOT _seq) so a describe() call never perturbs registered-node id numbering.
418
+ _synthSeq = 0;
419
+ _synthIds = /* @__PURE__ */ new WeakMap();
420
+ constructor(opts = {}) {
421
+ this.name = opts.name;
422
+ this._dispatcher = opts.dispatcher ?? defaultDispatcher;
423
+ this._versioning = opts.versioning;
424
+ this._environment = opts.environment ?? EnvironmentDrivers.empty();
425
+ if (opts.profile) this._dispatcher.setRecording(true);
426
+ restoreRegistrars.set(this, {
427
+ stateNode: (id, stateOpts = {}) => {
428
+ const n = this._construct(() => new StateNode([], null, this._nodeOpts(stateOpts)));
429
+ this._addWithId(n, "state", [], stateOpts, id);
430
+ return n;
431
+ },
432
+ node: (id, factory, deps, fn, nodeOpts = {}) => {
433
+ this._assertDepsLocal(deps, `dep of restored '${id}'`);
434
+ const n = this._construct(() => new Node([...deps], fn, this._nodeOpts(nodeOpts)));
435
+ this._addWithId(n, factory, deps, nodeOpts, id);
436
+ return n;
437
+ }
438
+ });
439
+ lifecycleRegistrars.set(this, {
440
+ assertRegisteredNode: (node, label) => this._assertRegisteredNode(node, label),
441
+ releaseNodes: (nodes, releaseOpts) => this._releaseNodes(nodes, releaseOpts)
442
+ });
443
+ }
444
+ // ── registration / inspection index ──
445
+ _add(n, factory, deps, opts) {
446
+ const id = opts.name ?? `${factory}#${this._seq++}`;
447
+ return this._addWithId(n, factory, deps, opts, id);
448
+ }
449
+ _addWithId(n, factory, deps, opts, id) {
450
+ assertGraphLocalNode(this, n, `graph node '${opts.name ?? factory}'`);
451
+ for (const dep of deps) assertGraphLocalNode(this, dep, `dep of '${opts.name ?? factory}'`);
452
+ if (this._byId.has(id)) {
453
+ throw new Error(`graph: duplicate node id '${id}' (checkpoint/describe ids must be unique)`);
454
+ }
455
+ if (this._retiredIds.has(id)) {
456
+ throw new Error(`graph: node id '${id}' was released and cannot be reused (D152/D153)`);
457
+ }
458
+ const meta = opts.meta === void 0 ? void 0 : normalizeTopologyMeta(opts.meta, `graph node '${id}' meta`);
459
+ this._entries.set(n, {
460
+ node: n,
461
+ id,
462
+ name: opts.name,
463
+ factory,
464
+ deps,
465
+ meta,
466
+ restore: opts.restore
467
+ });
468
+ setNodeOwner(n, this);
469
+ this._byId.set(id, n);
470
+ setNodeTopologyDepsChangedObserver(n, (_node, prevDeps, nextDeps) => {
471
+ this._emitTopologyDepsChanged(n, prevDeps, nextDeps);
472
+ });
473
+ const seqMatch = /#(\d+)$/.exec(id);
474
+ if (seqMatch) this._seq = Math.max(this._seq, Number(seqMatch[1]) + 1);
475
+ this._emitTopologyNodeRegistered(n);
476
+ return n;
477
+ }
478
+ _assertDepsLocal(deps, label) {
479
+ for (const dep of deps) assertGraphLocalNode(this, dep, label);
480
+ }
481
+ _assertRegisteredNode(node, label) {
482
+ assertGraphLocalNode(this, node, label);
483
+ if (!this._entries.has(node)) {
484
+ throw new Error(`${label} is not a registered graph node (D152)`);
485
+ }
486
+ }
487
+ _nodeOpts(opts) {
488
+ if (opts.meta !== void 0) {
489
+ normalizeTopologyMeta(opts.meta, `graph node '${opts.name ?? opts.factory ?? "node"}' meta`);
490
+ }
491
+ const { name: _n, meta: _m, restore: _r, ...rest } = opts;
492
+ return {
493
+ ...rest,
494
+ versioning: rest.versioning ?? this._versioning,
495
+ dispatcher: this._dispatcher
496
+ };
497
+ }
498
+ _construct(create) {
499
+ return withEnvironmentDrivers(this._environment, () => withNodeCore(this._core, create));
500
+ }
501
+ /** Look up a registered node by its id. */
502
+ find(id) {
503
+ return this._byId.get(id);
504
+ }
505
+ _releaseNodes(nodes, _opts = {}) {
506
+ const seen = /* @__PURE__ */ new Set();
507
+ const entries = [];
508
+ for (const node of nodes) {
509
+ if (seen.has(node)) continue;
510
+ seen.add(node);
511
+ const entry = this._entries.get(node);
512
+ if (entry === void 0) continue;
513
+ entries.push({ node, entry });
514
+ }
515
+ const releaseSet = new Set(entries.map(({ node }) => node));
516
+ const releaseIds = new Map(entries.map(({ node, entry }) => [node, entry.id]));
517
+ for (const entry of this._entries.values()) {
518
+ if (releaseSet.has(entry.node)) continue;
519
+ for (const dep of entry.node.deps) {
520
+ if (!releaseSet.has(dep)) continue;
521
+ const depId = releaseIds.get(dep) ?? dep.name ?? dep.factory ?? "released node";
522
+ throw new Error(
523
+ `graph: cannot release node group; '${entry.id}' still depends on '${depId}' (D122)`
524
+ );
525
+ }
526
+ }
527
+ for (const { node, entry } of entries) {
528
+ if (!isNodeRuntimeQuiescentForRelease(node)) {
529
+ throw new Error(
530
+ `graph: cannot release node group; '${entry.id}' is not runtime-quiescent (D124)`
531
+ );
532
+ }
533
+ let internalSubscribers = 0;
534
+ for (const { node: dependent } of entries) {
535
+ if (dependent === node || !isNodeActiveForRelease(dependent)) continue;
536
+ for (const dep of dependent.deps) {
537
+ if (dep === node) internalSubscribers += 1;
538
+ }
539
+ }
540
+ if (subscriberCountOfNode(node) > internalSubscribers) {
541
+ throw new Error(
542
+ `graph: cannot release node group; '${entry.id}' still has live subscribers (D124)`
543
+ );
544
+ }
545
+ }
546
+ const releasedEvents = this._topologyObservers.size === 0 ? [] : entries.map(({ node, entry }) => ({
547
+ path: entry.id,
548
+ factory: entry.factory,
549
+ deps: this._topologyDeps(node.deps)
550
+ }));
551
+ for (const { node, entry } of entries) {
552
+ this._entries.delete(node);
553
+ this._byId.delete(entry.id);
554
+ this._retiredIds.add(entry.id);
555
+ }
556
+ let releaseError;
557
+ for (const { node } of entries) {
558
+ try {
559
+ releaseRuntimeOfNode(node);
560
+ } catch (error) {
561
+ if (releaseError === void 0) releaseError = error;
562
+ }
563
+ }
564
+ for (const event of releasedEvents) this._emitTopologyNodeReleased(event);
565
+ if (releaseError !== void 0) throw releaseError;
566
+ }
567
+ // ── 8 verbs (core: node/state/batch + sugar: producer/derived/effect/mount) ──
568
+ /** ctx-level power surface: a raw `(ctx)=>void` fn (or a passthrough/state when null). */
569
+ node(deps = [], fn = null, opts = {}) {
570
+ this._assertDepsLocal(deps, `dep of '${opts.name ?? "node"}'`);
571
+ const n = this._construct(() => new Node(deps, fn, this._nodeOpts(opts)));
572
+ return this._add(n, opts.factory ?? "node", deps, opts);
573
+ }
574
+ /** A manual source with `.set(v)` (L4-Q1). */
575
+ state(initial, opts = {}) {
576
+ const n = this._construct(
577
+ () => new StateNode([], null, { ...this._nodeOpts(opts), initial })
578
+ );
579
+ this._add(n, "state", [], opts);
580
+ return n;
581
+ }
582
+ /** ctx-level depless source; its fn runs on activation (R-rom-ram). */
583
+ producer(fn, opts = {}) {
584
+ const n = this._construct(() => new Node([], fn, this._nodeOpts(opts)));
585
+ return this._add(n, "producer", [], opts);
586
+ }
587
+ /** value-level pure transform: deps → value (D27 wrapped; D30 throw→ERROR). */
588
+ derived(deps, fn, opts = {}) {
589
+ this._assertDepsLocal(deps, `dep of '${opts.name ?? "derived"}'`);
590
+ const ctxFn = (ctx) => {
591
+ try {
592
+ const args = Array.from(
593
+ { length: depCount(ctx) },
594
+ (_, i) => depLatest(ctx, i)
595
+ );
596
+ const result = fn(...args);
597
+ if (result !== void 0) ctx.down([["DATA", result]]);
598
+ } catch (e) {
599
+ ctx.down([["ERROR", errorPayload(e, "derived threw without a valid error payload")]]);
600
+ }
601
+ };
602
+ const n = this._construct(() => new Node([...deps], ctxFn, this._nodeOpts(opts)));
603
+ return this._add(n, "derived", deps, opts);
604
+ }
605
+ /** value-level sink: deps → effect; return value (a fn) becomes onDeactivation (D28). */
606
+ effect(deps, fn, opts = {}) {
607
+ this._assertDepsLocal(deps, `dep of '${opts.name ?? "effect"}'`);
608
+ const ctxFn = (ctx) => {
609
+ try {
610
+ const args = Array.from(
611
+ { length: depCount(ctx) },
612
+ (_, i) => depLatest(ctx, i)
613
+ );
614
+ const cleanup = fn(...args);
615
+ if (typeof cleanup === "function") ctx.onDeactivation(cleanup);
616
+ } catch (e) {
617
+ ctx.down([["ERROR", errorPayload(e, "effect threw without a valid error payload")]]);
618
+ }
619
+ };
620
+ const n = this._construct(() => new Node([...deps], ctxFn, this._nodeOpts(opts)));
621
+ return this._add(n, "effect", deps, opts);
622
+ }
623
+ /** Declarative batch (D12): one wave, success→commit / throw→rollback. */
624
+ batch(fn) {
625
+ return batch(fn);
626
+ }
627
+ /** Embed a child graph addressable under `at` (R-mount; mount has no deps). */
628
+ mount(child, opts) {
629
+ const mount = { at: opts.at, graph: child };
630
+ this._mounts.push(mount);
631
+ if (this._topologyObservers.size > 0) this._ensureMountedTopologyForwarders();
632
+ this._emitTopologyMountChanged(opts.at);
633
+ }
634
+ // ── operator funnel (D43): instantiate any free-standing Operator (node sugar, D6/L1.5) ──
635
+ // g.initNode is the single graph-bound entry for the whole operator/source catalog (D40):
636
+ // it delegates to the FREE initNode (graph/operators.ts — the D30 throw→ERROR boundary +
637
+ // dispatcher binding live there) and records the operator's REAL factory name in the
638
+ // inspection index (_add) so describe shows it (D6/R-describe) while the node stays thin
639
+ // (R-node-thin). Operators are free-standing factory definitions (graph/operators.ts,
640
+ // graph/sources.ts) usable bare via the free initNode(); this funnel is the inspectable
641
+ // path. Replaces the per-operator methods.
642
+ /**
643
+ * Instantiate an operator (or source) factory as a registered graph node. `deps` are
644
+ * type-checked against the operator's input element type; the output type flows from the
645
+ * operator. A source is a depless operator — pass `[]`. Caller `opts` (name/meta/behavioral
646
+ * overrides) win over the operator's baked-in `opts`.
647
+ */
648
+ initNode(op, deps, opts = {}) {
649
+ const entryOpts = op.restore !== void 0 && !("restore" in opts) ? { ...opts, restore: op.restore } : opts;
650
+ for (const dep of deps)
651
+ assertGraphLocalNode(this, dep, `dep of '${entryOpts.name ?? op.factory}'`);
652
+ const erased = deps;
653
+ const n = withEnvironmentDrivers(
654
+ this._environment,
655
+ () => initNodeWithCore(this._core, op, erased, this._nodeOpts(entryOpts))
656
+ );
657
+ return this._add(n, op.factory, erased, entryOpts);
658
+ }
659
+ /**
660
+ * Graph-owned activation root for internal helper nodes. This is the sanctioned keepalive shape:
661
+ * a graph, not a helper closure, owns the subscription and returns the release handle.
662
+ */
663
+ retain(node, opts = {}) {
664
+ assertGraphLocalNode(this, node, opts.reason ?? "retained node");
665
+ return node.subscribe(() => {
666
+ });
667
+ }
668
+ /**
669
+ * D152 graph-owned topology/release group. Members are ordinary registered graph nodes;
670
+ * release is quiescent-only and removes ids atomically without synthesizing protocol messages.
671
+ */
672
+ topologyGroup(opts = {}) {
673
+ return new GraphTopologyGroup(this, opts);
674
+ }
675
+ // ── inspection: describe / observe / profile (D39) ──
676
+ /** Live point-in-time structure snapshot (R-describe / D39 / D51). `_prefix` carries the mount path. */
677
+ describe(opts = {}, _prefix = "") {
678
+ const discovered = /* @__PURE__ */ new Map();
679
+ const localId = (n) => {
680
+ const e = this._entries.get(n);
681
+ if (e) return `${_prefix}${e.id}`;
682
+ let sid = this._synthIds.get(n);
683
+ if (sid === void 0) {
684
+ do {
685
+ sid = `~${n.factory ?? "?"}#${this._synthSeq++}`;
686
+ } while (this._byId.has(sid));
687
+ this._synthIds.set(n, sid);
688
+ }
689
+ discovered.set(n, sid);
690
+ return `${_prefix}${sid}`;
691
+ };
692
+ const nodes = [];
693
+ const edges = [];
694
+ for (const entry of this._entries.values()) {
695
+ const id = `${_prefix}${entry.id}`;
696
+ const liveIds = entry.node.deps.map(localId);
697
+ const dnode = {
698
+ id,
699
+ factory: entry.factory,
700
+ status: entry.node.status,
701
+ deps: liveIds
702
+ };
703
+ if (entry.name !== void 0) dnode.name = entry.name;
704
+ if (entry.node.cache !== void 0) dnode.value = entry.node.cache;
705
+ if (entry.node.version !== void 0) dnode.version = entry.node.version;
706
+ if (entry.meta !== void 0) dnode.meta = entry.meta;
707
+ nodes.push(dnode);
708
+ for (const from of liveIds) edges.push({ from, to: id });
709
+ }
710
+ const visited = /* @__PURE__ */ new Set();
711
+ const queue = [...discovered.keys()];
712
+ for (let i = 0; i < queue.length; i += 1) {
713
+ const inner = queue[i];
714
+ if (visited.has(inner)) continue;
715
+ visited.add(inner);
716
+ const sid = discovered.get(inner);
717
+ if (sid === void 0) continue;
718
+ const liveIds = inner.deps.map(localId);
719
+ for (const dep of inner.deps) {
720
+ if (!this._entries.has(dep) && !visited.has(dep)) queue.push(dep);
721
+ }
722
+ const dnode = {
723
+ id: `${_prefix}${sid}`,
724
+ factory: inner.factory ?? "?",
725
+ status: inner.status,
726
+ deps: liveIds
727
+ };
728
+ if (inner.cache !== void 0) dnode.value = inner.cache;
729
+ if (inner.version !== void 0) dnode.version = inner.version;
730
+ nodes.push(dnode);
731
+ for (const from of liveIds) edges.push({ from, to: dnode.id });
732
+ }
733
+ const snap = { nodes, edges };
734
+ if (this.name !== void 0) snap.name = this.name;
735
+ if (this._mounts.length > 0) {
736
+ snap.subgraphs = this._mounts.map((m) => m.graph.describe({}, `${_prefix}${m.at}::`));
737
+ }
738
+ return opts.explain ? explainSubset(snap, opts.explain) : snap;
739
+ }
740
+ /**
741
+ * D173 pure-structure topology snapshot over the same live truth source as describe().
742
+ * Runtime status/value/version remain on describe(); blueprint metadata is a later envelope.
743
+ */
744
+ topology() {
745
+ return topologyFromDescribe(this.describe());
746
+ }
747
+ /**
748
+ * D177 synchronous audit/collaboration envelope over the pure topology snapshot.
749
+ * Hashing and environment provenance enrichment stay in pure helpers outside Graph core.
750
+ */
751
+ blueprint(opts = {}) {
752
+ const topology = normalizeTopology(this.topology());
753
+ const out = {
754
+ version: GRAPH_BLUEPRINT_VERSION,
755
+ topology
756
+ };
757
+ if (opts.diagnostics) {
758
+ out.diagnostics = graphBlueprintDiagnostics(topology);
759
+ }
760
+ if (opts.provenance !== void 0) {
761
+ out.provenance = normalizeTopologyMeta(
762
+ opts.provenance,
763
+ "graph blueprint provenance",
764
+ "provenance"
765
+ );
766
+ }
767
+ return out;
768
+ }
769
+ _observeTargets(path) {
770
+ const all = [...this._entries.values()].map((e) => [
771
+ e.id,
772
+ e.node
773
+ ]);
774
+ if (path === void 0) return all;
775
+ const exact = this._byId.get(path);
776
+ if (exact) return [[path, exact]];
777
+ return all.filter(([id]) => id.startsWith(`${path}::`));
778
+ }
779
+ /**
780
+ * observe(path?) = read-only enveloped EGRESS (R-observe / D39). NOT a graph node — it
781
+ * taps the target node(s) via subscribe and forwards each Message as an ObserveEvent.
782
+ * No path = whole graph; an exact id = a single node; otherwise a `::`-prefix subtree.
783
+ */
784
+ // NOTE (R-observe/D19): observe is a real, lazily-ACTIVATING subscriber — observing a
785
+ // cold node runs its fn (and activates upstream); whole-graph observe() activates the
786
+ // graph. "Read-only" means it never emits/mutates node state, NOT that it avoids
787
+ // activation. Use it knowing inspection of a cold graph wakes it.
788
+ observe(path) {
789
+ const targets = this._observeTargets(path);
790
+ return {
791
+ subscribe: (sink) => {
792
+ const unsubs = targets.map(
793
+ ([id, n]) => n.subscribe((msg) => {
794
+ sink({ path: id, msg, tier: messageTier(msg[0]), seq: this._clock++ });
795
+ })
796
+ );
797
+ return () => {
798
+ for (const u of unsubs) u();
799
+ };
800
+ }
801
+ };
802
+ }
803
+ /**
804
+ * D145 observeTopology(path?) = read-only graph lifecycle egress over the existing
805
+ * graph registry. It is not a graph node, does not subscribe to nodes, and emits no DATA.
806
+ */
807
+ observeTopology(path) {
808
+ return {
809
+ subscribe: (sink) => {
810
+ const id = this._topologyObserverSeq++;
811
+ this._topologyObservers.set(id, { path, sink });
812
+ this._ensureMountedTopologyForwarders();
813
+ return () => {
814
+ this._topologyObservers.delete(id);
815
+ if (this._topologyObservers.size === 0) this._releaseMountedTopologyForwarders();
816
+ };
817
+ }
818
+ };
819
+ }
820
+ _idForTopologyNode(n) {
821
+ const e = this._entries.get(n);
822
+ if (e) return e.id;
823
+ let sid = this._synthIds.get(n);
824
+ if (sid === void 0) {
825
+ do {
826
+ sid = `~${n.factory ?? "?"}#${this._synthSeq++}`;
827
+ } while (this._byId.has(sid));
828
+ this._synthIds.set(n, sid);
829
+ }
830
+ return sid;
831
+ }
832
+ _topologyDeps(deps) {
833
+ return deps.map((dep) => this._idForTopologyNode(dep));
834
+ }
835
+ _emitTopologyNodeRegistered(node) {
836
+ if (this._topologyObservers.size === 0) return;
837
+ const entry = this._entries.get(node);
838
+ if (entry === void 0) return;
839
+ this._emitTopologyEvent({
840
+ kind: "node-registered",
841
+ path: entry.id,
842
+ factory: entry.factory,
843
+ deps: this._topologyDeps(node.deps),
844
+ seq: this._clock++
845
+ });
846
+ }
847
+ _emitTopologyDepsChanged(node, prevDeps, nextDeps) {
848
+ if (this._topologyObservers.size === 0) return;
849
+ const entry = this._entries.get(node);
850
+ if (entry === void 0) return;
851
+ this._emitTopologyEvent({
852
+ kind: "deps-changed",
853
+ path: entry.id,
854
+ prevDeps: this._topologyDeps(prevDeps),
855
+ deps: this._topologyDeps(nextDeps),
856
+ seq: this._clock++
857
+ });
858
+ }
859
+ _emitTopologyNodeReleased(event) {
860
+ if (this._topologyObservers.size === 0) return;
861
+ this._emitTopologyEvent({
862
+ kind: "node-released",
863
+ path: event.path,
864
+ factory: event.factory,
865
+ deps: [...event.deps],
866
+ seq: this._clock++
867
+ });
868
+ }
869
+ _emitTopologyMountChanged(path) {
870
+ if (this._topologyObservers.size === 0) return;
871
+ this._emitTopologyEvent({
872
+ kind: "mount-changed",
873
+ path,
874
+ factory: "mount",
875
+ deps: [],
876
+ seq: this._clock++
877
+ });
878
+ }
879
+ _ensureMountedTopologyForwarders() {
880
+ if (this._topologyObservers.size === 0) return;
881
+ for (const mount of this._mounts) {
882
+ if (mount.topologyUnsub !== void 0) continue;
883
+ const mountPath = mount.at;
884
+ mount.topologyUnsub = mount.graph.observeTopology().subscribe((event) => {
885
+ this._emitMountedTopologyEvent(mountPath, event);
886
+ });
887
+ }
888
+ }
889
+ _releaseMountedTopologyForwarders() {
890
+ for (const mount of this._mounts) {
891
+ mount.topologyUnsub?.();
892
+ mount.topologyUnsub = void 0;
893
+ }
894
+ }
895
+ _emitMountedTopologyEvent(mountPath, event) {
896
+ if (this._topologyObservers.size === 0) return;
897
+ this._emitTopologyEvent({
898
+ kind: event.kind,
899
+ path: prefixTopologyPath(mountPath, event.path),
900
+ deps: event.deps.map((dep) => prefixTopologyPath(mountPath, dep)),
901
+ ...event.prevDeps !== void 0 ? { prevDeps: event.prevDeps.map((dep) => prefixTopologyPath(mountPath, dep)) } : {},
902
+ ...event.factory !== void 0 ? { factory: event.factory } : {},
903
+ seq: this._clock++
904
+ });
905
+ }
906
+ _emitTopologyEvent(event) {
907
+ if (this._topologyDelivering) {
908
+ this._topologyQueue.push(event);
909
+ return;
910
+ }
911
+ this._topologyDelivering = true;
912
+ try {
913
+ let current = event;
914
+ while (current !== void 0) {
915
+ const observers = [...this._topologyObservers.entries()];
916
+ for (const [id, observer] of observers) {
917
+ if (this._topologyObservers.get(id) !== observer) continue;
918
+ if (observer.path !== void 0 && !topologyPathMatches(current.path, observer.path))
919
+ continue;
920
+ try {
921
+ observer.sink(cloneTopologyEvent(current));
922
+ } catch {
923
+ }
924
+ }
925
+ current = this._topologyQueue.shift();
926
+ }
927
+ } finally {
928
+ this._topologyDelivering = false;
929
+ }
930
+ }
931
+ /**
932
+ * profile() = accumulated-counter snapshot (R-profile / D39). invokes + duration are
933
+ * dispatcher-backed (the invoke funnel, F-DISPATCH-ALL) — counters never live on the
934
+ * thin node (R-node-thin). Requires `graph({ profile: true })` (opt-in, F-PERF).
935
+ */
936
+ profile() {
937
+ const nodes = {};
938
+ let totalInvokes = 0;
939
+ for (const e of this._entries.values()) {
940
+ const h = e.node.handle;
941
+ const stat = h ? this._dispatcher.statFor(h) : void 0;
942
+ const invokes = stat?.invokes ?? 0;
943
+ nodes[e.id] = {
944
+ invokes,
945
+ totalDurationNs: stat?.totalDurationNs ?? 0,
946
+ lastDurationNs: stat?.lastDurationNs ?? 0,
947
+ status: e.node.status
948
+ };
949
+ totalInvokes += invokes;
950
+ }
951
+ return { totalInvokes, nodes };
952
+ }
953
+ /** Versioned graph lifecycle checkpoint (R-snapshot / D83 / D90). Pure capture, no storage I/O. */
954
+ checkpoint() {
955
+ return this._checkpoint("", /* @__PURE__ */ new WeakSet());
956
+ }
957
+ _checkpoint(_prefix, stack) {
958
+ if (stack.has(this)) {
959
+ throw new Error("checkpoint: cyclic graph mount detected");
960
+ }
961
+ stack.add(this);
962
+ const discovered = /* @__PURE__ */ new Map();
963
+ const localId = (n) => {
964
+ const e = this._entries.get(n);
965
+ if (e) return `${_prefix}${e.id}`;
966
+ let sid = this._synthIds.get(n);
967
+ if (sid === void 0) {
968
+ do {
969
+ sid = `~${n.factory ?? "?"}#${this._synthSeq++}`;
970
+ } while (this._byId.has(sid));
971
+ this._synthIds.set(n, sid);
972
+ }
973
+ discovered.set(n, sid);
974
+ return `${_prefix}${sid}`;
975
+ };
976
+ const nodes = [];
977
+ const edges = [];
978
+ for (const entry of this._entries.values()) {
979
+ const id = `${_prefix}${entry.id}`;
980
+ const liveIds = entry.node.deps.map(localId);
981
+ nodes.push(
982
+ this._checkpointNode(entry.node, id, {
983
+ name: entry.name,
984
+ factory: checkpointFactory(entry.factory, entry.node, false, entry.restore, entry.meta),
985
+ deps: liveIds,
986
+ meta: entry.meta
987
+ })
988
+ );
989
+ for (const from of liveIds) edges.push({ from, to: id });
990
+ }
991
+ const visited = /* @__PURE__ */ new Set();
992
+ const queue = [...discovered.keys()];
993
+ for (let i = 0; i < queue.length; i += 1) {
994
+ const inner = queue[i];
995
+ if (visited.has(inner)) continue;
996
+ visited.add(inner);
997
+ const sid = discovered.get(inner);
998
+ if (sid === void 0) continue;
999
+ const liveIds = inner.deps.map(localId);
1000
+ for (const dep of inner.deps) {
1001
+ if (!this._entries.has(dep) && !visited.has(dep)) queue.push(dep);
1002
+ }
1003
+ const id = `${_prefix}${sid}`;
1004
+ nodes.push(
1005
+ this._checkpointNode(inner, id, {
1006
+ factory: checkpointFactory(inner.factory ?? "?", inner, true),
1007
+ deps: liveIds
1008
+ })
1009
+ );
1010
+ for (const from of liveIds) edges.push({ from, to: id });
1011
+ }
1012
+ const checkpoint = {
1013
+ version: GRAPH_CHECKPOINT_VERSION,
1014
+ nodes,
1015
+ edges
1016
+ };
1017
+ if (this.name !== void 0) checkpoint.name = this.name;
1018
+ if (this._mounts.length > 0) {
1019
+ checkpoint.mounts = this._mounts.map((m) => ({
1020
+ at: m.at,
1021
+ checkpoint: m.graph._checkpoint("", stack)
1022
+ }));
1023
+ }
1024
+ stack.delete(this);
1025
+ return toCheckpointJson(checkpoint, "checkpoint");
1026
+ }
1027
+ _checkpointNode(node, id, opts) {
1028
+ const state = checkpointStateOfNode(node);
1029
+ assertCheckpointQuiescentStatus(node.status, id, "checkpoint");
1030
+ const nonAuthoritativeCollectionHelper = isNonAuthoritativeCollectionHelperMeta(opts.meta);
1031
+ const out = {
1032
+ id,
1033
+ factory: opts.factory,
1034
+ status: node.status,
1035
+ deps: opts.deps,
1036
+ value: nonAuthoritativeCollectionHelper ? { kind: "SENTINEL" } : checkpointValue(state.cache, state.hasData, `${id}.value`),
1037
+ terminal: checkpointTerminal(state.terminal, `${id}.terminal`),
1038
+ lifecycle: { activated: state.activated, hasCalledFnOnce: state.hasCalledFnOnce },
1039
+ ctxState: {
1040
+ persist: state.ctxState.persist,
1041
+ value: nonAuthoritativeCollectionHelper ? { kind: "SENTINEL" } : checkpointValue(
1042
+ state.ctxState.value,
1043
+ state.ctxState.value !== SENTINEL,
1044
+ `${id}.ctxState`
1045
+ )
1046
+ }
1047
+ };
1048
+ if (opts.name !== void 0) out.name = opts.name;
1049
+ const backendState = checkpointBackendStateOfNode(node, `${id}.backendState`);
1050
+ if (backendState !== void 0) out.backendState = backendState;
1051
+ if (state.version !== void 0) out.version = state.version;
1052
+ if (opts.meta !== void 0)
1053
+ out.meta = toCheckpointJson(opts.meta, `${id}.meta`);
1054
+ return out;
1055
+ }
1056
+ };
1057
+ function isNonAuthoritativeCollectionHelperMeta(meta) {
1058
+ return meta?.kind === "collection_delta" || meta?.kind === "collection_intent" || meta?.kind === "collection_policy_apply" || meta?.kind === "collection_snapshot" || meta?.kind === "collection_snapshot_prep";
1059
+ }
1060
+ function assertCheckpointQuiescentStatus(status, id, op) {
1061
+ if (status === "pending" || status === "dirty") {
1062
+ throw new Error(
1063
+ `${op}: node '${id}' has non-quiescent status '${status}' that cannot be checkpoint-restored yet`
1064
+ );
1065
+ }
1066
+ }
1067
+ function topologyPathMatches(eventPath, path) {
1068
+ return eventPath === path || eventPath.startsWith(`${path}::`);
1069
+ }
1070
+ function prefixTopologyPath(prefix, path) {
1071
+ return `${prefix}::${path}`;
1072
+ }
1073
+ function cloneTopologyEvent(event) {
1074
+ const deps = Object.freeze([...event.deps]);
1075
+ const prevDeps = event.prevDeps === void 0 ? void 0 : Object.freeze([...event.prevDeps]);
1076
+ return Object.freeze({
1077
+ kind: event.kind,
1078
+ path: event.path,
1079
+ deps,
1080
+ ...prevDeps !== void 0 ? { prevDeps } : {},
1081
+ ...event.factory !== void 0 ? { factory: event.factory } : {},
1082
+ seq: event.seq
1083
+ });
1084
+ }
1085
+ function checkpointFactory(name, node, unregistered, restore, meta) {
1086
+ const state = checkpointStateOfNode(node);
1087
+ if (unregistered) {
1088
+ return {
1089
+ kind: "local-only",
1090
+ name,
1091
+ reason: "node is an unregistered live dependency auto-discovered from topology"
1092
+ };
1093
+ }
1094
+ if (restore === void 0 && typeof meta?.kind === "string" && meta.kind.startsWith("collection_")) {
1095
+ return {
1096
+ kind: "local-only",
1097
+ name,
1098
+ reason: "collection helper node has no backend checkpoint restore metadata"
1099
+ };
1100
+ }
1101
+ if (restore !== void 0) {
1102
+ const out = {
1103
+ kind: "registry-ref",
1104
+ ref: toCheckpointJson(restore.ref, `${name}.factory.ref`)
1105
+ };
1106
+ if (restore.config !== void 0)
1107
+ out.config = toCheckpointJson(restore.config, `${name}.factory.config`);
1108
+ if (restore.configVersion !== void 0)
1109
+ out.configVersion = toCheckpointJson(restore.configVersion, `${name}.factory.configVersion`);
1110
+ return out;
1111
+ }
1112
+ if (state.handle !== null) {
1113
+ return {
1114
+ kind: "local-only",
1115
+ name,
1116
+ reason: "node uses a function body; first-cut checkpoints do not serialize local functions"
1117
+ };
1118
+ }
1119
+ return { kind: "registry-ref", ref: name };
1120
+ }
1121
+ function explainSubset(snap, chain) {
1122
+ const fwd = /* @__PURE__ */ new Map();
1123
+ const rev = /* @__PURE__ */ new Map();
1124
+ const push = (map, k, v) => {
1125
+ const a = map.get(k);
1126
+ if (a) a.push(v);
1127
+ else map.set(k, [v]);
1128
+ };
1129
+ for (const e of snap.edges) {
1130
+ push(fwd, e.from, e.to);
1131
+ push(rev, e.to, e.from);
1132
+ }
1133
+ const reach = (start, adj) => {
1134
+ const seen = /* @__PURE__ */ new Set([start]);
1135
+ const stack = [start];
1136
+ while (stack.length > 0) {
1137
+ const cur = stack.pop();
1138
+ for (const nxt of adj.get(cur) ?? []) {
1139
+ if (!seen.has(nxt)) {
1140
+ seen.add(nxt);
1141
+ stack.push(nxt);
1142
+ }
1143
+ }
1144
+ }
1145
+ return seen;
1146
+ };
1147
+ const onPath = new Set([...reach(chain.from, fwd)].filter((id) => reach(chain.to, rev).has(id)));
1148
+ return {
1149
+ ...snap.name !== void 0 ? { name: snap.name } : {},
1150
+ nodes: snap.nodes.filter((n) => onPath.has(n.id)),
1151
+ edges: snap.edges.filter((e) => onPath.has(e.from) && onPath.has(e.to))
1152
+ };
1153
+ }
1154
+ function graph(opts = {}) {
1155
+ return new Graph(opts);
1156
+ }
1157
+ function releaseGraphNodes(graph2, nodes, opts = {}) {
1158
+ const registrar = lifecycleRegistrars.get(graph2);
1159
+ if (registrar === void 0) throw new Error("graph: unknown lifecycle registrar");
1160
+ registrar.releaseNodes(nodes, opts);
1161
+ }
1162
+ function restoreStateNodeInGraph(graph2, id, opts = {}) {
1163
+ const registrar = restoreRegistrars.get(graph2);
1164
+ if (registrar === void 0) throw new Error("restoreGraph: unknown graph restore registrar");
1165
+ return registrar.stateNode(id, opts);
1166
+ }
1167
+ function restoreNodeInGraph(graph2, id, factory, deps, fn, opts = {}) {
1168
+ const registrar = restoreRegistrars.get(graph2);
1169
+ if (registrar === void 0) throw new Error("restoreGraph: unknown graph restore registrar");
1170
+ return registrar.node(id, factory, deps, fn, opts);
1171
+ }
1172
+
1173
+ export {
1174
+ GRAPH_BLUEPRINT_VERSION,
1175
+ normalizeTopology,
1176
+ canonicalTopologyJson,
1177
+ canonicalTopologyBytes,
1178
+ withBlueprintHash,
1179
+ withBlueprintProvenance,
1180
+ graphBlueprintDiagnostics,
1181
+ assertGraphLocalNode,
1182
+ StateNode,
1183
+ Graph,
1184
+ graph,
1185
+ releaseGraphNodes,
1186
+ restoreStateNodeInGraph,
1187
+ restoreNodeInGraph
1188
+ };
1189
+ //# sourceMappingURL=chunk-2ILL7HQI.js.map