react-state-basis 0.6.4 → 0.6.5
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 +59 -1
- package/dist/{chunk-6GBZSOB3.mjs → chunk-EJXGN76H.mjs} +163 -2
- package/dist/chunk-EJXGN76H.mjs.map +1 -0
- package/dist/index.d.mts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +163 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/zustand.js +159 -0
- package/dist/integrations/zustand.js.map +1 -1
- package/dist/integrations/zustand.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-6GBZSOB3.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,9 @@ __export(index_exports, {
|
|
|
34
34
|
basis: () => basis,
|
|
35
35
|
configureBasis: () => configureBasis,
|
|
36
36
|
createContext: () => createContext,
|
|
37
|
+
getBasisGraph: () => getBasisGraph,
|
|
37
38
|
getBasisMetrics: () => getBasisMetrics,
|
|
39
|
+
printBasisGraph: () => printBasisGraph,
|
|
38
40
|
printBasisHealthReport: () => printBasisHealthReport,
|
|
39
41
|
use: () => use,
|
|
40
42
|
useActionState: () => useActionState,
|
|
@@ -125,6 +127,27 @@ var calculateSpectralInfluence = (graph, maxIterations = 20, tolerance = 1e-3) =
|
|
|
125
127
|
}
|
|
126
128
|
return scores;
|
|
127
129
|
};
|
|
130
|
+
var groupEventSources = (nodes, edges) => {
|
|
131
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
132
|
+
edges.forEach((e) => {
|
|
133
|
+
if (!outgoing.has(e.source)) outgoing.set(e.source, []);
|
|
134
|
+
outgoing.get(e.source).push(e);
|
|
135
|
+
});
|
|
136
|
+
const eventSourceIds = nodes.filter((n) => n.role === "event").map((n) => n.id);
|
|
137
|
+
const signatureOf = (sourceEdges) => sourceEdges.map((e) => `${e.target}@${e.weight}`).sort().join("|");
|
|
138
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
139
|
+
eventSourceIds.forEach((id) => {
|
|
140
|
+
const sig = signatureOf(outgoing.get(id) || []);
|
|
141
|
+
if (!buckets.has(sig)) buckets.set(sig, []);
|
|
142
|
+
buckets.get(sig).push(id);
|
|
143
|
+
});
|
|
144
|
+
const groups = Array.from(buckets.values()).map((sourceIds) => ({
|
|
145
|
+
sourceIds,
|
|
146
|
+
occurrences: sourceIds.length,
|
|
147
|
+
edges: (outgoing.get(sourceIds[0]) || []).slice()
|
|
148
|
+
}));
|
|
149
|
+
return groups.sort((a, b) => b.edges.length - a.edges.length || b.occurrences - a.occurrences);
|
|
150
|
+
};
|
|
128
151
|
|
|
129
152
|
// src/core/constants.ts
|
|
130
153
|
var WINDOW_SIZE = 50;
|
|
@@ -144,6 +167,7 @@ var parseLabel = (label) => {
|
|
|
144
167
|
return { file: parts[0] || "Unknown", name: parts[1] || base };
|
|
145
168
|
};
|
|
146
169
|
var isSameField = (labelA, labelB) => stripInstance(labelA) === stripInstance(labelB);
|
|
170
|
+
var isEffectLabel = (name) => /^effect_L\d+(:\d+)?$/.test(name) || name === "anonymous_effect" || name === "anonymous_layout_effect";
|
|
147
171
|
|
|
148
172
|
// src/core/ranker.ts
|
|
149
173
|
var identifyTopIssues = (graph, history2, redundantLabels2, violationMap) => {
|
|
@@ -539,6 +563,99 @@ var displayCausalHint = (targetLabel, targetMeta, sourceLabel, sourceMeta) => {
|
|
|
539
563
|
}
|
|
540
564
|
console.groupEnd();
|
|
541
565
|
};
|
|
566
|
+
var splitHookLine = (raw) => {
|
|
567
|
+
const m = raw.match(/^(.*):(\d+)$/);
|
|
568
|
+
if (!m) return { hook: raw };
|
|
569
|
+
return { hook: m[1], line: Number(m[2]) };
|
|
570
|
+
};
|
|
571
|
+
var formatHook = (raw) => {
|
|
572
|
+
const { hook } = splitHookLine(raw);
|
|
573
|
+
if (!isEffectLabel(hook)) return hook;
|
|
574
|
+
const lineMatch = hook.match(/L(\d+)$/);
|
|
575
|
+
return lineMatch ? `effect @ L${lineMatch[1]}` : "effect (anonymous)";
|
|
576
|
+
};
|
|
577
|
+
var formatNode = (node, fallbackId = "?") => {
|
|
578
|
+
if (!node) return fallbackId;
|
|
579
|
+
if (node.role === "event") return "Event";
|
|
580
|
+
const hook = formatHook(node.name || node.id);
|
|
581
|
+
if (node.file && hook) return `${node.file} \u2192 ${hook}`;
|
|
582
|
+
return hook || node.id;
|
|
583
|
+
};
|
|
584
|
+
var displayGraphReport = (graph) => {
|
|
585
|
+
if (!isWeb) return;
|
|
586
|
+
if (graph.nodes.length === 0) {
|
|
587
|
+
console.log(
|
|
588
|
+
`%c \u{1F4CA} BASIS | CAUSAL GRAPH %c(no data yet)`,
|
|
589
|
+
STYLES.headerIdentity,
|
|
590
|
+
`color: ${THEME.muted}; font-style: italic;`
|
|
591
|
+
);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
595
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
596
|
+
graph.edges.forEach((e) => {
|
|
597
|
+
if (!outgoing.has(e.source)) outgoing.set(e.source, []);
|
|
598
|
+
outgoing.get(e.source).push(e);
|
|
599
|
+
});
|
|
600
|
+
const eventGroups = graph.eventGroups.map((g) => ({
|
|
601
|
+
sourceIds: g.sourceIds,
|
|
602
|
+
sourceNode: nodeById.get(g.sourceIds[0]),
|
|
603
|
+
edges: g.edges,
|
|
604
|
+
occurrences: g.occurrences
|
|
605
|
+
}));
|
|
606
|
+
const groupedSourceIds = new Set(graph.eventGroups.flatMap((g) => g.sourceIds));
|
|
607
|
+
const nonEventGroups = Array.from(outgoing.keys()).filter((id) => !groupedSourceIds.has(id)).map((id) => ({ sourceIds: [id], sourceNode: nodeById.get(id), edges: outgoing.get(id), occurrences: 1 }));
|
|
608
|
+
const groups = [...eventGroups, ...nonEventGroups].sort(
|
|
609
|
+
(a, b) => b.edges.length - a.edges.length || b.occurrences - a.occurrences
|
|
610
|
+
);
|
|
611
|
+
console.group(
|
|
612
|
+
`%c \u{1F4CA} BASIS | CAUSAL GRAPH %c${graph.nodes.length} nodes \xB7 ${graph.edges.length} edges \xB7 ${groups.length} sources \xB7 buffer window ${graph.bufferWindowSize}`,
|
|
613
|
+
STYLES.headerIdentity,
|
|
614
|
+
`color: ${THEME.muted}; font-weight: normal; font-style: italic;`
|
|
615
|
+
);
|
|
616
|
+
console.log(
|
|
617
|
+
`%cparent \u2192 child = observed cause \u2192 update. (\xD7N) = times in this window. Event groups with the same fan-out are collapsed.`,
|
|
618
|
+
STYLES.subText
|
|
619
|
+
);
|
|
620
|
+
groups.forEach((group) => {
|
|
621
|
+
const isEvent = group.sourceNode?.role === "event";
|
|
622
|
+
const isCtx = group.sourceNode?.role === "context" /* CONTEXT */;
|
|
623
|
+
const isFx = group.sourceNode?.role === "effect";
|
|
624
|
+
const isUnknown = group.sourceNode?.role === "unknown";
|
|
625
|
+
const icon = isEvent ? "\u26A1" : isCtx ? "\u03A9" : isFx ? "\u21AF" : isUnknown ? "?" : "\u25CF";
|
|
626
|
+
const color = isEvent ? THEME.solution : isCtx ? THEME.context : THEME.identity;
|
|
627
|
+
const fanout = group.edges.length;
|
|
628
|
+
const hits = group.occurrences;
|
|
629
|
+
const hitLabel = hits > 1 ? ` \xB7 \xD7${hits}` : "";
|
|
630
|
+
const title = isEvent ? `Event \xB7 ${fanout} target${fanout === 1 ? "" : "s"}${hitLabel}` : formatNode(group.sourceNode, group.sourceIds[0]);
|
|
631
|
+
console.groupCollapsed(
|
|
632
|
+
`%c${icon} %c${title}`,
|
|
633
|
+
`color: ${color};`,
|
|
634
|
+
"font-family: monospace; font-weight: 600;"
|
|
635
|
+
);
|
|
636
|
+
group.edges.slice().sort((a, b) => b.weight - a.weight).forEach((edge) => {
|
|
637
|
+
const target = nodeById.get(edge.target);
|
|
638
|
+
const label = formatNode(target, edge.target);
|
|
639
|
+
const weight = edge.weight > 1 ? ` (\xD7${edge.weight})` : "";
|
|
640
|
+
if (target?.redundant) {
|
|
641
|
+
console.log(
|
|
642
|
+
`%c ${label}%c${weight} %credundant`,
|
|
643
|
+
`color: ${THEME.muted}; font-family: monospace;`,
|
|
644
|
+
`color: ${THEME.muted}; font-style: italic;`,
|
|
645
|
+
`color: ${THEME.problem}; font-weight: bold;`
|
|
646
|
+
);
|
|
647
|
+
} else {
|
|
648
|
+
console.log(
|
|
649
|
+
`%c ${label}%c${weight}`,
|
|
650
|
+
`color: ${THEME.muted}; font-family: monospace;`,
|
|
651
|
+
`color: ${THEME.muted}; font-style: italic;`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
console.groupEnd();
|
|
656
|
+
});
|
|
657
|
+
console.groupEnd();
|
|
658
|
+
};
|
|
542
659
|
var displayViolentBreaker = (label, count, threshold) => {
|
|
543
660
|
if (!isWeb) return;
|
|
544
661
|
const { name } = parseLabel(label);
|
|
@@ -925,9 +1042,53 @@ var getBasisMetrics = () => ({
|
|
|
925
1042
|
analysis_ms: instance.metrics.lastAnalysisTimeMs.toFixed(3),
|
|
926
1043
|
entropy: instance.metrics.systemEntropy.toFixed(3)
|
|
927
1044
|
});
|
|
1045
|
+
var getBasisGraph = () => {
|
|
1046
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
1047
|
+
const edges = [];
|
|
1048
|
+
instance.graph.forEach((targets, source) => {
|
|
1049
|
+
nodeIds.add(source);
|
|
1050
|
+
targets.forEach((weight, target) => {
|
|
1051
|
+
nodeIds.add(target);
|
|
1052
|
+
edges.push({ source, target, weight });
|
|
1053
|
+
});
|
|
1054
|
+
});
|
|
1055
|
+
const nodes = Array.from(nodeIds).map((id) => {
|
|
1056
|
+
if (id.startsWith("Event_Tick_")) {
|
|
1057
|
+
return { id, name: "Event", file: "(shared trigger)", role: "event", density: null, redundant: false };
|
|
1058
|
+
}
|
|
1059
|
+
const meta = instance.history.get(id);
|
|
1060
|
+
const { file, name } = parseLabel(id);
|
|
1061
|
+
if (!meta) {
|
|
1062
|
+
const role = isEffectLabel(name) ? "effect" : "unknown";
|
|
1063
|
+
return { id, name, file, role, density: null, redundant: false };
|
|
1064
|
+
}
|
|
1065
|
+
return {
|
|
1066
|
+
id,
|
|
1067
|
+
name,
|
|
1068
|
+
file,
|
|
1069
|
+
role: meta.role,
|
|
1070
|
+
density: meta.density,
|
|
1071
|
+
redundant: instance.redundantLabels.has(id)
|
|
1072
|
+
};
|
|
1073
|
+
});
|
|
1074
|
+
return {
|
|
1075
|
+
generatedAt: Date.now(),
|
|
1076
|
+
bufferWindowSize: WINDOW_SIZE,
|
|
1077
|
+
eventTtlMs: EVENT_TTL,
|
|
1078
|
+
nodes,
|
|
1079
|
+
edges,
|
|
1080
|
+
eventGroups: groupEventSources(nodes, edges)
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
var printBasisGraph = () => {
|
|
1084
|
+
if (!instance.config.debug) return;
|
|
1085
|
+
displayGraphReport(getBasisGraph());
|
|
1086
|
+
};
|
|
928
1087
|
if (typeof window !== "undefined") {
|
|
929
1088
|
window.printBasisReport = printBasisHealthReport;
|
|
930
1089
|
window.getBasisMetrics = getBasisMetrics;
|
|
1090
|
+
window.getBasisGraph = getBasisGraph;
|
|
1091
|
+
window.printBasisGraph = printBasisGraph;
|
|
931
1092
|
}
|
|
932
1093
|
|
|
933
1094
|
// src/hooks.ts
|
|
@@ -1330,7 +1491,9 @@ function basis() {
|
|
|
1330
1491
|
basis,
|
|
1331
1492
|
configureBasis,
|
|
1332
1493
|
createContext,
|
|
1494
|
+
getBasisGraph,
|
|
1333
1495
|
getBasisMetrics,
|
|
1496
|
+
printBasisGraph,
|
|
1334
1497
|
printBasisHealthReport,
|
|
1335
1498
|
use,
|
|
1336
1499
|
useActionState,
|