@graphrefly/graphrefly 0.17.0 → 0.19.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 (77) hide show
  1. package/dist/{chunk-R6OHUUYB.js → chunk-AHRKWMNI.js} +7 -7
  2. package/dist/chunk-AHRKWMNI.js.map +1 -0
  3. package/dist/{chunk-2PORF4RP.js → chunk-BER7UYLM.js} +27 -32
  4. package/dist/chunk-BER7UYLM.js.map +1 -0
  5. package/dist/{chunk-646OG3PO.js → chunk-IRZAGZUB.js} +51 -52
  6. package/dist/chunk-IRZAGZUB.js.map +1 -0
  7. package/dist/{chunk-IHJHBADD.js → chunk-JC2SN46B.js} +385 -197
  8. package/dist/chunk-JC2SN46B.js.map +1 -0
  9. package/dist/{chunk-XJ6EMQ22.js → chunk-OO5QOAXI.js} +4 -10
  10. package/dist/chunk-OO5QOAXI.js.map +1 -0
  11. package/dist/{chunk-YXROQFXZ.js → chunk-UW77D7SP.js} +3 -3
  12. package/dist/{chunk-F2ULI3Q3.js → chunk-XUOY3YKN.js} +7 -3
  13. package/dist/chunk-XUOY3YKN.js.map +1 -0
  14. package/dist/chunk-YLR5JUJZ.js +111 -0
  15. package/dist/chunk-YLR5JUJZ.js.map +1 -0
  16. package/dist/{chunk-BV3TPSBK.js → chunk-YXR3WW3Q.js} +740 -755
  17. package/dist/chunk-YXR3WW3Q.js.map +1 -0
  18. package/dist/compat/nestjs/index.cjs +1127 -983
  19. package/dist/compat/nestjs/index.cjs.map +1 -1
  20. package/dist/compat/nestjs/index.d.cts +4 -4
  21. package/dist/compat/nestjs/index.d.ts +4 -4
  22. package/dist/compat/nestjs/index.js +7 -13
  23. package/dist/core/index.cjs +653 -749
  24. package/dist/core/index.cjs.map +1 -1
  25. package/dist/core/index.d.cts +2 -2
  26. package/dist/core/index.d.ts +2 -2
  27. package/dist/core/index.js +7 -7
  28. package/dist/extra/index.cjs +773 -795
  29. package/dist/extra/index.cjs.map +1 -1
  30. package/dist/extra/index.d.cts +4 -4
  31. package/dist/extra/index.d.ts +4 -4
  32. package/dist/extra/index.js +5 -11
  33. package/dist/graph/index.cjs +1036 -975
  34. package/dist/graph/index.cjs.map +1 -1
  35. package/dist/graph/index.d.cts +3 -3
  36. package/dist/graph/index.d.ts +3 -3
  37. package/dist/graph/index.js +8 -8
  38. package/dist/{graph-fCsaaVIa.d.cts → graph-KsTe57nI.d.cts} +127 -51
  39. package/dist/{graph-Dc-P9BVm.d.ts → graph-mILUUqW8.d.ts} +127 -51
  40. package/dist/{index-DhXznWyH.d.ts → index-8a605sg9.d.ts} +2 -2
  41. package/dist/{index-D7y9Q8W4.d.ts → index-B2SvPEbc.d.ts} +8 -69
  42. package/dist/{index-YlOH1Gw6.d.cts → index-BBUYZfJ1.d.cts} +122 -78
  43. package/dist/{index-ClaKZFPl.d.cts → index-Bjh5C1Tp.d.cts} +38 -35
  44. package/dist/{index-DWq0P9T6.d.ts → index-BjtlNirP.d.cts} +5 -7
  45. package/dist/{index-N704txAA.d.ts → index-BnkMgNNa.d.ts} +38 -35
  46. package/dist/{index-BBVBYPxr.d.cts → index-CgSiUouz.d.ts} +5 -7
  47. package/dist/{index-BmoUvOGN.d.ts → index-CvKzv0AW.d.ts} +122 -78
  48. package/dist/{index-4OIX-q0C.d.cts → index-UudxGnzc.d.cts} +8 -69
  49. package/dist/{index-DlGMf_Qe.d.cts → index-VHA43cGP.d.cts} +2 -2
  50. package/dist/index.cjs +6146 -5725
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +617 -383
  53. package/dist/index.d.ts +617 -383
  54. package/dist/index.js +4401 -4028
  55. package/dist/index.js.map +1 -1
  56. package/dist/{meta-BV4pj9ML.d.cts → meta-BnG7XAaE.d.cts} +395 -289
  57. package/dist/{meta-BV4pj9ML.d.ts → meta-BnG7XAaE.d.ts} +395 -289
  58. package/dist/observable-C8Kx_O6k.d.cts +36 -0
  59. package/dist/observable-DcBwQY7t.d.ts +36 -0
  60. package/dist/patterns/reactive-layout/index.cjs +1037 -857
  61. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  62. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  63. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  64. package/dist/patterns/reactive-layout/index.js +4 -4
  65. package/package.json +1 -1
  66. package/dist/chunk-2PORF4RP.js.map +0 -1
  67. package/dist/chunk-646OG3PO.js.map +0 -1
  68. package/dist/chunk-BV3TPSBK.js.map +0 -1
  69. package/dist/chunk-EBNKJULL.js +0 -231
  70. package/dist/chunk-EBNKJULL.js.map +0 -1
  71. package/dist/chunk-F2ULI3Q3.js.map +0 -1
  72. package/dist/chunk-IHJHBADD.js.map +0 -1
  73. package/dist/chunk-R6OHUUYB.js.map +0 -1
  74. package/dist/chunk-XJ6EMQ22.js.map +0 -1
  75. package/dist/observable-Cz-AWhwR.d.cts +0 -42
  76. package/dist/observable-DCqlwGyl.d.ts +0 -42
  77. /package/dist/{chunk-YXROQFXZ.js.map → chunk-UW77D7SP.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  describeNode,
3
3
  resolveDescribeFields
4
- } from "./chunk-F2ULI3Q3.js";
4
+ } from "./chunk-XUOY3YKN.js";
5
5
  import {
6
6
  COMPLETE,
7
7
  DATA,
@@ -16,7 +16,130 @@ import {
16
16
  messageTier,
17
17
  monotonicNs,
18
18
  state
19
- } from "./chunk-BV3TPSBK.js";
19
+ } from "./chunk-YXR3WW3Q.js";
20
+
21
+ // src/graph/sizeof.ts
22
+ var OVERHEAD = {
23
+ object: 56,
24
+ array: 64,
25
+ string: 40,
26
+ // header; content added separately
27
+ number: 8,
28
+ boolean: 4,
29
+ null: 0,
30
+ undefined: 0,
31
+ symbol: 40,
32
+ bigint: 16,
33
+ function: 120,
34
+ map: 72,
35
+ set: 72,
36
+ mapEntry: 40,
37
+ setEntry: 24
38
+ };
39
+ function sizeof(value) {
40
+ const seen = /* @__PURE__ */ new WeakSet();
41
+ return _sizeof(value, seen);
42
+ }
43
+ function _sizeof(value, seen) {
44
+ if (value == null) return 0;
45
+ const t = typeof value;
46
+ switch (t) {
47
+ case "number":
48
+ return OVERHEAD.number;
49
+ case "boolean":
50
+ return OVERHEAD.boolean;
51
+ case "string":
52
+ return OVERHEAD.string + value.length * 2;
53
+ // UTF-16
54
+ case "bigint":
55
+ return OVERHEAD.bigint;
56
+ case "symbol":
57
+ return OVERHEAD.symbol;
58
+ case "function":
59
+ if (seen.has(value)) return 0;
60
+ seen.add(value);
61
+ return OVERHEAD.function;
62
+ case "undefined":
63
+ return 0;
64
+ }
65
+ const obj = value;
66
+ if (seen.has(obj)) return 0;
67
+ seen.add(obj);
68
+ if (obj instanceof Map) {
69
+ let size2 = OVERHEAD.map;
70
+ for (const [k, v] of obj) {
71
+ size2 += OVERHEAD.mapEntry + _sizeof(k, seen) + _sizeof(v, seen);
72
+ }
73
+ return size2;
74
+ }
75
+ if (obj instanceof Set) {
76
+ let size2 = OVERHEAD.set;
77
+ for (const v of obj) {
78
+ size2 += OVERHEAD.setEntry + _sizeof(v, seen);
79
+ }
80
+ return size2;
81
+ }
82
+ if (Array.isArray(obj)) {
83
+ let size2 = OVERHEAD.array + obj.length * 8;
84
+ for (const item of obj) {
85
+ size2 += _sizeof(item, seen);
86
+ }
87
+ return size2;
88
+ }
89
+ if (obj instanceof ArrayBuffer) return obj.byteLength;
90
+ if (ArrayBuffer.isView(obj)) return obj.byteLength;
91
+ let size = OVERHEAD.object;
92
+ const keys = Object.keys(obj);
93
+ for (const key of keys) {
94
+ size += OVERHEAD.string + key.length * 2;
95
+ size += _sizeof(obj[key], seen);
96
+ }
97
+ return size;
98
+ }
99
+
100
+ // src/graph/profile.ts
101
+ function graphProfile(graph, opts) {
102
+ const topN = opts?.topN ?? 10;
103
+ const desc = graph.describe({ detail: "standard" });
104
+ const targets = [];
105
+ if (typeof graph._collectObserveTargets === "function") {
106
+ graph._collectObserveTargets("", targets);
107
+ }
108
+ const pathToNode = /* @__PURE__ */ new Map();
109
+ for (const [p, n] of targets) {
110
+ pathToNode.set(p, n);
111
+ }
112
+ const profiles = [];
113
+ for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
114
+ const nd = pathToNode.get(path);
115
+ const impl = nd instanceof NodeImpl ? nd : null;
116
+ const valueSizeBytes = impl ? sizeof(impl.get()) : 0;
117
+ const subscriberCount = impl ? impl._sinkCount : 0;
118
+ const depCount = nodeDesc.deps?.length ?? 0;
119
+ const isOrphanEffect = nodeDesc.type === "effect" && subscriberCount === 0;
120
+ profiles.push({
121
+ path,
122
+ type: nodeDesc.type,
123
+ status: nodeDesc.status ?? "unknown",
124
+ valueSizeBytes,
125
+ subscriberCount,
126
+ depCount,
127
+ isOrphanEffect
128
+ });
129
+ }
130
+ const totalValueSizeBytes = profiles.reduce((sum, p) => sum + p.valueSizeBytes, 0);
131
+ const hotspots = [...profiles].sort((a, b) => b.valueSizeBytes - a.valueSizeBytes).slice(0, topN);
132
+ const orphanEffects = profiles.filter((p) => p.isOrphanEffect);
133
+ return {
134
+ nodeCount: profiles.length,
135
+ edgeCount: desc.edges.length,
136
+ subgraphCount: desc.subgraphs.length,
137
+ nodes: profiles,
138
+ totalValueSizeBytes,
139
+ hotspots,
140
+ orphanEffects
141
+ };
142
+ }
20
143
 
21
144
  // src/graph/graph.ts
22
145
  var PATH_SEP = "::";
@@ -160,7 +283,7 @@ var RingBuffer = class {
160
283
  return result;
161
284
  }
162
285
  };
163
- var SPY_ANSI_THEME = {
286
+ var OBSERVE_ANSI_THEME = {
164
287
  data: "\x1B[32m",
165
288
  dirty: "\x1B[33m",
166
289
  resolved: "\x1B[36m",
@@ -170,7 +293,7 @@ var SPY_ANSI_THEME = {
170
293
  path: "\x1B[90m",
171
294
  reset: "\x1B[0m"
172
295
  };
173
- var SPY_NO_COLOR_THEME = {
296
+ var OBSERVE_NO_COLOR_THEME = {
174
297
  data: "",
175
298
  dirty: "",
176
299
  resolved: "",
@@ -190,9 +313,9 @@ function describeData(value) {
190
313
  return "[unserializable]";
191
314
  }
192
315
  }
193
- function resolveSpyTheme(theme) {
194
- if (theme === "none") return SPY_NO_COLOR_THEME;
195
- if (theme === "ansi" || theme == null) return SPY_ANSI_THEME;
316
+ function resolveObserveTheme(theme) {
317
+ if (theme === "none") return OBSERVE_NO_COLOR_THEME;
318
+ if (theme === "ansi" || theme == null) return OBSERVE_ANSI_THEME;
196
319
  return {
197
320
  data: theme.data ?? "",
198
321
  dirty: theme.dirty ?? "",
@@ -930,6 +1053,16 @@ var Graph = class _Graph {
930
1053
  }
931
1054
  return out;
932
1055
  }
1056
+ /**
1057
+ * Snapshot-based resource profile: per-node stats, orphan effect detection,
1058
+ * memory hotspots. Zero runtime overhead — walks nodes on demand.
1059
+ *
1060
+ * @param opts - Optional `topN` for hotspot limit (default 10).
1061
+ * @returns Aggregate profile with per-node details, hotspots, and orphan effects.
1062
+ */
1063
+ resourceProfile(opts) {
1064
+ return graphProfile(this, opts);
1065
+ }
933
1066
  _qualifyEdgeEndpoint(part, prefix) {
934
1067
  if (part.includes(PATH_SEP)) return part;
935
1068
  return prefix === "" ? part : `${prefix}${PATH_SEP}${part}`;
@@ -963,9 +1096,13 @@ var Graph = class _Graph {
963
1096
  if (actor2 != null && !target.allowsObserve(actor2)) {
964
1097
  throw new GuardDenied({ actor: actor2, action: "observe", nodeName: path });
965
1098
  }
966
- const wantsStructured2 = resolved.structured === true || resolved.timeline === true || resolved.causal === true || resolved.derived === true || resolved.detail === "minimal" || resolved.detail === "full";
967
- if (wantsStructured2 && _Graph.inspectorEnabled) {
968
- return this._createObserveResult(path, target, resolved);
1099
+ const wantsStructured2 = resolved.structured === true || resolved.timeline === true || resolved.causal === true || resolved.derived === true || resolved.detail === "minimal" || resolved.detail === "full" || resolved.format != null;
1100
+ if (wantsStructured2) {
1101
+ const result = _Graph.inspectorEnabled ? this._createObserveResult(path, target, resolved) : this._createFallbackObserveResult(path, resolved);
1102
+ if (resolved.format != null) {
1103
+ this._attachFormatLogger(result, resolved);
1104
+ }
1105
+ return result;
969
1106
  }
970
1107
  return {
971
1108
  subscribe(sink) {
@@ -983,9 +1120,13 @@ var Graph = class _Graph {
983
1120
  }
984
1121
  const opts = resolveObserveDetail(pathOrOpts);
985
1122
  const actor = opts.actor;
986
- const wantsStructured = opts.structured === true || opts.timeline === true || opts.causal === true || opts.derived === true || opts.detail === "minimal" || opts.detail === "full";
987
- if (wantsStructured && _Graph.inspectorEnabled) {
988
- return this._createObserveResultForAll(opts);
1123
+ const wantsStructured = opts.structured === true || opts.timeline === true || opts.causal === true || opts.derived === true || opts.detail === "minimal" || opts.detail === "full" || opts.format != null;
1124
+ if (wantsStructured) {
1125
+ const result = _Graph.inspectorEnabled ? this._createObserveResultForAll(opts) : this._createFallbackObserveResultForAll(opts);
1126
+ if (opts.format != null) {
1127
+ this._attachFormatLogger(result, opts);
1128
+ }
1129
+ return result;
989
1130
  }
990
1131
  return {
991
1132
  subscribe: (sink) => {
@@ -1023,12 +1164,13 @@ var Graph = class _Graph {
1023
1164
  dirtyCount: 0,
1024
1165
  resolvedCount: 0,
1025
1166
  events: [],
1026
- completedCleanly: false,
1027
- errored: false
1167
+ anyCompletedCleanly: false,
1168
+ anyErrored: false
1028
1169
  };
1029
1170
  let lastTriggerDepIndex;
1030
1171
  let lastRunDepValues;
1031
1172
  let detachInspectorHook;
1173
+ let batchSeq = 0;
1032
1174
  if ((causal || derived) && target instanceof NodeImpl) {
1033
1175
  detachInspectorHook = target._setInspectorHook((event) => {
1034
1176
  if (event.kind === "dep_message") {
@@ -1041,15 +1183,16 @@ var Graph = class _Graph {
1041
1183
  type: "derived",
1042
1184
  path,
1043
1185
  dep_values: [...event.depValues],
1044
- ...timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching() } : {}
1186
+ ...timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching(), batch_id: batchSeq } : {}
1045
1187
  });
1046
1188
  }
1047
1189
  });
1048
1190
  }
1049
1191
  const unsub = target.subscribe((msgs) => {
1192
+ batchSeq++;
1050
1193
  for (const m of msgs) {
1051
1194
  const t = m[0];
1052
- const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching() } : {};
1195
+ const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching(), batch_id: batchSeq } : {};
1053
1196
  const withCausal = causal && lastRunDepValues != null ? (() => {
1054
1197
  const triggerDep = lastTriggerDepIndex != null && lastTriggerDepIndex >= 0 && target instanceof NodeImpl ? target._deps[lastTriggerDepIndex] : void 0;
1055
1198
  const tv = triggerDep?.v;
@@ -1066,8 +1209,8 @@ var Graph = class _Graph {
1066
1209
  } else if (minimal) {
1067
1210
  if (t === DIRTY) result.dirtyCount++;
1068
1211
  else if (t === RESOLVED) result.resolvedCount++;
1069
- else if (t === COMPLETE && !result.errored) result.completedCleanly = true;
1070
- else if (t === ERROR) result.errored = true;
1212
+ else if (t === COMPLETE && !result.anyErrored) result.anyCompletedCleanly = true;
1213
+ else if (t === ERROR) result.anyErrored = true;
1071
1214
  } else if (t === DIRTY) {
1072
1215
  result.dirtyCount++;
1073
1216
  result.events.push({ type: "dirty", path, ...base });
@@ -1075,10 +1218,10 @@ var Graph = class _Graph {
1075
1218
  result.resolvedCount++;
1076
1219
  result.events.push({ type: "resolved", path, ...base, ...withCausal });
1077
1220
  } else if (t === COMPLETE) {
1078
- if (!result.errored) result.completedCleanly = true;
1221
+ if (!result.anyErrored) result.anyCompletedCleanly = true;
1079
1222
  result.events.push({ type: "complete", path, ...base });
1080
1223
  } else if (t === ERROR) {
1081
- result.errored = true;
1224
+ result.anyErrored = true;
1082
1225
  result.events.push({ type: "error", path, data: m[1], ...base });
1083
1226
  }
1084
1227
  }
@@ -1098,11 +1241,14 @@ var Graph = class _Graph {
1098
1241
  get events() {
1099
1242
  return result.events;
1100
1243
  },
1101
- get completedCleanly() {
1102
- return result.completedCleanly;
1244
+ get anyCompletedCleanly() {
1245
+ return result.anyCompletedCleanly;
1103
1246
  },
1104
- get errored() {
1105
- return result.errored;
1247
+ get anyErrored() {
1248
+ return result.anyErrored;
1249
+ },
1250
+ get completedWithoutErrors() {
1251
+ return result.anyCompletedCleanly && !result.anyErrored;
1106
1252
  },
1107
1253
  dispose() {
1108
1254
  unsub();
@@ -1118,11 +1264,15 @@ var Graph = class _Graph {
1118
1264
  Object.assign(merged, extra);
1119
1265
  }
1120
1266
  const resolvedTarget = graph.resolve(basePath);
1121
- return graph._createObserveResult(
1267
+ const expanded = graph._createObserveResult(
1122
1268
  basePath,
1123
1269
  resolvedTarget,
1124
1270
  resolveObserveDetail(merged)
1125
1271
  );
1272
+ if (merged.format != null) {
1273
+ graph._attachFormatLogger(expanded, merged);
1274
+ }
1275
+ return expanded;
1126
1276
  }
1127
1277
  };
1128
1278
  }
@@ -1134,27 +1284,33 @@ var Graph = class _Graph {
1134
1284
  dirtyCount: 0,
1135
1285
  resolvedCount: 0,
1136
1286
  events: [],
1137
- completedCleanly: false,
1138
- errored: false
1287
+ anyCompletedCleanly: false,
1288
+ anyErrored: false
1139
1289
  };
1290
+ const nodeErrored = /* @__PURE__ */ new Set();
1140
1291
  const actor = options.actor;
1141
1292
  const targets = [];
1142
1293
  this._collectObserveTargets("", targets);
1143
1294
  targets.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
1144
1295
  const picked = actor == null ? targets : targets.filter(([, nd]) => nd.allowsObserve(actor));
1296
+ let batchSeq = 0;
1145
1297
  const unsubs = picked.map(
1146
1298
  ([path, nd]) => nd.subscribe((msgs) => {
1299
+ batchSeq++;
1147
1300
  for (const m of msgs) {
1148
1301
  const t = m[0];
1149
- const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching() } : {};
1302
+ const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching(), batch_id: batchSeq } : {};
1150
1303
  if (t === DATA) {
1151
1304
  result.values[path] = m[1];
1152
1305
  result.events.push({ type: "data", path, data: m[1], ...base });
1153
1306
  } else if (minimal) {
1154
1307
  if (t === DIRTY) result.dirtyCount++;
1155
1308
  else if (t === RESOLVED) result.resolvedCount++;
1156
- else if (t === COMPLETE && !result.errored) result.completedCleanly = true;
1157
- else if (t === ERROR) result.errored = true;
1309
+ else if (t === COMPLETE && !nodeErrored.has(path)) result.anyCompletedCleanly = true;
1310
+ else if (t === ERROR) {
1311
+ result.anyErrored = true;
1312
+ nodeErrored.add(path);
1313
+ }
1158
1314
  } else if (t === DIRTY) {
1159
1315
  result.dirtyCount++;
1160
1316
  result.events.push({ type: "dirty", path, ...base });
@@ -1162,10 +1318,11 @@ var Graph = class _Graph {
1162
1318
  result.resolvedCount++;
1163
1319
  result.events.push({ type: "resolved", path, ...base });
1164
1320
  } else if (t === COMPLETE) {
1165
- if (!result.errored) result.completedCleanly = true;
1321
+ if (!nodeErrored.has(path)) result.anyCompletedCleanly = true;
1166
1322
  result.events.push({ type: "complete", path, ...base });
1167
1323
  } else if (t === ERROR) {
1168
- result.errored = true;
1324
+ result.anyErrored = true;
1325
+ nodeErrored.add(path);
1169
1326
  result.events.push({ type: "error", path, data: m[1], ...base });
1170
1327
  }
1171
1328
  }
@@ -1185,11 +1342,14 @@ var Graph = class _Graph {
1185
1342
  get events() {
1186
1343
  return result.events;
1187
1344
  },
1188
- get completedCleanly() {
1189
- return result.completedCleanly;
1345
+ get anyCompletedCleanly() {
1346
+ return result.anyCompletedCleanly;
1190
1347
  },
1191
- get errored() {
1192
- return result.errored;
1348
+ get anyErrored() {
1349
+ return result.anyErrored;
1350
+ },
1351
+ get completedWithoutErrors() {
1352
+ return result.anyCompletedCleanly && !result.anyErrored;
1193
1353
  },
1194
1354
  dispose() {
1195
1355
  for (const u of unsubs) u();
@@ -1202,25 +1362,169 @@ var Graph = class _Graph {
1202
1362
  } else {
1203
1363
  Object.assign(merged, extra);
1204
1364
  }
1205
- return graph._createObserveResultForAll(resolveObserveDetail(merged));
1365
+ const expanded = graph._createObserveResultForAll(resolveObserveDetail(merged));
1366
+ if (merged.format != null) {
1367
+ graph._attachFormatLogger(expanded, merged);
1368
+ }
1369
+ return expanded;
1206
1370
  }
1207
1371
  };
1208
1372
  }
1209
1373
  /**
1210
- * Convenience live debugger over {@link Graph.observe}. Logs protocol events as they flow.
1211
- *
1212
- * Supports one-node (`path`) and graph-wide modes, event filtering, and JSON/pretty rendering.
1213
- * Color themes are built in (`ansi` / `none`) to avoid external dependencies.
1214
- *
1215
- * @param options - Spy configuration.
1216
- * @returns Disposable handle plus a structured observation accumulator.
1374
+ * Fallback ObserveResult for single-node when inspector is disabled but `format` is requested.
1375
+ * Subscribes to raw messages and accumulates events with timeline info.
1376
+ */
1377
+ _createFallbackObserveResult(path, options) {
1378
+ const timeline = options.timeline !== false;
1379
+ const acc = {
1380
+ values: {},
1381
+ dirtyCount: 0,
1382
+ resolvedCount: 0,
1383
+ events: [],
1384
+ anyCompletedCleanly: false,
1385
+ anyErrored: false
1386
+ };
1387
+ const target = this.resolve(path);
1388
+ let batchSeq = 0;
1389
+ const unsub = target.subscribe((msgs) => {
1390
+ batchSeq++;
1391
+ for (const m of msgs) {
1392
+ const t = m[0];
1393
+ const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching(), batch_id: batchSeq } : {};
1394
+ if (t === DATA) {
1395
+ acc.values[path] = m[1];
1396
+ acc.events.push({ type: "data", path, data: m[1], ...base });
1397
+ } else if (t === DIRTY) {
1398
+ acc.dirtyCount++;
1399
+ acc.events.push({ type: "dirty", path, ...base });
1400
+ } else if (t === RESOLVED) {
1401
+ acc.resolvedCount++;
1402
+ acc.events.push({ type: "resolved", path, ...base });
1403
+ } else if (t === COMPLETE) {
1404
+ if (!acc.anyErrored) acc.anyCompletedCleanly = true;
1405
+ acc.events.push({ type: "complete", path, ...base });
1406
+ } else if (t === ERROR) {
1407
+ acc.anyErrored = true;
1408
+ acc.events.push({ type: "error", path, data: m[1], ...base });
1409
+ }
1410
+ }
1411
+ });
1412
+ return {
1413
+ get values() {
1414
+ return acc.values;
1415
+ },
1416
+ get dirtyCount() {
1417
+ return acc.dirtyCount;
1418
+ },
1419
+ get resolvedCount() {
1420
+ return acc.resolvedCount;
1421
+ },
1422
+ get events() {
1423
+ return acc.events;
1424
+ },
1425
+ get anyCompletedCleanly() {
1426
+ return acc.anyCompletedCleanly;
1427
+ },
1428
+ get anyErrored() {
1429
+ return acc.anyErrored;
1430
+ },
1431
+ get completedWithoutErrors() {
1432
+ return acc.anyCompletedCleanly && !acc.anyErrored;
1433
+ },
1434
+ dispose() {
1435
+ unsub();
1436
+ },
1437
+ expand() {
1438
+ throw new Error("expand() requires inspector mode (Graph.inspectorEnabled = true)");
1439
+ }
1440
+ };
1441
+ }
1442
+ /**
1443
+ * Fallback ObserveResult for graph-wide when inspector is disabled but `format` is requested.
1444
+ */
1445
+ _createFallbackObserveResultForAll(options) {
1446
+ const timeline = options.timeline !== false;
1447
+ const actor = options.actor;
1448
+ const acc = {
1449
+ values: {},
1450
+ dirtyCount: 0,
1451
+ resolvedCount: 0,
1452
+ events: [],
1453
+ anyCompletedCleanly: false,
1454
+ anyErrored: false
1455
+ };
1456
+ const nodeErrored = /* @__PURE__ */ new Set();
1457
+ const targets = [];
1458
+ this._collectObserveTargets("", targets);
1459
+ targets.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
1460
+ const picked = actor == null ? targets : targets.filter(([, nd]) => nd.allowsObserve(actor));
1461
+ let batchSeq = 0;
1462
+ const unsubs = picked.map(
1463
+ ([path, nd]) => nd.subscribe((msgs) => {
1464
+ batchSeq++;
1465
+ for (const m of msgs) {
1466
+ const t = m[0];
1467
+ const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching(), batch_id: batchSeq } : {};
1468
+ if (t === DATA) {
1469
+ acc.values[path] = m[1];
1470
+ acc.events.push({ type: "data", path, data: m[1], ...base });
1471
+ } else if (t === DIRTY) {
1472
+ acc.dirtyCount++;
1473
+ acc.events.push({ type: "dirty", path, ...base });
1474
+ } else if (t === RESOLVED) {
1475
+ acc.resolvedCount++;
1476
+ acc.events.push({ type: "resolved", path, ...base });
1477
+ } else if (t === COMPLETE) {
1478
+ if (!nodeErrored.has(path)) acc.anyCompletedCleanly = true;
1479
+ acc.events.push({ type: "complete", path, ...base });
1480
+ } else if (t === ERROR) {
1481
+ acc.anyErrored = true;
1482
+ nodeErrored.add(path);
1483
+ acc.events.push({ type: "error", path, data: m[1], ...base });
1484
+ }
1485
+ }
1486
+ })
1487
+ );
1488
+ return {
1489
+ get values() {
1490
+ return acc.values;
1491
+ },
1492
+ get dirtyCount() {
1493
+ return acc.dirtyCount;
1494
+ },
1495
+ get resolvedCount() {
1496
+ return acc.resolvedCount;
1497
+ },
1498
+ get events() {
1499
+ return acc.events;
1500
+ },
1501
+ get anyCompletedCleanly() {
1502
+ return acc.anyCompletedCleanly;
1503
+ },
1504
+ get anyErrored() {
1505
+ return acc.anyErrored;
1506
+ },
1507
+ get completedWithoutErrors() {
1508
+ return acc.anyCompletedCleanly && !acc.anyErrored;
1509
+ },
1510
+ dispose() {
1511
+ for (const u of unsubs) u();
1512
+ },
1513
+ expand() {
1514
+ throw new Error("expand() requires inspector mode (Graph.inspectorEnabled = true)");
1515
+ }
1516
+ };
1517
+ }
1518
+ /**
1519
+ * Attaches a format logger to an ObserveResult, rendering events as they arrive.
1520
+ * Wraps the result's dispose to flush pending events.
1217
1521
  */
1218
- spy(options = {}) {
1522
+ _attachFormatLogger(result, options) {
1523
+ const format = options.format;
1524
+ const logger = options.logger ?? ((line) => console.log(line));
1219
1525
  const include = options.includeTypes ? new Set(options.includeTypes) : null;
1220
1526
  const exclude = options.excludeTypes ? new Set(options.excludeTypes) : null;
1221
- const theme = resolveSpyTheme(options.theme);
1222
- const format = options.format ?? "pretty";
1223
- const logger = options.logger ?? ((line) => console.log(line));
1527
+ const theme = resolveObserveTheme(options.theme);
1224
1528
  const shouldLog = (type) => {
1225
1529
  if (include?.has(type) === false) return false;
1226
1530
  if (exclude?.has(type) === true) return false;
@@ -1245,133 +1549,26 @@ var Graph = class _Graph {
1245
1549
  const batchPart = event.in_batch ? " [batch]" : "";
1246
1550
  return `${pathPart}${color}${event.type.toUpperCase()}${theme.reset}${dataPart}${triggerPart}${batchPart}`;
1247
1551
  };
1248
- if (!_Graph.inspectorEnabled) {
1249
- const timeline = options.timeline ?? true;
1250
- const acc = {
1251
- values: {},
1252
- dirtyCount: 0,
1253
- resolvedCount: 0,
1254
- events: [],
1255
- completedCleanly: false,
1256
- errored: false
1257
- };
1258
- let stop2 = () => {
1259
- };
1260
- const result2 = {
1261
- get values() {
1262
- return acc.values;
1263
- },
1264
- get dirtyCount() {
1265
- return acc.dirtyCount;
1266
- },
1267
- get resolvedCount() {
1268
- return acc.resolvedCount;
1269
- },
1270
- get events() {
1271
- return acc.events;
1272
- },
1273
- get completedCleanly() {
1274
- return acc.completedCleanly;
1275
- },
1276
- get errored() {
1277
- return acc.errored;
1278
- },
1279
- dispose() {
1280
- stop2();
1281
- },
1282
- expand() {
1283
- throw new Error("expand() requires inspector mode (Graph.inspectorEnabled = true)");
1284
- }
1285
- };
1286
- const pushEvent = (path, message) => {
1287
- const t = message[0];
1288
- const base = timeline ? { timestamp_ns: monotonicNs(), in_batch: isBatching() } : {};
1289
- let event;
1290
- if (t === DATA) {
1291
- if (path != null) acc.values[path] = message[1];
1292
- event = { type: "data", ...path != null ? { path } : {}, data: message[1], ...base };
1293
- } else if (t === DIRTY) {
1294
- acc.dirtyCount += 1;
1295
- event = { type: "dirty", ...path != null ? { path } : {}, ...base };
1296
- } else if (t === RESOLVED) {
1297
- acc.resolvedCount += 1;
1298
- event = { type: "resolved", ...path != null ? { path } : {}, ...base };
1299
- } else if (t === COMPLETE) {
1300
- if (!acc.errored) acc.completedCleanly = true;
1301
- event = { type: "complete", ...path != null ? { path } : {}, ...base };
1302
- } else if (t === ERROR) {
1303
- acc.errored = true;
1304
- event = {
1305
- type: "error",
1306
- ...path != null ? { path } : {},
1307
- data: message[1],
1308
- ...base
1309
- };
1552
+ let cursor = 0;
1553
+ const flush = () => {
1554
+ const events = result.events;
1555
+ while (cursor < events.length) {
1556
+ const event = events[cursor++];
1557
+ if (shouldLog(event.type)) {
1558
+ logger(renderEvent(event), event);
1310
1559
  }
1311
- if (!event) return;
1312
- acc.events.push(event);
1313
- if (!shouldLog(event.type)) return;
1314
- logger(renderEvent(event), event);
1315
- };
1316
- if (options.path != null) {
1317
- const stream2 = this.observe(options.path, {
1318
- actor: options.actor,
1319
- structured: false
1320
- });
1321
- stop2 = stream2.subscribe((messages) => {
1322
- for (const m of messages) {
1323
- pushEvent(options.path, m);
1324
- }
1325
- });
1326
- } else {
1327
- const stream2 = this.observe({ actor: options.actor, structured: false });
1328
- stop2 = stream2.subscribe((path, messages) => {
1329
- for (const m of messages) {
1330
- pushEvent(path, m);
1331
- }
1332
- });
1333
1560
  }
1334
- return {
1335
- result: result2,
1336
- dispose() {
1337
- result2.dispose();
1338
- }
1339
- };
1340
- }
1341
- const structuredObserveOptions = {
1342
- actor: options.actor,
1343
- structured: true,
1344
- ...options.timeline !== false ? { timeline: true } : {},
1345
- ...options.causal ? { causal: true } : {},
1346
- ...options.derived ? { derived: true } : {}
1347
1561
  };
1348
- const result = options.path != null ? this.observe(options.path, structuredObserveOptions) : this.observe(structuredObserveOptions);
1349
- let cursor = 0;
1350
- const flushNewEvents = () => {
1351
- const nextEvents = result.events.slice(cursor);
1352
- cursor = result.events.length;
1353
- for (const event of nextEvents) {
1354
- if (!shouldLog(event.type)) continue;
1355
- logger(renderEvent(event), event);
1356
- }
1562
+ const origPush = result.events.push;
1563
+ result.events.push = function(...items) {
1564
+ const ret = origPush.apply(this, items);
1565
+ flush();
1566
+ return ret;
1357
1567
  };
1358
- const stream = options.path != null ? this.observe(options.path, { actor: options.actor, structured: false }) : this.observe({ actor: options.actor, structured: false });
1359
- const stop = options.path != null ? stream.subscribe((messages) => {
1360
- if (messages.length > 0) {
1361
- flushNewEvents();
1362
- }
1363
- }) : stream.subscribe((_path, messages) => {
1364
- if (messages.length > 0) {
1365
- flushNewEvents();
1366
- }
1367
- });
1368
- return {
1369
- result,
1370
- dispose() {
1371
- stop();
1372
- flushNewEvents();
1373
- result.dispose();
1374
- }
1568
+ const origDispose = result.dispose.bind(result);
1569
+ result.dispose = () => {
1570
+ origDispose();
1571
+ flush();
1375
1572
  };
1376
1573
  }
1377
1574
  /**
@@ -1634,8 +1831,9 @@ var Graph = class _Graph {
1634
1831
  /**
1635
1832
  * Debounced persistence wired to graph-wide observe stream (spec §3.8 auto-checkpoint).
1636
1833
  *
1637
- * Checkpoint trigger uses {@link messageTier}: only batches containing tier >= 2 messages
1638
- * schedule a save (`DATA`/`RESOLVED`/terminal/destruction), never pure tier-0/1 control waves.
1834
+ * Checkpoint trigger uses {@link messageTier}: only batches containing tier >= 3 messages
1835
+ * schedule a save (`DATA`/`RESOLVED`/terminal/destruction), never pure tier-0/1/2 control
1836
+ * waves (`START`/`DIRTY`/`INVALIDATE`/`PAUSE`/`RESUME`).
1639
1837
  */
1640
1838
  autoCheckpoint(adapter, options = {}) {
1641
1839
  const debounceMs = Math.max(0, options.debounceMs ?? 500);
@@ -1682,7 +1880,7 @@ var Graph = class _Graph {
1682
1880
  timer = setTimeout(flush, debounceMs);
1683
1881
  };
1684
1882
  const off = this.observe().subscribe((path, messages) => {
1685
- const triggeredByTier = messages.some((m) => messageTier(m[0]) >= 2);
1883
+ const triggeredByTier = messages.some((m) => messageTier(m[0]) >= 3);
1686
1884
  if (!triggeredByTier) return;
1687
1885
  if (options.filter) {
1688
1886
  const nd = this.resolve(path);
@@ -1766,33 +1964,21 @@ var Graph = class _Graph {
1766
1964
  // ——————————————————————————————————————————————————————————————
1767
1965
  /**
1768
1966
  * When `false`, structured observation options (`causal`, `timeline`),
1769
- * `annotate()`, and `traceLog()` are no-ops. Raw `observe()` always works.
1967
+ * and `trace()` writes are no-ops. Raw `observe()` always works.
1770
1968
  *
1771
1969
  * Default: `true` outside production (`process.env.NODE_ENV !== "production"`).
1772
1970
  */
1773
1971
  static inspectorEnabled = !(typeof process !== "undefined" && process.env?.NODE_ENV === "production");
1774
1972
  _annotations = /* @__PURE__ */ new Map();
1775
1973
  _traceRing = new RingBuffer(1e3);
1776
- /**
1777
- * Attaches a reasoning annotation to a node — captures *why* an AI agent set a value.
1778
- *
1779
- * No-op when {@link Graph.inspectorEnabled} is `false`.
1780
- *
1781
- * @param path - Qualified node path.
1782
- * @param reason - Free-text note stored in the trace ring buffer.
1783
- */
1784
- annotate(path, reason) {
1785
- if (!_Graph.inspectorEnabled) return;
1786
- this.resolve(path);
1787
- this._annotations.set(path, reason);
1788
- this._traceRing.push({ path, reason, timestamp_ns: monotonicNs() });
1789
- }
1790
- /**
1791
- * Returns a chronological log of all reasoning annotations (ring buffer).
1792
- *
1793
- * @returns `[]` when {@link Graph.inspectorEnabled} is `false`.
1794
- */
1795
- traceLog() {
1974
+ trace(path, reason) {
1975
+ if (path != null && reason != null) {
1976
+ if (!_Graph.inspectorEnabled) return;
1977
+ this.resolve(path);
1978
+ this._annotations.set(path, reason);
1979
+ this._traceRing.push({ path, reason, timestamp_ns: monotonicNs() });
1980
+ return;
1981
+ }
1796
1982
  if (!_Graph.inspectorEnabled) return [];
1797
1983
  return this._traceRing.toArray();
1798
1984
  }
@@ -1922,8 +2108,10 @@ function reachable(described, from, direction, options = {}) {
1922
2108
  }
1923
2109
 
1924
2110
  export {
2111
+ sizeof,
2112
+ graphProfile,
1925
2113
  GRAPH_META_SEGMENT,
1926
2114
  Graph,
1927
2115
  reachable
1928
2116
  };
1929
- //# sourceMappingURL=chunk-IHJHBADD.js.map
2117
+ //# sourceMappingURL=chunk-JC2SN46B.js.map