@graphrefly/graphrefly 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/ai-CaR_912Q.d.cts +1033 -0
- package/dist/ai-WlRltJV7.d.ts +1033 -0
- package/dist/audit-ClmqGOCx.d.cts +245 -0
- package/dist/audit-DRlSzBu9.d.ts +245 -0
- package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
- package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
- package/dist/chunk-APFNLIRG.js +62 -0
- package/dist/chunk-APFNLIRG.js.map +1 -0
- package/dist/chunk-AT5LKYNL.js +395 -0
- package/dist/chunk-AT5LKYNL.js.map +1 -0
- package/dist/{chunk-IAHGTNOZ.js → chunk-BQ6RQQFF.js} +351 -2095
- package/dist/chunk-BQ6RQQFF.js.map +1 -0
- package/dist/{chunk-L2GLW2U7.js → chunk-BVZYTZ5H.js} +9 -103
- package/dist/chunk-BVZYTZ5H.js.map +1 -0
- package/dist/{chunk-EVR6UFUV.js → chunk-DST5DKZS.js} +19 -15
- package/dist/{chunk-EVR6UFUV.js.map → chunk-DST5DKZS.js.map} +1 -1
- package/dist/{chunk-TKE3JGOH.js → chunk-GTE6PWRZ.js} +5 -692
- package/dist/chunk-GTE6PWRZ.js.map +1 -0
- package/dist/chunk-HXZEYDUR.js +94 -0
- package/dist/chunk-HXZEYDUR.js.map +1 -0
- package/dist/chunk-J22W6HV3.js +107 -0
- package/dist/chunk-J22W6HV3.js.map +1 -0
- package/dist/{chunk-PY4XCDLR.js → chunk-J2VBW3DZ.js} +6 -95
- package/dist/chunk-J2VBW3DZ.js.map +1 -0
- package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
- package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
- package/dist/chunk-JWBCY4NC.js +330 -0
- package/dist/chunk-JWBCY4NC.js.map +1 -0
- package/dist/chunk-K2AUJHVP.js +2251 -0
- package/dist/chunk-K2AUJHVP.js.map +1 -0
- package/dist/chunk-MJ2NKQQL.js +119 -0
- package/dist/chunk-MJ2NKQQL.js.map +1 -0
- package/dist/chunk-N6UR7YVY.js +198 -0
- package/dist/chunk-N6UR7YVY.js.map +1 -0
- package/dist/chunk-NC6S43JJ.js +456 -0
- package/dist/chunk-NC6S43JJ.js.map +1 -0
- package/dist/chunk-OFVJBJXR.js +98 -0
- package/dist/chunk-OFVJBJXR.js.map +1 -0
- package/dist/chunk-OHISZPOJ.js +97 -0
- package/dist/chunk-OHISZPOJ.js.map +1 -0
- package/dist/chunk-OU5CQKNW.js +102 -0
- package/dist/chunk-OU5CQKNW.js.map +1 -0
- package/dist/{chunk-XOFWRC73.js → chunk-PF7GRZMW.js} +316 -21
- package/dist/chunk-PF7GRZMW.js.map +1 -0
- package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
- package/dist/chunk-PHOUUNK7.js.map +1 -0
- package/dist/chunk-RNHBMHKA.js +1665 -0
- package/dist/chunk-RNHBMHKA.js.map +1 -0
- package/dist/chunk-SX52TAR4.js +110 -0
- package/dist/chunk-SX52TAR4.js.map +1 -0
- package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
- package/dist/chunk-WBZOVTYK.js +171 -0
- package/dist/chunk-WBZOVTYK.js.map +1 -0
- package/dist/chunk-WKNUIZOY.js +354 -0
- package/dist/chunk-WKNUIZOY.js.map +1 -0
- package/dist/chunk-X3VMZYBT.js +713 -0
- package/dist/chunk-X3VMZYBT.js.map +1 -0
- package/dist/chunk-X5R3GL6H.js +525 -0
- package/dist/chunk-X5R3GL6H.js.map +1 -0
- package/dist/chunk-XGPU467M.js +136 -0
- package/dist/chunk-XGPU467M.js.map +1 -0
- package/dist/compat/index.cjs +7656 -0
- package/dist/compat/index.cjs.map +1 -0
- package/dist/compat/index.d.cts +18 -0
- package/dist/compat/index.d.ts +18 -0
- package/dist/compat/index.js +50 -0
- package/dist/compat/index.js.map +1 -0
- package/dist/compat/jotai/index.cjs +2048 -0
- package/dist/compat/jotai/index.cjs.map +1 -0
- package/dist/compat/jotai/index.d.cts +2 -0
- package/dist/compat/jotai/index.d.ts +2 -0
- package/dist/compat/jotai/index.js +9 -0
- package/dist/compat/jotai/index.js.map +1 -0
- package/dist/compat/nanostores/index.cjs +2175 -0
- package/dist/compat/nanostores/index.cjs.map +1 -0
- package/dist/compat/nanostores/index.d.cts +2 -0
- package/dist/compat/nanostores/index.d.ts +2 -0
- package/dist/compat/nanostores/index.js +23 -0
- package/dist/compat/nanostores/index.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +350 -16
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +6 -6
- package/dist/compat/nestjs/index.d.ts +6 -6
- package/dist/compat/nestjs/index.js +11 -9
- package/dist/compat/react/index.cjs +141 -0
- package/dist/compat/react/index.cjs.map +1 -0
- package/dist/compat/react/index.d.cts +2 -0
- package/dist/compat/react/index.d.ts +2 -0
- package/dist/compat/react/index.js +12 -0
- package/dist/compat/react/index.js.map +1 -0
- package/dist/compat/solid/index.cjs +128 -0
- package/dist/compat/solid/index.cjs.map +1 -0
- package/dist/compat/solid/index.d.cts +2 -0
- package/dist/compat/solid/index.d.ts +2 -0
- package/dist/compat/solid/index.js +12 -0
- package/dist/compat/solid/index.js.map +1 -0
- package/dist/compat/svelte/index.cjs +131 -0
- package/dist/compat/svelte/index.cjs.map +1 -0
- package/dist/compat/svelte/index.d.cts +2 -0
- package/dist/compat/svelte/index.d.ts +2 -0
- package/dist/compat/svelte/index.js +12 -0
- package/dist/compat/svelte/index.js.map +1 -0
- package/dist/compat/vue/index.cjs +146 -0
- package/dist/compat/vue/index.cjs.map +1 -0
- package/dist/compat/vue/index.d.cts +3 -0
- package/dist/compat/vue/index.d.ts +3 -0
- package/dist/compat/vue/index.js +12 -0
- package/dist/compat/vue/index.js.map +1 -0
- package/dist/compat/zustand/index.cjs +4931 -0
- package/dist/compat/zustand/index.cjs.map +1 -0
- package/dist/compat/zustand/index.d.cts +5 -0
- package/dist/compat/zustand/index.d.ts +5 -0
- package/dist/compat/zustand/index.js +12 -0
- package/dist/compat/zustand/index.js.map +1 -0
- package/dist/composite-C7PcQvcs.d.cts +303 -0
- package/dist/composite-aUCvjZVR.d.ts +303 -0
- package/dist/core/index.cjs +53 -4
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +4 -3
- package/dist/core/index.d.ts +4 -3
- package/dist/core/index.js +26 -24
- package/dist/demo-shell-BDkOptd6.d.ts +102 -0
- package/dist/demo-shell-Crid1WdR.d.cts +102 -0
- package/dist/extra/index.cjs +222 -110
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +6 -4
- package/dist/extra/index.d.ts +6 -4
- package/dist/extra/index.js +72 -65
- package/dist/extra/sources.cjs +2486 -0
- package/dist/extra/sources.cjs.map +1 -0
- package/dist/extra/sources.d.cts +465 -0
- package/dist/extra/sources.d.ts +465 -0
- package/dist/extra/sources.js +57 -0
- package/dist/extra/sources.js.map +1 -0
- package/dist/graph/index.cjs +408 -14
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +5 -5
- package/dist/graph/index.d.ts +5 -5
- package/dist/graph/index.js +13 -5
- package/dist/{graph-D-3JIQme.d.cts → graph-CCwGKLCm.d.ts} +195 -4
- package/dist/{graph-B6NFqv3z.d.ts → graph-DNCrvZSn.d.cts} +195 -4
- package/dist/index-3lsddbbS.d.ts +86 -0
- package/dist/index-B1tloyhO.d.cts +34 -0
- package/dist/{index-CYkjxu3s.d.ts → index-B6D3QNSA.d.ts} +33 -4
- package/dist/index-B6EhDnjH.d.cts +37 -0
- package/dist/index-B9B7_HEY.d.ts +37 -0
- package/dist/{index-Ds23Wvou.d.ts → index-BHlKbUwO.d.cts} +131 -883
- package/dist/{index-DiobMNwE.d.ts → index-BPVt8kqc.d.ts} +3 -3
- package/dist/index-BaSM3aYt.d.ts +195 -0
- package/dist/index-BuEoe-Qu.d.ts +121 -0
- package/dist/{index-Ch0IpIO0.d.cts → index-BwfLUNw4.d.ts} +131 -883
- package/dist/index-ByQxazQJ.d.cts +86 -0
- package/dist/index-C0svESO4.d.ts +127 -0
- package/dist/{index-OXImXMq6.d.ts → index-C8oil6M6.d.ts} +18 -196
- package/dist/{index-DKE1EATr.d.cts → index-CI3DprxP.d.cts} +18 -196
- package/dist/{index-AMWewNDe.d.cts → index-CO8uBlUh.d.cts} +33 -4
- package/dist/index-CxFrXH4m.d.ts +45 -0
- package/dist/index-D8wS_PeY.d.cts +121 -0
- package/dist/index-DO_6JN9Z.d.cts +127 -0
- package/dist/index-DVGiGFGT.d.cts +195 -0
- package/dist/index-DYme44FM.d.cts +44 -0
- package/dist/{index-J7Kc0oIQ.d.cts → index-DlLp-2Xn.d.cts} +3 -3
- package/dist/index-Dzk2hrlR.d.ts +44 -0
- package/dist/index-VHqptjhu.d.cts +45 -0
- package/dist/index-VdHQMPy1.d.ts +36 -0
- package/dist/index-Xi3u0HCQ.d.cts +36 -0
- package/dist/index-wEn0eFe8.d.ts +34 -0
- package/dist/index.cjs +1780 -176
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +784 -2082
- package/dist/index.d.ts +784 -2082
- package/dist/index.js +955 -4349
- package/dist/index.js.map +1 -1
- package/dist/memory-C6Z2tGpC.d.cts +139 -0
- package/dist/memory-li6FL5RM.d.ts +139 -0
- package/dist/messaging-Gt4LPbyA.d.cts +269 -0
- package/dist/messaging-XDoYablx.d.ts +269 -0
- package/dist/{meta-DWbkoq1s.d.cts → meta-BxCA7rcr.d.cts} +1 -1
- package/dist/{meta-CnkLA_43.d.ts → meta-CbznRPYJ.d.ts} +1 -1
- package/dist/{node-B-f-Lu-k.d.cts → node-BmerH3kS.d.cts} +26 -1
- package/dist/{node-B-f-Lu-k.d.ts → node-BmerH3kS.d.ts} +26 -1
- package/dist/{observable-uP-wy_uK.d.ts → observable-BgGUwcqp.d.ts} +1 -1
- package/dist/{observable-DBnrwcar.d.cts → observable-DJt_AxzQ.d.cts} +1 -1
- package/dist/patterns/ai.cjs +7930 -0
- package/dist/patterns/ai.cjs.map +1 -0
- package/dist/patterns/ai.d.cts +10 -0
- package/dist/patterns/ai.d.ts +10 -0
- package/dist/patterns/ai.js +71 -0
- package/dist/patterns/ai.js.map +1 -0
- package/dist/patterns/audit.cjs +5805 -0
- package/dist/patterns/audit.cjs.map +1 -0
- package/dist/patterns/audit.d.cts +6 -0
- package/dist/patterns/audit.d.ts +6 -0
- package/dist/patterns/audit.js +29 -0
- package/dist/patterns/audit.js.map +1 -0
- package/dist/patterns/demo-shell.cjs +5604 -0
- package/dist/patterns/demo-shell.cjs.map +1 -0
- package/dist/patterns/demo-shell.d.cts +6 -0
- package/dist/patterns/demo-shell.d.ts +6 -0
- package/dist/patterns/demo-shell.js +15 -0
- package/dist/patterns/demo-shell.js.map +1 -0
- package/dist/patterns/memory.cjs +5283 -0
- package/dist/patterns/memory.cjs.map +1 -0
- package/dist/patterns/memory.d.cts +5 -0
- package/dist/patterns/memory.d.ts +5 -0
- package/dist/patterns/memory.js +20 -0
- package/dist/patterns/memory.js.map +1 -0
- package/dist/patterns/reactive-layout/index.cjs +355 -13
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +6 -5
- package/dist/patterns/reactive-layout/index.d.ts +6 -5
- package/dist/patterns/reactive-layout/index.js +15 -12
- package/dist/reactive-layout-MQP--J3F.d.cts +183 -0
- package/dist/reactive-layout-u5Ulnqag.d.ts +183 -0
- package/dist/{storage-BuTdpCI1.d.cts → storage-CMjUUuxn.d.ts} +10 -2
- package/dist/{storage-F2X1U1x0.d.ts → storage-DdWlZo6U.d.cts} +10 -2
- package/dist/sugar-CCOxXK1e.d.ts +201 -0
- package/dist/sugar-D02n5JjF.d.cts +201 -0
- package/package.json +63 -3
- package/dist/chunk-5DJTTKX3.js.map +0 -1
- package/dist/chunk-IAHGTNOZ.js.map +0 -1
- package/dist/chunk-L2GLW2U7.js.map +0 -1
- package/dist/chunk-MW4VAKAO.js +0 -47
- package/dist/chunk-MW4VAKAO.js.map +0 -1
- package/dist/chunk-PY4XCDLR.js.map +0 -1
- package/dist/chunk-TKE3JGOH.js.map +0 -1
- package/dist/chunk-XOFWRC73.js.map +0 -1
- package/dist/index-BJB7t9gg.d.cts +0 -392
- package/dist/index-C-TXEa7C.d.ts +0 -392
- /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
|
@@ -276,10 +276,6 @@ function SagaHandler(cqrsName, sagaName, eventNames) {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
// src/extra/sources.ts
|
|
280
|
-
var import_node_fs = require("fs");
|
|
281
|
-
var import_node_path = require("path");
|
|
282
|
-
|
|
283
279
|
// src/core/clock.ts
|
|
284
280
|
function monotonicNs() {
|
|
285
281
|
return Math.trunc(performance.now() * 1e6);
|
|
@@ -1142,6 +1138,12 @@ var NodeImpl = class _NodeImpl {
|
|
|
1142
1138
|
_autoError;
|
|
1143
1139
|
_pausable;
|
|
1144
1140
|
_guard;
|
|
1141
|
+
/**
|
|
1142
|
+
* @internal Additional guards stacked at runtime via {@link NodeImpl._pushGuard}
|
|
1143
|
+
* (e.g. by `policyEnforcer({ mode: "enforce" })`, roadmap §9.2). Effective
|
|
1144
|
+
* write/signal/observe checks AND the original `_guard` with every entry here.
|
|
1145
|
+
*/
|
|
1146
|
+
_extraGuards;
|
|
1145
1147
|
_hashFn;
|
|
1146
1148
|
_versioning;
|
|
1147
1149
|
/**
|
|
@@ -1315,18 +1317,61 @@ var NodeImpl = class _NodeImpl {
|
|
|
1315
1317
|
if (this._inspectorHooks?.size === 0) this._inspectorHooks = void 0;
|
|
1316
1318
|
};
|
|
1317
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* @internal Push an additional guard onto this node. Effective enforcement
|
|
1322
|
+
* is the AND of `_guard` and every guard pushed via this hook — any one
|
|
1323
|
+
* rejecting throws {@link GuardDenied}. Returns a disposer that removes
|
|
1324
|
+
* the pushed guard. Multiple guards may be stacked simultaneously.
|
|
1325
|
+
*
|
|
1326
|
+
* Used by `policyEnforcer({ mode: "enforce" })` (roadmap §9.2) to overlay
|
|
1327
|
+
* runtime constraint enforcement onto an existing graph without rebuilding
|
|
1328
|
+
* its nodes. Pre-1.0 internal API; not part of the public surface.
|
|
1329
|
+
*
|
|
1330
|
+
* **Identity semantics:** guards are tracked in a `Set`, so pushing the
|
|
1331
|
+
* same `NodeGuard` reference twice is a single registration. Wrap each
|
|
1332
|
+
* push in a unique closure if independent stacking is needed.
|
|
1333
|
+
*
|
|
1334
|
+
* **Iteration order:** insertion-ordered (`Set` semantics). Determinism
|
|
1335
|
+
* follows from single-threaded JS execution; nested re-entry from inside
|
|
1336
|
+
* a guard body (push/pop while iterating) is undefined-but-survivable.
|
|
1337
|
+
*/
|
|
1338
|
+
_pushGuard(guard) {
|
|
1339
|
+
if (this._extraGuards == null) this._extraGuards = /* @__PURE__ */ new Set();
|
|
1340
|
+
this._extraGuards.add(guard);
|
|
1341
|
+
return () => {
|
|
1342
|
+
this._extraGuards?.delete(guard);
|
|
1343
|
+
if (this._extraGuards?.size === 0) this._extraGuards = void 0;
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1318
1346
|
allowsObserve(actor) {
|
|
1319
|
-
if (this._guard == null) return true;
|
|
1320
|
-
|
|
1347
|
+
if (this._guard == null && this._extraGuards == null) return true;
|
|
1348
|
+
const a = normalizeActor(actor);
|
|
1349
|
+
if (this._guard != null && !this._guard(a, "observe")) return false;
|
|
1350
|
+
if (this._extraGuards != null) {
|
|
1351
|
+
for (const eg of this._extraGuards) {
|
|
1352
|
+
if (!eg(a, "observe")) return false;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return true;
|
|
1321
1356
|
}
|
|
1322
1357
|
// --- Guard helper ---
|
|
1323
1358
|
_checkGuard(options) {
|
|
1324
|
-
if (options?.internal
|
|
1359
|
+
if (options?.internal) return;
|
|
1360
|
+
const hasGuard = this._guard != null || this._extraGuards != null;
|
|
1361
|
+
const hasActor = options?.actor != null;
|
|
1362
|
+
if (!hasGuard && !hasActor) return;
|
|
1325
1363
|
const actor = normalizeActor(options?.actor);
|
|
1326
1364
|
const action = options?.delivery === "signal" ? "signal" : "write";
|
|
1327
|
-
if (!this._guard(actor, action)) {
|
|
1365
|
+
if (this._guard != null && !this._guard(actor, action)) {
|
|
1328
1366
|
throw new GuardDenied({ actor, action, nodeName: this.name });
|
|
1329
1367
|
}
|
|
1368
|
+
if (this._extraGuards != null) {
|
|
1369
|
+
for (const eg of this._extraGuards) {
|
|
1370
|
+
if (!eg(actor, action)) {
|
|
1371
|
+
throw new GuardDenied({ actor, action, nodeName: this.name });
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1330
1375
|
this._lastMutation = { actor, timestamp_ns: wallClockNs() };
|
|
1331
1376
|
}
|
|
1332
1377
|
// --- Public transport ---
|
|
@@ -3291,6 +3336,200 @@ var RingBuffer = class {
|
|
|
3291
3336
|
}
|
|
3292
3337
|
};
|
|
3293
3338
|
|
|
3339
|
+
// src/graph/explain.ts
|
|
3340
|
+
function explainPath(described, from, to, opts = {}) {
|
|
3341
|
+
const fromExists = from in described.nodes;
|
|
3342
|
+
const toExists = to in described.nodes;
|
|
3343
|
+
if (!fromExists) return makeFailure(from, to, "no-such-from");
|
|
3344
|
+
if (!toExists) return makeFailure(from, to, "no-such-to");
|
|
3345
|
+
const maxDepth = opts.maxDepth;
|
|
3346
|
+
if (maxDepth != null && (!Number.isInteger(maxDepth) || maxDepth < 0)) {
|
|
3347
|
+
throw new Error(`explainPath: maxDepth must be an integer >= 0`);
|
|
3348
|
+
}
|
|
3349
|
+
if (from === to) {
|
|
3350
|
+
if (opts.findCycle === true) {
|
|
3351
|
+
const cycle = findShortestCycle(described, from, opts);
|
|
3352
|
+
if (cycle != null) return cycle;
|
|
3353
|
+
}
|
|
3354
|
+
const step = buildStep(from, described.nodes[from], 0, opts);
|
|
3355
|
+
return makeSuccess(from, to, [step]);
|
|
3356
|
+
}
|
|
3357
|
+
if (maxDepth === 0) return makeFailure(from, to, "no-path");
|
|
3358
|
+
const result = bfsShortestPath(described, from, to, maxDepth);
|
|
3359
|
+
if (!result.found) {
|
|
3360
|
+
return makeFailure(from, to, result.truncated ? "max-depth-exceeded" : "no-path");
|
|
3361
|
+
}
|
|
3362
|
+
return makeSuccess(from, to, materializeSteps(described, result.pathOrder, opts));
|
|
3363
|
+
}
|
|
3364
|
+
function bfsShortestPath(described, from, to, maxDepth) {
|
|
3365
|
+
const pred = /* @__PURE__ */ new Map();
|
|
3366
|
+
const queue = [{ path: to, depth: 0 }];
|
|
3367
|
+
const visited = /* @__PURE__ */ new Set([to]);
|
|
3368
|
+
let head = 0;
|
|
3369
|
+
let truncated = false;
|
|
3370
|
+
while (head < queue.length) {
|
|
3371
|
+
const cur = queue[head++];
|
|
3372
|
+
if (cur.path === from) break;
|
|
3373
|
+
if (maxDepth != null && cur.depth >= maxDepth) {
|
|
3374
|
+
const node3 = described.nodes[cur.path];
|
|
3375
|
+
if (node3?.deps && node3.deps.length > 0) truncated = true;
|
|
3376
|
+
continue;
|
|
3377
|
+
}
|
|
3378
|
+
const node2 = described.nodes[cur.path];
|
|
3379
|
+
if (node2 == null) continue;
|
|
3380
|
+
const deps = node2.deps ?? [];
|
|
3381
|
+
const slots = /* @__PURE__ */ new Map();
|
|
3382
|
+
for (let i = 0; i < deps.length; i++) {
|
|
3383
|
+
const dep = deps[i];
|
|
3384
|
+
if (!dep) continue;
|
|
3385
|
+
let arr = slots.get(dep);
|
|
3386
|
+
if (arr == null) {
|
|
3387
|
+
arr = [];
|
|
3388
|
+
slots.set(dep, arr);
|
|
3389
|
+
}
|
|
3390
|
+
arr.push(i);
|
|
3391
|
+
}
|
|
3392
|
+
for (const [dep, indices] of slots) {
|
|
3393
|
+
if (visited.has(dep)) continue;
|
|
3394
|
+
visited.add(dep);
|
|
3395
|
+
pred.set(dep, { from: cur.path, depIndices: indices });
|
|
3396
|
+
queue.push({ path: dep, depth: cur.depth + 1 });
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
if (!pred.has(from)) {
|
|
3400
|
+
return { found: false, pathOrder: [], truncated };
|
|
3401
|
+
}
|
|
3402
|
+
const pathOrder = [{ path: from }];
|
|
3403
|
+
let cursor = from;
|
|
3404
|
+
while (cursor !== to) {
|
|
3405
|
+
const p = pred.get(cursor);
|
|
3406
|
+
if (p == null) return { found: false, pathOrder: [], truncated: false };
|
|
3407
|
+
pathOrder[pathOrder.length - 1].depIndices = p.depIndices;
|
|
3408
|
+
pathOrder.push({ path: p.from });
|
|
3409
|
+
cursor = p.from;
|
|
3410
|
+
}
|
|
3411
|
+
return { found: true, pathOrder, truncated: false };
|
|
3412
|
+
}
|
|
3413
|
+
function findShortestCycle(described, start, opts) {
|
|
3414
|
+
const startNode = described.nodes[start];
|
|
3415
|
+
if (startNode == null) return null;
|
|
3416
|
+
const startDeps = startNode.deps ?? [];
|
|
3417
|
+
const selfSlots = [];
|
|
3418
|
+
for (let i = 0; i < startDeps.length; i++) if (startDeps[i] === start) selfSlots.push(i);
|
|
3419
|
+
if (selfSlots.length > 0) {
|
|
3420
|
+
const step0 = buildStep(start, startNode, 0, opts);
|
|
3421
|
+
step0.dep_index = selfSlots[0];
|
|
3422
|
+
const step1 = buildStep(start, startNode, 1, opts);
|
|
3423
|
+
return makeSuccess(start, start, [step0, step1]);
|
|
3424
|
+
}
|
|
3425
|
+
let best = null;
|
|
3426
|
+
for (let i = 0; i < startDeps.length; i++) {
|
|
3427
|
+
const dep = startDeps[i];
|
|
3428
|
+
if (!dep || dep === start) continue;
|
|
3429
|
+
const sub = bfsShortestPath(described, dep, start, opts.maxDepth);
|
|
3430
|
+
if (!sub.found) continue;
|
|
3431
|
+
if (best == null || sub.pathOrder.length < best.pathOrder.length) {
|
|
3432
|
+
best = sub;
|
|
3433
|
+
best = {
|
|
3434
|
+
found: true,
|
|
3435
|
+
pathOrder: [{ path: start, depIndices: [i] }, ...sub.pathOrder],
|
|
3436
|
+
truncated: false
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
if (best == null) return null;
|
|
3441
|
+
return makeSuccess(start, start, materializeSteps(described, best.pathOrder, opts));
|
|
3442
|
+
}
|
|
3443
|
+
function materializeSteps(described, pathOrder, opts) {
|
|
3444
|
+
return pathOrder.map((entry, i) => {
|
|
3445
|
+
const node2 = described.nodes[entry.path];
|
|
3446
|
+
const step = buildStep(entry.path, node2, i, opts);
|
|
3447
|
+
if (entry.depIndices != null && entry.depIndices.length > 0) {
|
|
3448
|
+
step.dep_index = entry.depIndices[0];
|
|
3449
|
+
if (entry.depIndices.length > 1) step.dep_indices = [...entry.depIndices];
|
|
3450
|
+
}
|
|
3451
|
+
return step;
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
function buildStep(path, node2, hop, opts) {
|
|
3455
|
+
const step = {
|
|
3456
|
+
path,
|
|
3457
|
+
type: node2.type,
|
|
3458
|
+
hop
|
|
3459
|
+
};
|
|
3460
|
+
if (node2.status !== void 0) step.status = node2.status;
|
|
3461
|
+
if ("value" in node2) step.value = node2.value;
|
|
3462
|
+
if (node2.v != null) step.v = node2.v;
|
|
3463
|
+
const annotation = opts.annotations?.get(path) ?? node2.reason;
|
|
3464
|
+
if (annotation != null) step.reason = annotation;
|
|
3465
|
+
const lastMutation = opts.lastMutations?.get(path) ?? node2.lastMutation;
|
|
3466
|
+
if (lastMutation != null) step.lastMutation = lastMutation;
|
|
3467
|
+
return step;
|
|
3468
|
+
}
|
|
3469
|
+
function makeSuccess(from, to, steps) {
|
|
3470
|
+
return finalize(from, to, true, "ok", steps);
|
|
3471
|
+
}
|
|
3472
|
+
function makeFailure(from, to, reason) {
|
|
3473
|
+
return finalize(from, to, false, reason, []);
|
|
3474
|
+
}
|
|
3475
|
+
function finalize(from, to, found, reason, steps) {
|
|
3476
|
+
const text = renderChain(from, to, found, reason, steps);
|
|
3477
|
+
return {
|
|
3478
|
+
from,
|
|
3479
|
+
to,
|
|
3480
|
+
found,
|
|
3481
|
+
reason,
|
|
3482
|
+
steps,
|
|
3483
|
+
text,
|
|
3484
|
+
toJSON() {
|
|
3485
|
+
return { from, to, found, reason, steps };
|
|
3486
|
+
}
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
function renderChain(from, to, found, reason, steps) {
|
|
3490
|
+
if (!found) {
|
|
3491
|
+
switch (reason) {
|
|
3492
|
+
case "no-such-from":
|
|
3493
|
+
return `explainPath: no node named "${from}"`;
|
|
3494
|
+
case "no-such-to":
|
|
3495
|
+
return `explainPath: no node named "${to}"`;
|
|
3496
|
+
case "max-depth-exceeded":
|
|
3497
|
+
return `explainPath: no path from "${from}" to "${to}" within maxDepth`;
|
|
3498
|
+
default:
|
|
3499
|
+
return `explainPath: no path from "${from}" to "${to}"`;
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
const lines = [`Causal path: ${from} \u2192 ${to} (${steps.length} step(s))`];
|
|
3503
|
+
for (const step of steps) {
|
|
3504
|
+
const arrow = step.hop === 0 ? "\xB7" : "\u2193";
|
|
3505
|
+
const head = ` ${arrow} ${step.path} (${step.type}${step.status ? `/${step.status}` : ""})`;
|
|
3506
|
+
lines.push(head);
|
|
3507
|
+
if ("value" in step) {
|
|
3508
|
+
lines.push(` value: ${formatValue(step.value)}`);
|
|
3509
|
+
}
|
|
3510
|
+
if (step.reason != null) {
|
|
3511
|
+
lines.push(` reason: ${step.reason}`);
|
|
3512
|
+
}
|
|
3513
|
+
if (step.lastMutation != null) {
|
|
3514
|
+
const a = step.lastMutation.actor;
|
|
3515
|
+
lines.push(` actor: ${a.type}${a.id ? `:${a.id}` : ""}`);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
return lines.join("\n");
|
|
3519
|
+
}
|
|
3520
|
+
function formatValue(v) {
|
|
3521
|
+
if (v === void 0) return "<sentinel>";
|
|
3522
|
+
if (v === null) return "null";
|
|
3523
|
+
if (typeof v === "string") return JSON.stringify(v);
|
|
3524
|
+
if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
|
|
3525
|
+
try {
|
|
3526
|
+
const s = JSON.stringify(v);
|
|
3527
|
+
return s.length > 80 ? `${s.slice(0, 77)}...` : s;
|
|
3528
|
+
} catch {
|
|
3529
|
+
return String(v);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3294
3533
|
// src/extra/utils/sizeof.ts
|
|
3295
3534
|
var OVERHEAD = {
|
|
3296
3535
|
object: 56,
|
|
@@ -3924,6 +4163,20 @@ var Graph = class _Graph {
|
|
|
3924
4163
|
_parent = void 0;
|
|
3925
4164
|
_storageDisposers = /* @__PURE__ */ new Set();
|
|
3926
4165
|
_disposers = /* @__PURE__ */ new Set();
|
|
4166
|
+
/**
|
|
4167
|
+
* @internal Lazy `TopologyEvent` producer. Created on first `.topology`
|
|
4168
|
+
* access. Zero cost until something subscribes — producer fn only runs when
|
|
4169
|
+
* the first sink attaches, registering one handler into
|
|
4170
|
+
* {@link Graph._topologyEmitters}.
|
|
4171
|
+
*/
|
|
4172
|
+
_topology;
|
|
4173
|
+
/**
|
|
4174
|
+
* @internal Active emit handlers for the topology producer. Each entry is
|
|
4175
|
+
* the closure registered by the producer fn on activation; cleared on
|
|
4176
|
+
* deactivation. `_emitTopology` broadcasts through every entry (there is at
|
|
4177
|
+
* most one per activation cycle of the producer).
|
|
4178
|
+
*/
|
|
4179
|
+
_topologyEmitters = /* @__PURE__ */ new Set();
|
|
3927
4180
|
/**
|
|
3928
4181
|
* @param name - Non-empty graph id (must not contain `::` and must not
|
|
3929
4182
|
* equal the reserved meta segment `__meta__`).
|
|
@@ -3963,6 +4216,55 @@ var Graph = class _Graph {
|
|
|
3963
4216
|
return out;
|
|
3964
4217
|
}
|
|
3965
4218
|
// ——————————————————————————————————————————————————————————————
|
|
4219
|
+
// Topology companion (structural-change event stream)
|
|
4220
|
+
// ——————————————————————————————————————————————————————————————
|
|
4221
|
+
/**
|
|
4222
|
+
* Reactive stream of structural changes to this graph's own registry
|
|
4223
|
+
* (add / mount / remove). Value mutations live on `observe()`; this
|
|
4224
|
+
* companion only fires when the topology shape changes.
|
|
4225
|
+
*
|
|
4226
|
+
* Lazy: the underlying node is created on first access and activates when
|
|
4227
|
+
* something subscribes. No emission replay — late subscribers do not
|
|
4228
|
+
* receive historical events and should snapshot via {@link Graph.describe}
|
|
4229
|
+
* before listening for incremental changes. Events that fire while the
|
|
4230
|
+
* producer has zero subscribers are dropped (no retention).
|
|
4231
|
+
*
|
|
4232
|
+
* Own-graph only: a parent's `topology` does NOT emit for structural
|
|
4233
|
+
* changes inside a mounted child. Transitive consumers subscribe to each
|
|
4234
|
+
* child's topology separately (recurse through `topology`'s own "added"
|
|
4235
|
+
* events with `nodeKind: "mount"` to discover new children).
|
|
4236
|
+
*
|
|
4237
|
+
* See {@link TopologyEvent} for payload shape.
|
|
4238
|
+
*
|
|
4239
|
+
* @category observability
|
|
4240
|
+
*/
|
|
4241
|
+
get topology() {
|
|
4242
|
+
if (this._topology == null) {
|
|
4243
|
+
this._topology = producer(
|
|
4244
|
+
(actions) => {
|
|
4245
|
+
const handler = (event) => {
|
|
4246
|
+
actions.emit(event);
|
|
4247
|
+
};
|
|
4248
|
+
this._topologyEmitters.add(handler);
|
|
4249
|
+
return () => {
|
|
4250
|
+
this._topologyEmitters.delete(handler);
|
|
4251
|
+
};
|
|
4252
|
+
},
|
|
4253
|
+
{ name: `${this.name}_topology` }
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
return this._topology;
|
|
4257
|
+
}
|
|
4258
|
+
/**
|
|
4259
|
+
* @internal Fire a {@link TopologyEvent} to every active subscriber of
|
|
4260
|
+
* `this.topology`. No-op when the topology node has never been accessed or
|
|
4261
|
+
* currently has no sinks — zero cost for graphs nobody observes.
|
|
4262
|
+
*/
|
|
4263
|
+
_emitTopology(event) {
|
|
4264
|
+
if (this._topology == null || this._topologyEmitters.size === 0) return;
|
|
4265
|
+
for (const h of this._topologyEmitters) h(event);
|
|
4266
|
+
}
|
|
4267
|
+
// ——————————————————————————————————————————————————————————————
|
|
3966
4268
|
// Node registry
|
|
3967
4269
|
// ——————————————————————————————————————————————————————————————
|
|
3968
4270
|
/**
|
|
@@ -3992,6 +4294,7 @@ var Graph = class _Graph {
|
|
|
3992
4294
|
}
|
|
3993
4295
|
this._nodes.set(name, node2);
|
|
3994
4296
|
this._nodeToName.set(node2, name);
|
|
4297
|
+
this._emitTopology({ kind: "added", name, nodeKind: "node" });
|
|
3995
4298
|
return node2;
|
|
3996
4299
|
}
|
|
3997
4300
|
/**
|
|
@@ -4032,22 +4335,23 @@ var Graph = class _Graph {
|
|
|
4032
4335
|
assertRegisterableName(name, this.name, "remove");
|
|
4033
4336
|
const child = this._mounts.get(name);
|
|
4034
4337
|
if (child) {
|
|
4035
|
-
const
|
|
4338
|
+
const audit2 = { kind: "mount", nodes: [], mounts: [] };
|
|
4036
4339
|
const targets = [];
|
|
4037
4340
|
child._collectObserveTargets("", targets);
|
|
4038
4341
|
for (const [p, n] of targets) {
|
|
4039
4342
|
if (!p.includes(`${PATH_SEP}${GRAPH_META_SEGMENT}${PATH_SEP}`)) {
|
|
4040
|
-
|
|
4343
|
+
audit2.nodes.push(p);
|
|
4041
4344
|
}
|
|
4042
4345
|
void n;
|
|
4043
4346
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4347
|
+
audit2.nodes.sort();
|
|
4348
|
+
audit2.mounts.push(name);
|
|
4349
|
+
audit2.mounts.push(...child._collectSubgraphs(`${name}${PATH_SEP}`));
|
|
4047
4350
|
this._mounts.delete(name);
|
|
4048
4351
|
child._parent = void 0;
|
|
4049
4352
|
teardownMountedGraph(child);
|
|
4050
|
-
|
|
4353
|
+
this._emitTopology({ kind: "removed", name, nodeKind: "mount", audit: audit2 });
|
|
4354
|
+
return audit2;
|
|
4051
4355
|
}
|
|
4052
4356
|
const node2 = this._nodes.get(name);
|
|
4053
4357
|
if (!node2) {
|
|
@@ -4056,7 +4360,9 @@ var Graph = class _Graph {
|
|
|
4056
4360
|
this._nodes.delete(name);
|
|
4057
4361
|
this._nodeToName.delete(node2);
|
|
4058
4362
|
node2.down([[TEARDOWN]], { internal: true });
|
|
4059
|
-
|
|
4363
|
+
const audit = { kind: "node", nodes: [name], mounts: [] };
|
|
4364
|
+
this._emitTopology({ kind: "removed", name, nodeKind: "node", audit });
|
|
4365
|
+
return audit;
|
|
4060
4366
|
}
|
|
4061
4367
|
/**
|
|
4062
4368
|
* Bulk remove — invokes {@link Graph.remove} for every local name matching
|
|
@@ -4285,6 +4591,7 @@ var Graph = class _Graph {
|
|
|
4285
4591
|
}
|
|
4286
4592
|
this._mounts.set(name, child);
|
|
4287
4593
|
child._parent = this;
|
|
4594
|
+
this._emitTopology({ kind: "added", name, nodeKind: "mount" });
|
|
4288
4595
|
return child;
|
|
4289
4596
|
}
|
|
4290
4597
|
/**
|
|
@@ -4575,6 +4882,33 @@ var Graph = class _Graph {
|
|
|
4575
4882
|
}
|
|
4576
4883
|
return reachable(this.describe(), from, direction, opts);
|
|
4577
4884
|
}
|
|
4885
|
+
/**
|
|
4886
|
+
* Causal walkback: shortest dep-chain from `from` to `to`, enriched with
|
|
4887
|
+
* each node's value, status, last-mutation actor, and reasoning annotation
|
|
4888
|
+
* from {@link Graph.trace}. Wraps {@link explainPath} (roadmap §9.2).
|
|
4889
|
+
*
|
|
4890
|
+
* @param from - Upstream node (the cause).
|
|
4891
|
+
* @param to - Downstream node (the effect).
|
|
4892
|
+
* @param opts - Optional `maxDepth` and `findCycle`. When `findCycle:true`
|
|
4893
|
+
* and `from === to`, returns the shortest cycle through other nodes
|
|
4894
|
+
* (useful for diagnosing feedback loops, COMPOSITION-GUIDE §7).
|
|
4895
|
+
* Annotations and lastMutations are collected automatically from the
|
|
4896
|
+
* live graph.
|
|
4897
|
+
*/
|
|
4898
|
+
explain(from, to, opts) {
|
|
4899
|
+
const described = this.describe({ detail: "full" });
|
|
4900
|
+
const annotations = new Map(this._annotations);
|
|
4901
|
+
const lastMutations = /* @__PURE__ */ new Map();
|
|
4902
|
+
for (const [path, n] of Object.entries(described.nodes)) {
|
|
4903
|
+
if (n.lastMutation != null) lastMutations.set(path, n.lastMutation);
|
|
4904
|
+
}
|
|
4905
|
+
return explainPath(described, from, to, {
|
|
4906
|
+
...opts?.maxDepth != null ? { maxDepth: opts.maxDepth } : {},
|
|
4907
|
+
...opts?.findCycle === true ? { findCycle: true } : {},
|
|
4908
|
+
annotations,
|
|
4909
|
+
lastMutations
|
|
4910
|
+
});
|
|
4911
|
+
}
|
|
4578
4912
|
/**
|
|
4579
4913
|
* @internal Collect all qualified paths in this graph tree matching a
|
|
4580
4914
|
* glob pattern. Used by scoped autoCheckpoint subscription.
|
|
@@ -5253,7 +5587,7 @@ var Graph = class _Graph {
|
|
|
5253
5587
|
return;
|
|
5254
5588
|
}
|
|
5255
5589
|
const nextSeq = s.seq + 1;
|
|
5256
|
-
const timestamp_ns =
|
|
5590
|
+
const timestamp_ns = wallClockNs();
|
|
5257
5591
|
const isFirst = s.lastSnapshot == null;
|
|
5258
5592
|
const shouldCompact = isFirst || nextSeq % s.compactEvery === 0;
|
|
5259
5593
|
const record = shouldCompact ? {
|