@graphrefly/graphrefly 0.6.0 → 0.7.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 (75) hide show
  1. package/README.md +30 -14
  2. package/dist/{chunk-5X3LAO3B.js → chunk-3EVXOI5C.js} +50 -5
  3. package/dist/chunk-3EVXOI5C.js.map +1 -0
  4. package/dist/chunk-47YJEZUJ.js +106 -0
  5. package/dist/chunk-47YJEZUJ.js.map +1 -0
  6. package/dist/{chunk-6W5SGIGB.js → chunk-BLCXEMAD.js} +129 -25
  7. package/dist/chunk-BLCXEMAD.js.map +1 -0
  8. package/dist/{chunk-QW7H3ICI.js → chunk-FGLZ5QID.js} +4 -4
  9. package/dist/{chunk-CP6MNKAA.js → chunk-ISGMZ2T3.js} +10 -4
  10. package/dist/{chunk-CP6MNKAA.js.map → chunk-ISGMZ2T3.js.map} +1 -1
  11. package/dist/{chunk-HP7OKEOE.js → chunk-L4J2K2RT.js} +3 -3
  12. package/dist/chunk-L4J2K2RT.js.map +1 -0
  13. package/dist/{chunk-V3UACY6A.js → chunk-ONLYF6GA.js} +790 -203
  14. package/dist/chunk-ONLYF6GA.js.map +1 -0
  15. package/dist/{chunk-Z4Y4FMQN.js → chunk-OSR3G3DP.js} +7 -7
  16. package/dist/{chunk-KWXPDASV.js → chunk-PEBORXRA.js} +2 -2
  17. package/dist/chunk-WZ2Z2CRV.js +32 -0
  18. package/dist/chunk-WZ2Z2CRV.js.map +1 -0
  19. package/dist/compat/nestjs/index.cjs +226 -41
  20. package/dist/compat/nestjs/index.cjs.map +1 -1
  21. package/dist/compat/nestjs/index.d.cts +4 -4
  22. package/dist/compat/nestjs/index.d.ts +4 -4
  23. package/dist/compat/nestjs/index.js +8 -7
  24. package/dist/core/index.cjs +134 -20
  25. package/dist/core/index.cjs.map +1 -1
  26. package/dist/core/index.d.cts +2 -2
  27. package/dist/core/index.d.ts +2 -2
  28. package/dist/core/index.js +10 -4
  29. package/dist/extra/index.cjs +863 -206
  30. package/dist/extra/index.cjs.map +1 -1
  31. package/dist/extra/index.d.cts +4 -4
  32. package/dist/extra/index.d.ts +4 -4
  33. package/dist/extra/index.js +22 -3
  34. package/dist/graph/index.cjs +226 -41
  35. package/dist/graph/index.cjs.map +1 -1
  36. package/dist/graph/index.d.cts +3 -3
  37. package/dist/graph/index.d.ts +3 -3
  38. package/dist/graph/index.js +4 -4
  39. package/dist/{graph-CL_ZDAj9.d.cts → graph-B3BoJjcb.d.cts} +58 -7
  40. package/dist/{graph-D18qmsNm.d.ts → graph-CmiUuhaN.d.ts} +58 -7
  41. package/dist/{index-B7eOdgEx.d.ts → index-Bf2X1YSI.d.ts} +3 -3
  42. package/dist/{index-BvhgZRHK.d.cts → index-Bl7hJcc3.d.cts} +4 -2
  43. package/dist/{index-Bvy_6CaN.d.ts → index-BrgtEG-C.d.ts} +47 -4
  44. package/dist/{index-D_geH2Bm.d.cts → index-BsuKSs4L.d.cts} +3 -3
  45. package/dist/{index-BtK55IE2.d.ts → index-CsUq2rrK.d.ts} +4 -2
  46. package/dist/{index-C3BMRmmp.d.cts → index-D0cx-Yht.d.cts} +3 -3
  47. package/dist/{index-Bk_idZm1.d.cts → index-D1hgSTzr.d.cts} +406 -61
  48. package/dist/{index-C5mqLhMX.d.cts → index-D8NIq6om.d.cts} +47 -4
  49. package/dist/{index-CP_QvbWu.d.ts → index-DFFNKYig.d.ts} +3 -3
  50. package/dist/{index-B2jmzVxL.d.ts → index-Pm68AYPh.d.ts} +406 -61
  51. package/dist/index.cjs +2929 -1775
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +112 -14
  54. package/dist/index.d.ts +112 -14
  55. package/dist/index.js +392 -27
  56. package/dist/index.js.map +1 -1
  57. package/dist/{meta-BsF6Sag9.d.cts → meta-BJEU8fYz.d.cts} +31 -4
  58. package/dist/{meta-BsF6Sag9.d.ts → meta-BJEU8fYz.d.ts} +31 -4
  59. package/dist/patterns/reactive-layout/index.cjs +226 -41
  60. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  61. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  62. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  63. package/dist/patterns/reactive-layout/index.js +4 -4
  64. package/dist/{reactive-log-BfvfNWQh.d.cts → reactive-log-CAXzJ7hw.d.cts} +2 -2
  65. package/dist/{reactive-log-ohLmTXoZ.d.ts → reactive-log-DwNhOe0g.d.ts} +2 -2
  66. package/package.json +29 -18
  67. package/dist/chunk-5X3LAO3B.js.map +0 -1
  68. package/dist/chunk-6W5SGIGB.js.map +0 -1
  69. package/dist/chunk-HP7OKEOE.js.map +0 -1
  70. package/dist/chunk-O3PI7W45.js +0 -68
  71. package/dist/chunk-O3PI7W45.js.map +0 -1
  72. package/dist/chunk-V3UACY6A.js.map +0 -1
  73. /package/dist/{chunk-QW7H3ICI.js.map → chunk-FGLZ5QID.js.map} +0 -0
  74. /package/dist/{chunk-Z4Y4FMQN.js.map → chunk-OSR3G3DP.js.map} +0 -0
  75. /package/dist/{chunk-KWXPDASV.js.map → chunk-PEBORXRA.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Graph
3
- } from "./chunk-6W5SGIGB.js";
3
+ } from "./chunk-BLCXEMAD.js";
4
4
  import {
5
5
  DATA,
6
6
  INVALIDATE,
@@ -10,7 +10,7 @@ import {
10
10
  emitWithBatch,
11
11
  monotonicNs,
12
12
  state
13
- } from "./chunk-5X3LAO3B.js";
13
+ } from "./chunk-3EVXOI5C.js";
14
14
 
15
15
  // src/patterns/reactive-layout/index.ts
16
16
  var reactive_layout_exports = {};
@@ -1077,16 +1077,16 @@ function reactiveBlockLayout(opts) {
1077
1077
  }
1078
1078
 
1079
1079
  export {
1080
+ analyzeAndMeasure,
1081
+ computeLineBreaks,
1082
+ computeCharPositions,
1083
+ reactiveLayout,
1080
1084
  CliMeasureAdapter,
1081
1085
  PrecomputedAdapter,
1082
1086
  CanvasMeasureAdapter,
1083
1087
  NodeCanvasMeasureAdapter,
1084
1088
  SvgBoundsAdapter,
1085
1089
  ImageSizeAdapter,
1086
- analyzeAndMeasure,
1087
- computeLineBreaks,
1088
- computeCharPositions,
1089
- reactiveLayout,
1090
1090
  measureBlock,
1091
1091
  measureBlocks,
1092
1092
  computeBlockFlow,
@@ -1094,4 +1094,4 @@ export {
1094
1094
  reactiveBlockLayout,
1095
1095
  reactive_layout_exports
1096
1096
  };
1097
- //# sourceMappingURL=chunk-Z4Y4FMQN.js.map
1097
+ //# sourceMappingURL=chunk-OSR3G3DP.js.map
@@ -11,7 +11,7 @@ import {
11
11
  producer,
12
12
  state,
13
13
  wallClockNs
14
- } from "./chunk-5X3LAO3B.js";
14
+ } from "./chunk-3EVXOI5C.js";
15
15
 
16
16
  // src/extra/observable.ts
17
17
  import { Observable } from "rxjs";
@@ -778,4 +778,4 @@ export {
778
778
  reactiveLog,
779
779
  logSlice
780
780
  };
781
- //# sourceMappingURL=chunk-KWXPDASV.js.map
781
+ //# sourceMappingURL=chunk-PEBORXRA.js.map
@@ -0,0 +1,32 @@
1
+ // src/core/timer.ts
2
+ var ResettableTimer = class {
3
+ _timer;
4
+ _gen = 0;
5
+ /** Schedule callback after delayMs. Cancels any pending timer. */
6
+ start(delayMs, callback) {
7
+ this.cancel();
8
+ this._gen += 1;
9
+ const gen = this._gen;
10
+ this._timer = setTimeout(() => {
11
+ this._timer = void 0;
12
+ if (gen !== this._gen) return;
13
+ callback();
14
+ }, delayMs);
15
+ }
16
+ /** Cancel the pending timer (if any). */
17
+ cancel() {
18
+ if (this._timer !== void 0) {
19
+ clearTimeout(this._timer);
20
+ this._timer = void 0;
21
+ }
22
+ }
23
+ /** Whether a timer is currently pending. */
24
+ get pending() {
25
+ return this._timer !== void 0;
26
+ }
27
+ };
28
+
29
+ export {
30
+ ResettableTimer
31
+ };
32
+ //# sourceMappingURL=chunk-WZ2Z2CRV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/timer.ts"],"sourcesContent":["/**\n * Creates a resettable deadline timer for internal timeout, retry, and rate-limiting use.\n *\n * @remarks **Centralised primitive:** wraps `setTimeout`/`clearTimeout` with a generation guard\n * so that stale callbacks never fire after `cancel()` or a new `start()`.\n *\n * @remarks **Spec §5.10 exception:** resilience operators (`timeout`, `retry`, `rateLimiter`)\n * need raw timers — `fromTimer` creates a new Node per reset, which is too heavy here.\n *\n * @example\n * ```ts\n * import { ResettableTimer } from \"@graphrefly/graphrefly-ts\";\n *\n * const timer = new ResettableTimer();\n * timer.start(1000, () => console.log(\"fired\"));\n * timer.cancel(); // cancels before firing\n * timer.start(500, () => console.log(\"new deadline\"));\n * console.log(timer.pending); // true\n * ```\n *\n * @category core\n */\nexport class ResettableTimer {\n\tprivate _timer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _gen = 0;\n\n\t/** Schedule callback after delayMs. Cancels any pending timer. */\n\tstart(delayMs: number, callback: () => void): void {\n\t\tthis.cancel();\n\t\tthis._gen += 1;\n\t\tconst gen = this._gen;\n\t\tthis._timer = setTimeout(() => {\n\t\t\tthis._timer = undefined;\n\t\t\tif (gen !== this._gen) return;\n\t\t\tcallback();\n\t\t}, delayMs);\n\t}\n\n\t/** Cancel the pending timer (if any). */\n\tcancel(): void {\n\t\tif (this._timer !== undefined) {\n\t\t\tclearTimeout(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\t/** Whether a timer is currently pending. */\n\tget pending(): boolean {\n\t\treturn this._timer !== undefined;\n\t}\n}\n"],"mappings":";AAsBO,IAAM,kBAAN,MAAsB;AAAA,EACpB;AAAA,EACA,OAAO;AAAA;AAAA,EAGf,MAAM,SAAiB,UAA4B;AAClD,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,UAAM,MAAM,KAAK;AACjB,SAAK,SAAS,WAAW,MAAM;AAC9B,WAAK,SAAS;AACd,UAAI,QAAQ,KAAK,KAAM;AACvB,eAAS;AAAA,IACV,GAAG,OAAO;AAAA,EACX;AAAA;AAAA,EAGA,SAAe;AACd,QAAI,KAAK,WAAW,QAAW;AAC9B,mBAAa,KAAK,MAAM;AACxB,WAAK,SAAS;AAAA,IACf;AAAA,EACD;AAAA;AAAA,EAGA,IAAI,UAAmB;AACtB,WAAO,KAAK,WAAW;AAAA,EACxB;AACD;","names":[]}
@@ -447,10 +447,14 @@ function partitionForBatch(messages) {
447
447
  }
448
448
  return { immediate, deferred, terminal };
449
449
  }
450
- function emitWithBatch(emit, messages, phase = 2) {
450
+ function emitWithBatch(emit, messages, phase = 2, options) {
451
451
  if (messages.length === 0) {
452
452
  return;
453
453
  }
454
+ if (options?.strategy === "sequential") {
455
+ _emitSequential(emit, messages, phase);
456
+ return;
457
+ }
454
458
  const queue = phase === 3 ? pendingPhase3 : pendingPhase2;
455
459
  if (messages.length === 1) {
456
460
  const t = messages[0][0];
@@ -491,6 +495,29 @@ function emitWithBatch(emit, messages, phase = 2) {
491
495
  }
492
496
  }
493
497
  }
498
+ function _emitSequential(emit, messages, phase = 2) {
499
+ const dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;
500
+ for (const msg of messages) {
501
+ const tier = messageTier(msg[0]);
502
+ if (tier === 2) {
503
+ if (isBatching()) {
504
+ const m = msg;
505
+ dataQueue.push(() => emit([m]));
506
+ } else {
507
+ emit([msg]);
508
+ }
509
+ } else if (tier >= 3) {
510
+ if (isBatching()) {
511
+ const m = msg;
512
+ pendingPhase3.push(() => emit([m]));
513
+ } else {
514
+ emit([msg]);
515
+ }
516
+ } else {
517
+ emit([msg]);
518
+ }
519
+ }
520
+ }
494
521
 
495
522
  // src/core/guard.ts
496
523
  var GuardDenied = class extends Error {
@@ -721,6 +748,7 @@ var NodeImpl = class {
721
748
  _producerStarted = false;
722
749
  _connecting = false;
723
750
  _manualEmitUsed = false;
751
+ _hasEmittedData = false;
724
752
  _sinkCount = 0;
725
753
  _singleDepSinkCount = 0;
726
754
  // --- Object/collection state ---
@@ -1007,6 +1035,7 @@ var NodeImpl = class {
1007
1035
  this._cleanup = void 0;
1008
1036
  cleanupFn?.();
1009
1037
  this._cached = void 0;
1038
+ this._hasEmittedData = false;
1010
1039
  this._lastDepValues = void 0;
1011
1040
  }
1012
1041
  this._status = statusAfterMessage(this._status, m);
@@ -1016,6 +1045,7 @@ var NodeImpl = class {
1016
1045
  if (t === TEARDOWN) {
1017
1046
  if (this._opts.resetOnTeardown) {
1018
1047
  this._cached = void 0;
1048
+ this._hasEmittedData = false;
1019
1049
  }
1020
1050
  const teardownCleanup = this._cleanup;
1021
1051
  this._cleanup = void 0;
@@ -1046,7 +1076,16 @@ var NodeImpl = class {
1046
1076
  }
1047
1077
  _emitAutoValue(value) {
1048
1078
  const wasDirty = this._status === "dirty";
1049
- const unchanged = this._equals(this._cached, value);
1079
+ let unchanged;
1080
+ try {
1081
+ unchanged = this._hasEmittedData && this._equals(this._cached, value);
1082
+ } catch (eqErr) {
1083
+ const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
1084
+ const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
1085
+ this._downInternal([[ERROR, wrapped]]);
1086
+ return;
1087
+ }
1088
+ this._hasEmittedData = true;
1050
1089
  if (unchanged) {
1051
1090
  this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
1052
1091
  return;
@@ -1093,7 +1132,9 @@ var NodeImpl = class {
1093
1132
  if (out === void 0) return;
1094
1133
  this._emitAutoValue(out);
1095
1134
  } catch (err) {
1096
- this._downInternal([[ERROR, err]]);
1135
+ const errMsg = err instanceof Error ? err.message : String(err);
1136
+ const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
1137
+ this._downInternal([[ERROR, wrapped]]);
1097
1138
  }
1098
1139
  }
1099
1140
  _onDepDirty(index) {
@@ -1128,7 +1169,11 @@ var NodeImpl = class {
1128
1169
  try {
1129
1170
  if (this._onMessage(msg, index, this._actions)) continue;
1130
1171
  } catch (err) {
1131
- this._downInternal([[ERROR, err]]);
1172
+ const errMsg = err instanceof Error ? err.message : String(err);
1173
+ const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
1174
+ cause: err
1175
+ });
1176
+ this._downInternal([[ERROR, wrapped]]);
1132
1177
  return;
1133
1178
  }
1134
1179
  }
@@ -2527,6 +2572,19 @@ var DynamicNodeImpl = class {
2527
2572
  };
2528
2573
 
2529
2574
  // src/core/meta.ts
2575
+ function resolveDescribeFields(detail, fields) {
2576
+ if (fields != null && fields.length > 0) return new Set(fields);
2577
+ switch (detail) {
2578
+ case "standard":
2579
+ return /* @__PURE__ */ new Set(["type", "status", "value", "deps", "meta", "v"]);
2580
+ case "full":
2581
+ return null;
2582
+ // null = include everything
2583
+ case "minimal":
2584
+ default:
2585
+ return /* @__PURE__ */ new Set(["type", "deps"]);
2586
+ }
2587
+ }
2530
2588
  function inferDescribeType(n) {
2531
2589
  if (n._describeKind != null) return n._describeKind;
2532
2590
  if (!n._hasDeps) return n._fn != null ? "producer" : "state";
@@ -2544,12 +2602,10 @@ function metaSnapshot(node2) {
2544
2602
  }
2545
2603
  return out;
2546
2604
  }
2547
- function describeNode(node2) {
2548
- const meta = { ...metaSnapshot(node2) };
2549
- const guard = node2 instanceof NodeImpl && node2._guard || node2 instanceof DynamicNodeImpl && node2._guard || void 0;
2550
- if (guard != null && meta.access === void 0) {
2551
- meta.access = accessHintForGuard(guard);
2552
- }
2605
+ function describeNode(node2, includeFields) {
2606
+ const all = includeFields == null;
2607
+ const metaKeys = !all && includeFields != null ? [...includeFields].filter((f) => f.startsWith("meta.")).map((f) => f.slice(5)) : null;
2608
+ const wantsMeta = all || includeFields.has("meta") || metaKeys != null && metaKeys.length > 0;
2553
2609
  let type = "state";
2554
2610
  let deps = [];
2555
2611
  if (node2 instanceof NodeImpl) {
@@ -2559,20 +2615,36 @@ function describeNode(node2) {
2559
2615
  type = node2._describeKind ?? "derived";
2560
2616
  deps = [];
2561
2617
  }
2562
- const out = {
2563
- type,
2564
- status: node2.status,
2565
- deps,
2566
- meta
2567
- };
2618
+ const out = { type, deps };
2619
+ if (all || includeFields.has("status")) {
2620
+ out.status = node2.status;
2621
+ }
2622
+ const guard = node2 instanceof NodeImpl && node2._guard || node2 instanceof DynamicNodeImpl && node2._guard || void 0;
2623
+ if (wantsMeta) {
2624
+ const rawMeta = { ...metaSnapshot(node2) };
2625
+ if (guard != null && rawMeta.access === void 0) {
2626
+ rawMeta.access = accessHintForGuard(guard);
2627
+ }
2628
+ if (metaKeys != null && metaKeys.length > 0 && !includeFields.has("meta")) {
2629
+ const filtered = {};
2630
+ for (const k of metaKeys) {
2631
+ if (k in rawMeta) filtered[k] = rawMeta[k];
2632
+ }
2633
+ out.meta = filtered;
2634
+ } else {
2635
+ out.meta = rawMeta;
2636
+ }
2637
+ }
2568
2638
  if (node2.name != null) {
2569
2639
  out.name = node2.name;
2570
2640
  }
2571
- try {
2572
- out.value = node2.get();
2573
- } catch {
2641
+ if (all || includeFields.has("value")) {
2642
+ try {
2643
+ out.value = node2.get();
2644
+ } catch {
2645
+ }
2574
2646
  }
2575
- if (node2.v != null) {
2647
+ if ((all || includeFields.has("v")) && node2.v != null) {
2576
2648
  const vInfo = { id: node2.v.id, version: node2.v.version };
2577
2649
  if ("cid" in node2.v) {
2578
2650
  vInfo.cid = node2.v.cid;
@@ -2580,6 +2652,16 @@ function describeNode(node2) {
2580
2652
  }
2581
2653
  out.v = vInfo;
2582
2654
  }
2655
+ if (all || includeFields.has("guard")) {
2656
+ if (guard != null) {
2657
+ out.guard = accessHintForGuard(guard);
2658
+ }
2659
+ }
2660
+ if (all || includeFields.has("lastMutation")) {
2661
+ if (node2.lastMutation != null) {
2662
+ out.lastMutation = node2.lastMutation;
2663
+ }
2664
+ }
2583
2665
  return out;
2584
2666
  }
2585
2667
 
@@ -2769,6 +2851,23 @@ function resolveSpyTheme(theme) {
2769
2851
  reset: theme.reset ?? ""
2770
2852
  };
2771
2853
  }
2854
+ function resolveObserveDetail(opts) {
2855
+ if (opts == null) return {};
2856
+ const detail = opts.detail;
2857
+ if (detail === "full") {
2858
+ return {
2859
+ ...opts,
2860
+ structured: opts.structured ?? true,
2861
+ timeline: opts.timeline ?? true,
2862
+ causal: opts.causal ?? true,
2863
+ derived: opts.derived ?? true
2864
+ };
2865
+ }
2866
+ if (detail === "minimal") {
2867
+ return { ...opts, structured: opts.structured ?? true };
2868
+ }
2869
+ return opts;
2870
+ }
2772
2871
  function assertLocalName(name, graphName, label) {
2773
2872
  if (name === "") {
2774
2873
  throw new Error(`Graph "${graphName}": ${label} name must be non-empty`);
@@ -2966,6 +3065,22 @@ var Graph = class _Graph {
2966
3065
  if (this._defaultVersioningLevel != null) {
2967
3066
  node2._applyVersioning(this._defaultVersioningLevel);
2968
3067
  }
3068
+ if (node2._deps.length > 0) {
3069
+ for (const dep of node2._deps) {
3070
+ for (const [depName, depNode] of this._nodes) {
3071
+ if (depNode === dep) {
3072
+ this._edges.add(edgeKey(depName, name));
3073
+ break;
3074
+ }
3075
+ }
3076
+ }
3077
+ }
3078
+ for (const [otherName, otherNode] of this._nodes) {
3079
+ if (otherName === name) continue;
3080
+ if (otherNode instanceof NodeImpl && otherNode._deps.includes(node2)) {
3081
+ this._edges.add(edgeKey(name, otherName));
3082
+ }
3083
+ }
2969
3084
  }
2970
3085
  }
2971
3086
  /**
@@ -3352,6 +3467,9 @@ var Graph = class _Graph {
3352
3467
  describe(options) {
3353
3468
  const actor = options?.actor;
3354
3469
  const filter = options?.filter;
3470
+ const includeFields = resolveDescribeFields(options?.detail, options?.fields);
3471
+ const isSpec = options?.format === "spec";
3472
+ const effectiveFields = isSpec ? resolveDescribeFields("minimal") : includeFields;
3355
3473
  const targets = [];
3356
3474
  this._collectObserveTargets("", targets);
3357
3475
  const nodeToPath = /* @__PURE__ */ new Map();
@@ -3361,7 +3479,7 @@ var Graph = class _Graph {
3361
3479
  const nodes = {};
3362
3480
  for (const [p, n] of targets) {
3363
3481
  if (actor != null && !n.allowsObserve(actor)) continue;
3364
- const raw = describeNode(n);
3482
+ const raw = describeNode(n, effectiveFields);
3365
3483
  const deps = n instanceof NodeImpl ? n._deps.map((d) => nodeToPath.get(d) ?? d.name ?? "") : [];
3366
3484
  const { name: _name, ...rest } = raw;
3367
3485
  const entry = { ...rest, deps };
@@ -3382,7 +3500,7 @@ var Graph = class _Graph {
3382
3500
  continue;
3383
3501
  }
3384
3502
  if (normalizedKey === "metaHas") {
3385
- if (!Object.hasOwn(entry.meta, String(fv))) {
3503
+ if (!Object.hasOwn(entry.meta ?? {}, String(fv))) {
3386
3504
  match = false;
3387
3505
  break;
3388
3506
  }
@@ -3415,11 +3533,24 @@ var Graph = class _Graph {
3415
3533
  const prefix = `${sg}${PATH_SEP}`;
3416
3534
  return [...nodeKeys].some((k) => k === sg || k.startsWith(prefix));
3417
3535
  }) : allSubgraphs;
3536
+ const graph = this;
3537
+ const baseOpts = options;
3418
3538
  return {
3419
3539
  name: this.name,
3420
3540
  nodes,
3421
3541
  edges,
3422
- subgraphs
3542
+ subgraphs,
3543
+ expand(detailOrFields) {
3544
+ const merged = { ...baseOpts, format: void 0 };
3545
+ if (Array.isArray(detailOrFields)) {
3546
+ merged.fields = detailOrFields;
3547
+ merged.detail = void 0;
3548
+ } else {
3549
+ merged.detail = detailOrFields;
3550
+ merged.fields = void 0;
3551
+ }
3552
+ return graph.describe(merged);
3553
+ }
3423
3554
  };
3424
3555
  }
3425
3556
  _collectSubgraphs(prefix) {
@@ -3472,14 +3603,15 @@ var Graph = class _Graph {
3472
3603
  observe(pathOrOpts, options) {
3473
3604
  if (typeof pathOrOpts === "string") {
3474
3605
  const path = pathOrOpts;
3475
- const actor2 = options?.actor;
3606
+ const resolved = resolveObserveDetail(options);
3607
+ const actor2 = resolved.actor;
3476
3608
  const target = this.resolve(path);
3477
3609
  if (actor2 != null && !target.allowsObserve(actor2)) {
3478
3610
  throw new GuardDenied({ actor: actor2, action: "observe", nodeName: path });
3479
3611
  }
3480
- const wantsStructured2 = options?.structured === true || options?.timeline === true || options?.causal === true || options?.derived === true;
3612
+ const wantsStructured2 = resolved.structured === true || resolved.timeline === true || resolved.causal === true || resolved.derived === true || resolved.detail === "minimal" || resolved.detail === "full";
3481
3613
  if (wantsStructured2 && _Graph.inspectorEnabled) {
3482
- return this._createObserveResult(path, target, options);
3614
+ return this._createObserveResult(path, target, resolved);
3483
3615
  }
3484
3616
  return {
3485
3617
  subscribe(sink) {
@@ -3495,11 +3627,11 @@ var Graph = class _Graph {
3495
3627
  }
3496
3628
  };
3497
3629
  }
3498
- const opts = pathOrOpts;
3499
- const actor = opts?.actor;
3500
- const wantsStructured = opts?.structured === true || opts?.timeline === true || opts?.causal === true || opts?.derived === true;
3630
+ const opts = resolveObserveDetail(pathOrOpts);
3631
+ const actor = opts.actor;
3632
+ const wantsStructured = opts.structured === true || opts.timeline === true || opts.causal === true || opts.derived === true || opts.detail === "minimal" || opts.detail === "full";
3501
3633
  if (wantsStructured && _Graph.inspectorEnabled) {
3502
- return this._createObserveResultForAll(opts ?? {});
3634
+ return this._createObserveResultForAll(opts);
3503
3635
  }
3504
3636
  return {
3505
3637
  subscribe: (sink) => {
@@ -3531,6 +3663,7 @@ var Graph = class _Graph {
3531
3663
  const timeline = options.timeline === true;
3532
3664
  const causal = options.causal === true;
3533
3665
  const derived2 = options.derived === true;
3666
+ const minimal = options.detail === "minimal";
3534
3667
  const result = {
3535
3668
  values: {},
3536
3669
  dirtyCount: 0,
@@ -3576,6 +3709,11 @@ var Graph = class _Graph {
3576
3709
  if (t === DATA) {
3577
3710
  result.values[path] = m[1];
3578
3711
  result.events.push({ type: "data", path, data: m[1], ...base, ...withCausal });
3712
+ } else if (minimal) {
3713
+ if (t === DIRTY) result.dirtyCount++;
3714
+ else if (t === RESOLVED) result.resolvedCount++;
3715
+ else if (t === COMPLETE && !result.errored) result.completedCleanly = true;
3716
+ else if (t === ERROR) result.errored = true;
3579
3717
  } else if (t === DIRTY) {
3580
3718
  result.dirtyCount++;
3581
3719
  result.events.push({ type: "dirty", path, ...base });
@@ -3591,6 +3729,8 @@ var Graph = class _Graph {
3591
3729
  }
3592
3730
  }
3593
3731
  });
3732
+ const graph = this;
3733
+ const basePath = path;
3594
3734
  return {
3595
3735
  get values() {
3596
3736
  return result.values;
@@ -3613,11 +3753,28 @@ var Graph = class _Graph {
3613
3753
  dispose() {
3614
3754
  unsub();
3615
3755
  detachInspectorHook?.();
3756
+ },
3757
+ expand(extra) {
3758
+ unsub();
3759
+ detachInspectorHook?.();
3760
+ const merged = { ...options };
3761
+ if (typeof extra === "string") {
3762
+ merged.detail = extra;
3763
+ } else {
3764
+ Object.assign(merged, extra);
3765
+ }
3766
+ const resolvedTarget = graph.resolve(basePath);
3767
+ return graph._createObserveResult(
3768
+ basePath,
3769
+ resolvedTarget,
3770
+ resolveObserveDetail(merged)
3771
+ );
3616
3772
  }
3617
3773
  };
3618
3774
  }
3619
3775
  _createObserveResultForAll(options) {
3620
3776
  const timeline = options.timeline === true;
3777
+ const minimal = options.detail === "minimal";
3621
3778
  const result = {
3622
3779
  values: {},
3623
3780
  dirtyCount: 0,
@@ -3639,6 +3796,11 @@ var Graph = class _Graph {
3639
3796
  if (t === DATA) {
3640
3797
  result.values[path] = m[1];
3641
3798
  result.events.push({ type: "data", path, data: m[1], ...base });
3799
+ } else if (minimal) {
3800
+ if (t === DIRTY) result.dirtyCount++;
3801
+ else if (t === RESOLVED) result.resolvedCount++;
3802
+ else if (t === COMPLETE && !result.errored) result.completedCleanly = true;
3803
+ else if (t === ERROR) result.errored = true;
3642
3804
  } else if (t === DIRTY) {
3643
3805
  result.dirtyCount++;
3644
3806
  result.events.push({ type: "dirty", path, ...base });
@@ -3655,6 +3817,7 @@ var Graph = class _Graph {
3655
3817
  }
3656
3818
  })
3657
3819
  );
3820
+ const graph = this;
3658
3821
  return {
3659
3822
  get values() {
3660
3823
  return result.values;
@@ -3676,6 +3839,16 @@ var Graph = class _Graph {
3676
3839
  },
3677
3840
  dispose() {
3678
3841
  for (const u of unsubs) u();
3842
+ },
3843
+ expand(extra) {
3844
+ for (const u of unsubs) u();
3845
+ const merged = { ...options };
3846
+ if (typeof extra === "string") {
3847
+ merged.detail = extra;
3848
+ } else {
3849
+ Object.assign(merged, extra);
3850
+ }
3851
+ return graph._createObserveResultForAll(resolveObserveDetail(merged));
3679
3852
  }
3680
3853
  };
3681
3854
  }
@@ -3751,6 +3924,9 @@ var Graph = class _Graph {
3751
3924
  },
3752
3925
  dispose() {
3753
3926
  stop2();
3927
+ },
3928
+ expand() {
3929
+ throw new Error("expand() requires inspector mode (Graph.inspectorEnabled = true)");
3754
3930
  }
3755
3931
  };
3756
3932
  const pushEvent = (path, message) => {
@@ -3851,16 +4027,16 @@ var Graph = class _Graph {
3851
4027
  * @returns Rendered graph text.
3852
4028
  */
3853
4029
  dumpGraph(options = {}) {
3854
- const described = this.describe({
4030
+ const { expand: _, ...described } = this.describe({
3855
4031
  actor: options.actor,
3856
- filter: options.filter
4032
+ filter: options.filter,
4033
+ detail: "standard"
3857
4034
  });
3858
4035
  const includeEdges = options.includeEdges ?? true;
3859
4036
  const includeSubgraphs = options.includeSubgraphs ?? true;
3860
4037
  if (options.format === "json") {
3861
4038
  const payload = {
3862
- name: described.name,
3863
- nodes: described.nodes,
4039
+ ...described,
3864
4040
  edges: includeEdges ? described.edges : [],
3865
4041
  subgraphs: includeSubgraphs ? described.subgraphs : []
3866
4042
  };
@@ -3930,10 +4106,11 @@ var Graph = class _Graph {
3930
4106
  * @returns Persistable snapshot with sorted keys.
3931
4107
  */
3932
4108
  snapshot() {
3933
- const d = this.describe();
4109
+ const { expand: _, ...d } = this.describe({ detail: "full" });
3934
4110
  const sortedNodes = {};
3935
4111
  for (const key of Object.keys(d.nodes).sort()) {
3936
- sortedNodes[key] = d.nodes[key];
4112
+ const { lastMutation: _lm, guard: _g, ...node2 } = d.nodes[key];
4113
+ sortedNodes[key] = node2;
3937
4114
  }
3938
4115
  const sortedSubgraphs = [...d.subgraphs].sort();
3939
4116
  return { ...d, version: 1, nodes: sortedNodes, subgraphs: sortedSubgraphs };
@@ -4087,16 +4264,22 @@ var Graph = class _Graph {
4087
4264
  if (!pending) return;
4088
4265
  pending = false;
4089
4266
  try {
4090
- const described = this.describe();
4267
+ const { expand: _expand, ...raw } = this.describe({ detail: "full" });
4268
+ const cleanNodes = {};
4269
+ for (const [p, n] of Object.entries(raw.nodes)) {
4270
+ const { lastMutation: _lm, guard: _g, ...node2 } = n;
4271
+ cleanNodes[p] = node2;
4272
+ }
4273
+ const described = { ...raw, nodes: cleanNodes };
4091
4274
  const snapshot = { ...described, version: SNAPSHOT_VERSION };
4092
4275
  seq += 1;
4093
4276
  const shouldCompact = lastDescribe == null || seq % compactEvery === 0;
4094
4277
  if (shouldCompact) {
4095
- adapter.save({ mode: "full", snapshot, seq });
4278
+ adapter.save(this.name, { mode: "full", snapshot, seq });
4096
4279
  } else {
4097
4280
  const previous = lastDescribe;
4098
4281
  if (previous == null) return;
4099
- adapter.save({
4282
+ adapter.save(this.name, {
4100
4283
  mode: "diff",
4101
4284
  diff: _Graph.diff(previous, described),
4102
4285
  snapshot,
@@ -4117,8 +4300,10 @@ var Graph = class _Graph {
4117
4300
  const triggeredByTier = messages.some((m) => messageTier(m[0]) >= 2);
4118
4301
  if (!triggeredByTier) return;
4119
4302
  if (options.filter) {
4120
- const described = this.describe().nodes[path];
4121
- if (described == null || !options.filter(path, described)) return;
4303
+ const nd = this.resolve(path);
4304
+ if (nd == null) return;
4305
+ const described = describeNode(nd, resolveDescribeFields("standard"));
4306
+ if (!options.filter(path, described)) return;
4122
4307
  }
4123
4308
  schedule();
4124
4309
  });