react-state-basis 0.6.1 → 0.6.2
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 +11 -9
- package/dist/{chunk-O2ZOR3L2.mjs → chunk-E3D6YEKB.mjs} +32 -24
- package/dist/chunk-E3D6YEKB.mjs.map +1 -0
- package/dist/index.js +83 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -30
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/zustand.js +29 -23
- package/dist/integrations/zustand.js.map +1 -1
- package/dist/integrations/zustand.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-O2ZOR3L2.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -126,11 +126,26 @@ var calculateSpectralInfluence = (graph, maxIterations = 20, tolerance = 1e-3) =
|
|
|
126
126
|
return scores;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
-
// src/core/
|
|
129
|
+
// src/core/constants.ts
|
|
130
|
+
var WINDOW_SIZE = 50;
|
|
131
|
+
var SIMILARITY_THRESHOLD = 0.88;
|
|
132
|
+
var LOOP_THRESHOLD = 150;
|
|
133
|
+
var VOLATILITY_THRESHOLD = 25;
|
|
134
|
+
var INSTANCE_SEP = "##";
|
|
135
|
+
|
|
136
|
+
// src/core/label.ts
|
|
137
|
+
var stripInstance = (label) => {
|
|
138
|
+
const idx = label.indexOf(INSTANCE_SEP);
|
|
139
|
+
return idx === -1 ? label : label.slice(0, idx);
|
|
140
|
+
};
|
|
130
141
|
var parseLabel = (label) => {
|
|
131
|
-
const
|
|
132
|
-
|
|
142
|
+
const base = stripInstance(label);
|
|
143
|
+
const parts = base.split(" -> ");
|
|
144
|
+
return { file: parts[0] || "Unknown", name: parts[1] || base };
|
|
133
145
|
};
|
|
146
|
+
var isSameField = (labelA, labelB) => stripInstance(labelA) === stripInstance(labelB);
|
|
147
|
+
|
|
148
|
+
// src/core/ranker.ts
|
|
134
149
|
var identifyTopIssues = (graph, history2, redundantLabels2, violationMap) => {
|
|
135
150
|
const results = [];
|
|
136
151
|
const influence = calculateSpectralInfluence(graph);
|
|
@@ -260,10 +275,6 @@ var STYLES = {
|
|
|
260
275
|
bold: "font-weight: bold;",
|
|
261
276
|
label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;"
|
|
262
277
|
};
|
|
263
|
-
var parseLabel2 = (label) => {
|
|
264
|
-
const parts = label.split(" -> ");
|
|
265
|
-
return { file: parts[0] || "Unknown", name: parts[1] || label };
|
|
266
|
-
};
|
|
267
278
|
var shouldLog = (key) => {
|
|
268
279
|
const now = Date.now();
|
|
269
280
|
const last = LAST_LOG_TIMES.get(key) || 0;
|
|
@@ -286,7 +297,7 @@ var getSuggestedFix = (issue, info) => {
|
|
|
286
297
|
return `Local state is 'shadowing' Global Context. This creates two sources of truth. Delete the local state and consume the %cContext%c value directly.`;
|
|
287
298
|
}
|
|
288
299
|
if (leaks.length > 0) {
|
|
289
|
-
const targetName =
|
|
300
|
+
const targetName = parseLabel(leaks[0].target).name;
|
|
290
301
|
if (issue.label.includes("effect")) {
|
|
291
302
|
return `This Effect triggers a synchronous re-render of ${targetName}. Calculate ${targetName} during the render phase (Derived State) or wrap in %cuseMemo%c if expensive.`;
|
|
292
303
|
}
|
|
@@ -316,7 +327,7 @@ var displayHealthReport = (history2, threshold, violationMap) => {
|
|
|
316
327
|
`font-weight: normal; color: ${THEME.muted}; font-style: italic;`
|
|
317
328
|
);
|
|
318
329
|
topIssues.forEach((issue, idx) => {
|
|
319
|
-
const info =
|
|
330
|
+
const info = parseLabel(issue.label);
|
|
320
331
|
const icon = issue.metric === "influence" ? "\u26A1" : "\u{1F4C8}";
|
|
321
332
|
const pColor = idx === 0 ? THEME.problem : idx === 1 ? THEME.solution : THEME.identity;
|
|
322
333
|
let displayName = info.name;
|
|
@@ -336,7 +347,7 @@ var displayHealthReport = (history2, threshold, violationMap) => {
|
|
|
336
347
|
const byFile = /* @__PURE__ */ new Map();
|
|
337
348
|
issue.violations.forEach((v) => {
|
|
338
349
|
if (issue.label.includes("Global Event") && v.type === "context_mirror") return;
|
|
339
|
-
const { file, name } =
|
|
350
|
+
const { file, name } = parseLabel(v.target);
|
|
340
351
|
if (!byFile.has(file)) byFile.set(file, []);
|
|
341
352
|
byFile.get(file).push(name);
|
|
342
353
|
});
|
|
@@ -411,7 +422,7 @@ var displayHealthReport = (history2, threshold, violationMap) => {
|
|
|
411
422
|
const clusterMetas = cluster.map((l) => ({
|
|
412
423
|
label: l,
|
|
413
424
|
meta: history2.get(l),
|
|
414
|
-
name:
|
|
425
|
+
name: parseLabel(l).name
|
|
415
426
|
}));
|
|
416
427
|
const hasCtx = clusterMetas.some(
|
|
417
428
|
(c) => c.meta.role === "context" /* CONTEXT */ || c.meta.role === "store" /* STORE */
|
|
@@ -452,8 +463,8 @@ var displayHealthReport = (history2, threshold, violationMap) => {
|
|
|
452
463
|
};
|
|
453
464
|
var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
|
|
454
465
|
if (!isWeb || !shouldLog(`redundant-${labelA}-${labelB}`)) return;
|
|
455
|
-
const infoA =
|
|
456
|
-
const infoB =
|
|
466
|
+
const infoA = parseLabel(labelA);
|
|
467
|
+
const infoB = parseLabel(labelB);
|
|
457
468
|
const isContextMirror = metaA.role === "local" /* LOCAL */ && metaB.role === "context" /* CONTEXT */ || metaB.role === "local" /* LOCAL */ && metaA.role === "context" /* CONTEXT */;
|
|
458
469
|
const isStoreMirror = metaA.role === "local" /* LOCAL */ && metaB.role === "store" /* STORE */ || metaB.role === "local" /* LOCAL */ && metaA.role === "store" /* STORE */;
|
|
459
470
|
const alertType = isContextMirror ? "CONTEXT MIRRORING" : isStoreMirror ? "STORE MIRRORING" : "DUPLICATE STATE";
|
|
@@ -498,8 +509,8 @@ var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
|
|
|
498
509
|
};
|
|
499
510
|
var displayCausalHint = (targetLabel, targetMeta, sourceLabel, sourceMeta) => {
|
|
500
511
|
if (!isWeb || !shouldLog(`causal-${sourceLabel}-${targetLabel}`)) return;
|
|
501
|
-
const target =
|
|
502
|
-
const source =
|
|
512
|
+
const target = parseLabel(targetLabel);
|
|
513
|
+
const source = parseLabel(sourceLabel);
|
|
503
514
|
const headerType = sourceMeta.role === "context" /* CONTEXT */ ? "CONTEXT SYNC LEAK" : sourceMeta.role === "store" /* STORE */ ? "STORE SYNC LEAK" : "DOUBLE RENDER";
|
|
504
515
|
const isEffect = sourceLabel.includes("effect") || sourceLabel.includes("useLayoutEffect");
|
|
505
516
|
console.groupCollapsed(`%c \u26A1 BASIS | ${headerType} `, STYLES.headerProblem);
|
|
@@ -530,10 +541,10 @@ var displayCausalHint = (targetLabel, targetMeta, sourceLabel, sourceMeta) => {
|
|
|
530
541
|
};
|
|
531
542
|
var displayViolentBreaker = (label, count, threshold) => {
|
|
532
543
|
if (!isWeb) return;
|
|
533
|
-
const
|
|
544
|
+
const { name } = parseLabel(label);
|
|
534
545
|
console.group(`%c \u{1F6D1} BASIS CRITICAL | CIRCUIT BREAKER `, STYLES.headerProblem);
|
|
535
546
|
console.error(`INFINITE LOOP DETECTED
|
|
536
|
-
Variable: ${
|
|
547
|
+
Variable: ${name}
|
|
537
548
|
Frequency: ${count} updates/sec`);
|
|
538
549
|
console.log(`%cACTION: Update BLOCKED to prevent browser freeze.`, `color: ${THEME.problem}; font-weight: bold;`);
|
|
539
550
|
console.groupEnd();
|
|
@@ -543,12 +554,6 @@ var displayBootLog = (windowSize) => {
|
|
|
543
554
|
console.log(`%cBasis%cAuditor%c "Graph Era" (Window: ${windowSize})`, STYLES.basis, STYLES.version, `color: ${THEME.muted}; font-style: italic; margin-left: 8px;`);
|
|
544
555
|
};
|
|
545
556
|
|
|
546
|
-
// src/core/constants.ts
|
|
547
|
-
var WINDOW_SIZE = 50;
|
|
548
|
-
var SIMILARITY_THRESHOLD = 0.88;
|
|
549
|
-
var LOOP_THRESHOLD = 150;
|
|
550
|
-
var VOLATILITY_THRESHOLD = 25;
|
|
551
|
-
|
|
552
557
|
// src/core/analysis.ts
|
|
553
558
|
var CAUSAL_MARGIN = 0.05;
|
|
554
559
|
var isEventDriven = (label, graph) => {
|
|
@@ -585,6 +590,7 @@ var calculateAllSimilarities = (entryA, entryB) => {
|
|
|
585
590
|
};
|
|
586
591
|
var shouldSkipComparison = (entryA, entryB, dirtyLabels2) => {
|
|
587
592
|
if (entryA.label === entryB.label) return true;
|
|
593
|
+
if (isSameField(entryA.label, entryB.label)) return true;
|
|
588
594
|
if (dirtyLabels2.has(entryB.label) && entryA.label > entryB.label) return true;
|
|
589
595
|
return false;
|
|
590
596
|
};
|
|
@@ -920,39 +926,52 @@ if (typeof window !== "undefined") {
|
|
|
920
926
|
// src/hooks.ts
|
|
921
927
|
var anonCount = 0;
|
|
922
928
|
var getFallbackLabel = (type) => `anon_${type}_${anonCount++}`;
|
|
929
|
+
var reactUseId = React.useId;
|
|
930
|
+
var legacyInstanceCounter = 0;
|
|
931
|
+
var useInstanceId = () => {
|
|
932
|
+
const [legacyId] = (0, import_react.useState)(
|
|
933
|
+
() => typeof reactUseId === "function" ? "" : `legacy_${legacyInstanceCounter++}`
|
|
934
|
+
);
|
|
935
|
+
return typeof reactUseId === "function" ? reactUseId() : legacyId;
|
|
936
|
+
};
|
|
937
|
+
var withInstance = (label, instanceId) => `${label}${INSTANCE_SEP}${instanceId}`;
|
|
923
938
|
var React19 = React;
|
|
924
939
|
function useState(initialState, label) {
|
|
925
940
|
const [val, setVal] = (0, import_react.useState)(initialState);
|
|
926
941
|
const effectiveLabel = (0, import_react.useRef)(label || getFallbackLabel("state")).current;
|
|
942
|
+
const instanceId = useInstanceId();
|
|
943
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
927
944
|
(0, import_react.useEffect)(() => {
|
|
928
|
-
registerVariable(
|
|
945
|
+
registerVariable(storageKey, { role: "local" /* LOCAL */ });
|
|
929
946
|
return () => {
|
|
930
|
-
unregisterVariable(
|
|
947
|
+
unregisterVariable(storageKey);
|
|
931
948
|
};
|
|
932
|
-
}, [
|
|
949
|
+
}, [storageKey]);
|
|
933
950
|
const setter = (0, import_react.useCallback)((value) => {
|
|
934
|
-
if (recordUpdate(
|
|
951
|
+
if (recordUpdate(storageKey)) {
|
|
935
952
|
setVal(value);
|
|
936
953
|
}
|
|
937
|
-
}, [
|
|
954
|
+
}, [storageKey]);
|
|
938
955
|
return [val, setter];
|
|
939
956
|
}
|
|
940
957
|
function useReducer(reducer, initialArg, init, label) {
|
|
941
958
|
const isLazy = typeof init === "function";
|
|
942
959
|
const providedLabel = label || (typeof init === "string" ? init : void 0);
|
|
943
960
|
const effectiveLabel = (0, import_react.useRef)(providedLabel || getFallbackLabel("reducer")).current;
|
|
961
|
+
const instanceId = useInstanceId();
|
|
962
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
944
963
|
const [state, dispatch] = isLazy ? (0, import_react.useReducer)(reducer, initialArg, init) : (0, import_react.useReducer)(reducer, initialArg);
|
|
945
964
|
(0, import_react.useEffect)(() => {
|
|
946
|
-
registerVariable(
|
|
965
|
+
registerVariable(storageKey, { role: "local" /* LOCAL */ });
|
|
947
966
|
return () => {
|
|
948
|
-
unregisterVariable(
|
|
967
|
+
unregisterVariable(storageKey);
|
|
949
968
|
};
|
|
950
|
-
}, [
|
|
969
|
+
}, [storageKey]);
|
|
951
970
|
const basisDispatch = (0, import_react.useCallback)((action) => {
|
|
952
|
-
if (recordUpdate(
|
|
971
|
+
if (recordUpdate(storageKey)) {
|
|
953
972
|
dispatch(action);
|
|
954
973
|
}
|
|
955
|
-
}, [
|
|
974
|
+
}, [storageKey, dispatch]);
|
|
956
975
|
return [state, basisDispatch];
|
|
957
976
|
}
|
|
958
977
|
function createContext(defaultValue, label) {
|
|
@@ -978,28 +997,34 @@ function useContext(context) {
|
|
|
978
997
|
}
|
|
979
998
|
function useMemo(factory, deps, label) {
|
|
980
999
|
const effectiveLabel = (0, import_react.useRef)(label || getFallbackLabel("proj")).current;
|
|
1000
|
+
const instanceId = useInstanceId();
|
|
1001
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
981
1002
|
(0, import_react.useEffect)(() => {
|
|
982
|
-
registerVariable(
|
|
1003
|
+
registerVariable(storageKey, { role: "proj" /* PROJECTION */ });
|
|
983
1004
|
return () => {
|
|
984
|
-
unregisterVariable(
|
|
1005
|
+
unregisterVariable(storageKey);
|
|
985
1006
|
};
|
|
986
|
-
}, [
|
|
1007
|
+
}, [storageKey]);
|
|
987
1008
|
return (0, import_react.useMemo)(factory, deps || []);
|
|
988
1009
|
}
|
|
989
1010
|
function useCallback(callback, deps, label) {
|
|
990
1011
|
const effectiveLabel = (0, import_react.useRef)(label || getFallbackLabel("cb")).current;
|
|
1012
|
+
const instanceId = useInstanceId();
|
|
1013
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
991
1014
|
(0, import_react.useEffect)(() => {
|
|
992
|
-
registerVariable(
|
|
1015
|
+
registerVariable(storageKey, { role: "proj" /* PROJECTION */ });
|
|
993
1016
|
return () => {
|
|
994
|
-
unregisterVariable(
|
|
1017
|
+
unregisterVariable(storageKey);
|
|
995
1018
|
};
|
|
996
|
-
}, [
|
|
1019
|
+
}, [storageKey]);
|
|
997
1020
|
return (0, import_react.useCallback)(callback, deps);
|
|
998
1021
|
}
|
|
999
1022
|
function useEffect(effect, deps, label) {
|
|
1000
1023
|
const effectiveLabel = label || "anonymous_effect";
|
|
1024
|
+
const instanceId = useInstanceId();
|
|
1025
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
1001
1026
|
(0, import_react.useEffect)(() => {
|
|
1002
|
-
beginEffectTracking(
|
|
1027
|
+
beginEffectTracking(storageKey);
|
|
1003
1028
|
const destructor = effect();
|
|
1004
1029
|
endEffectTracking();
|
|
1005
1030
|
return typeof destructor === "function" ? destructor : void 0;
|
|
@@ -1007,8 +1032,10 @@ function useEffect(effect, deps, label) {
|
|
|
1007
1032
|
}
|
|
1008
1033
|
function useLayoutEffect(effect, deps, label) {
|
|
1009
1034
|
const effectiveLabel = label || "anonymous_layout_effect";
|
|
1035
|
+
const instanceId = useInstanceId();
|
|
1036
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
1010
1037
|
(0, import_react.useLayoutEffect)(() => {
|
|
1011
|
-
beginEffectTracking(
|
|
1038
|
+
beginEffectTracking(storageKey);
|
|
1012
1039
|
const destructor = effect();
|
|
1013
1040
|
endEffectTracking();
|
|
1014
1041
|
return typeof destructor === "function" ? destructor : void 0;
|
|
@@ -1016,36 +1043,40 @@ function useLayoutEffect(effect, deps, label) {
|
|
|
1016
1043
|
}
|
|
1017
1044
|
function useOptimistic(passthrough, reducer, label) {
|
|
1018
1045
|
const effectiveLabel = (0, import_react.useRef)(label || getFallbackLabel("optimistic")).current;
|
|
1046
|
+
const instanceId = useInstanceId();
|
|
1047
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
1019
1048
|
(0, import_react.useEffect)(() => {
|
|
1020
|
-
registerVariable(
|
|
1049
|
+
registerVariable(storageKey, { role: "local" /* LOCAL */ });
|
|
1021
1050
|
return () => {
|
|
1022
|
-
unregisterVariable(
|
|
1051
|
+
unregisterVariable(storageKey);
|
|
1023
1052
|
};
|
|
1024
|
-
}, [
|
|
1053
|
+
}, [storageKey]);
|
|
1025
1054
|
const [state, reactAddOptimistic] = React19.useOptimistic(passthrough, reducer);
|
|
1026
1055
|
const addOptimistic = (0, import_react.useCallback)((payload) => {
|
|
1027
|
-
if (recordUpdate(
|
|
1056
|
+
if (recordUpdate(storageKey)) {
|
|
1028
1057
|
reactAddOptimistic(payload);
|
|
1029
1058
|
}
|
|
1030
|
-
}, [
|
|
1059
|
+
}, [storageKey, reactAddOptimistic]);
|
|
1031
1060
|
return [state, addOptimistic];
|
|
1032
1061
|
}
|
|
1033
1062
|
function useActionState(action, initialState, permalink, label) {
|
|
1034
1063
|
const isLabelArg = typeof permalink === "string" && label === void 0;
|
|
1035
1064
|
const effectiveLabel = (0, import_react.useRef)(isLabelArg ? permalink : label || getFallbackLabel("action_state")).current;
|
|
1036
1065
|
const actualPermalink = isLabelArg ? void 0 : permalink;
|
|
1066
|
+
const instanceId = useInstanceId();
|
|
1067
|
+
const storageKey = withInstance(effectiveLabel, instanceId);
|
|
1037
1068
|
const [state, reactDispatch, isPending] = React19.useActionState(action, initialState, actualPermalink);
|
|
1038
1069
|
(0, import_react.useEffect)(() => {
|
|
1039
|
-
registerVariable(
|
|
1070
|
+
registerVariable(storageKey, { role: "local" /* LOCAL */ });
|
|
1040
1071
|
return () => {
|
|
1041
|
-
unregisterVariable(
|
|
1072
|
+
unregisterVariable(storageKey);
|
|
1042
1073
|
};
|
|
1043
|
-
}, [
|
|
1074
|
+
}, [storageKey]);
|
|
1044
1075
|
const basisDispatch = (0, import_react.useCallback)((payload) => {
|
|
1045
|
-
if (recordUpdate(
|
|
1076
|
+
if (recordUpdate(storageKey)) {
|
|
1046
1077
|
reactDispatch(payload);
|
|
1047
1078
|
}
|
|
1048
|
-
}, [
|
|
1079
|
+
}, [storageKey, reactDispatch]);
|
|
1049
1080
|
return [state, basisDispatch, isPending];
|
|
1050
1081
|
}
|
|
1051
1082
|
var useRef = import_react.useRef;
|
|
@@ -1200,7 +1231,7 @@ function renderMatrix(ctx, entries) {
|
|
|
1200
1231
|
};
|
|
1201
1232
|
for (let i = head; i < L; i++) addToPath(buffer[i], uiPos++);
|
|
1202
1233
|
for (let i = 0; i < head; i++) addToPath(buffer[i], uiPos++);
|
|
1203
|
-
const stateName = label.
|
|
1234
|
+
const stateName = parseLabel(label).name;
|
|
1204
1235
|
const textX = L * colW + pad + 10;
|
|
1205
1236
|
ctx.fillStyle = isContext ? HUD_THEME.header : isRedundant ? HUD_THEME.error : HUD_THEME.text;
|
|
1206
1237
|
const prefix = meta.role === "store" ? "\u03A3 " : isContext ? "\u03A9 " : isRedundant ? "! " : "";
|