@signaltree/guardrails 8.0.2 → 9.0.1
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/dist/factories/index.js +3 -6
- package/dist/lib/guardrails.js +2 -39
- package/package.json +3 -3
- package/src/lib/types.d.ts +0 -2
package/dist/factories/index.js
CHANGED
|
@@ -12,8 +12,7 @@ function resolveGuardrailsConfig(guardrails) {
|
|
|
12
12
|
}
|
|
13
13
|
return {
|
|
14
14
|
budgets: {
|
|
15
|
-
maxUpdateTime: 16
|
|
16
|
-
maxRecomputations: 100
|
|
15
|
+
maxUpdateTime: 16
|
|
17
16
|
},
|
|
18
17
|
hotPaths: {
|
|
19
18
|
enabled: true,
|
|
@@ -70,8 +69,7 @@ function createPerformanceTree(signalTree, initial, name) {
|
|
|
70
69
|
return createFeatureTree(signalTree, initial, {
|
|
71
70
|
guardrails: {
|
|
72
71
|
budgets: {
|
|
73
|
-
maxUpdateTime: 8
|
|
74
|
-
maxRecomputations: 200
|
|
72
|
+
maxUpdateTime: 8
|
|
75
73
|
},
|
|
76
74
|
hotPaths: {
|
|
77
75
|
threshold: 50
|
|
@@ -107,8 +105,7 @@ function createTestTree(signalTree, initial, overrides) {
|
|
|
107
105
|
guardrails: {
|
|
108
106
|
mode: 'throw',
|
|
109
107
|
budgets: {
|
|
110
|
-
maxUpdateTime: 5
|
|
111
|
-
maxRecomputations: 50
|
|
108
|
+
maxUpdateTime: 5
|
|
112
109
|
},
|
|
113
110
|
customRules: [rules.noFunctionsInState(), rules.noDeepNesting(4)],
|
|
114
111
|
...overrides
|
package/dist/lib/guardrails.js
CHANGED
|
@@ -34,13 +34,12 @@ function tryStructuredClone(value) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
function isDevEnvironment() {
|
|
37
|
-
if (__DEV__ !== undefined) return __DEV__;
|
|
37
|
+
if (typeof __DEV__ !== 'undefined') return __DEV__;
|
|
38
38
|
if (process?.env?.['NODE_ENV'] === 'production') return false;
|
|
39
39
|
if (ngDevMode != null) return Boolean(ngDevMode);
|
|
40
40
|
return true;
|
|
41
41
|
}
|
|
42
42
|
const MAX_TIMING_SAMPLES = 1000;
|
|
43
|
-
const RECOMPUTATION_WINDOW_MS = 1000;
|
|
44
43
|
const POLLING_INTERVAL_MS = 50;
|
|
45
44
|
function guardrails(config = {}) {
|
|
46
45
|
return function (tree) {
|
|
@@ -61,29 +60,10 @@ function guardrails(config = {}) {
|
|
|
61
60
|
hotPathData: new Map(),
|
|
62
61
|
issueMap: new Map(),
|
|
63
62
|
signalUsage: new Map(),
|
|
64
|
-
pathRecomputations: new Map(),
|
|
65
63
|
memoryHistory: [],
|
|
66
|
-
recomputationLog: [],
|
|
67
64
|
previousState: tryStructuredClone(tree()),
|
|
68
65
|
disposed: false
|
|
69
66
|
};
|
|
70
|
-
tree['__devHooks'] = {
|
|
71
|
-
onRecompute: (path, count) => {
|
|
72
|
-
if (!context.disposed && !context.suppressed) {
|
|
73
|
-
recordRecomputations(path, context, count, Date.now());
|
|
74
|
-
const maxRecomputations = config.budgets?.maxRecomputations;
|
|
75
|
-
if (maxRecomputations && context.stats.recomputationCount > maxRecomputations) {
|
|
76
|
-
addIssue(context, {
|
|
77
|
-
type: 'budget',
|
|
78
|
-
severity: 'error',
|
|
79
|
-
message: `Recomputation budget exceeded: ${context.stats.recomputationCount} > ${maxRecomputations}`,
|
|
80
|
-
path,
|
|
81
|
-
count: 1
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
67
|
const stopChangeDetection = startChangeDetection(context);
|
|
88
68
|
const stopMonitoring = startMonitoring(context);
|
|
89
69
|
const teardown = () => {
|
|
@@ -349,20 +329,6 @@ function updateSignalStats(context, timestamp) {
|
|
|
349
329
|
const growth = baseline === 0 ? 0 : (signalCount - baseline) / Math.max(1, baseline);
|
|
350
330
|
context.stats.memoryGrowthRate = growth;
|
|
351
331
|
}
|
|
352
|
-
function recordRecomputations(path, context, count, timestamp) {
|
|
353
|
-
const currentPathCount = context.pathRecomputations.get(path) ?? 0;
|
|
354
|
-
context.pathRecomputations.set(path, currentPathCount + count);
|
|
355
|
-
if (count > 0) {
|
|
356
|
-
context.stats.recomputationCount += count;
|
|
357
|
-
for (let i = 0; i < count; i++) {
|
|
358
|
-
context.recomputationLog.push(timestamp);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (context.recomputationLog.length) {
|
|
362
|
-
context.recomputationLog = context.recomputationLog.filter(value => timestamp - value <= RECOMPUTATION_WINDOW_MS);
|
|
363
|
-
}
|
|
364
|
-
context.stats.recomputationsPerSecond = context.recomputationLog.length;
|
|
365
|
-
}
|
|
366
332
|
function updateHotPath(context, hotPath) {
|
|
367
333
|
const existing = context.hotPaths.find(h => h.path === hotPath.path);
|
|
368
334
|
if (existing) {
|
|
@@ -514,12 +480,9 @@ function getSeverityPrefix(severity) {
|
|
|
514
480
|
function generateReport(context) {
|
|
515
481
|
const memoryCurrent = context.stats.signalCount;
|
|
516
482
|
const memoryLimit = context.config.budgets?.maxMemory ?? 50;
|
|
517
|
-
const recomputationCurrent = context.stats.recomputationsPerSecond;
|
|
518
|
-
const recomputationLimit = context.config.budgets?.maxRecomputations ?? 100;
|
|
519
483
|
const budgets = {
|
|
520
484
|
updateTime: createBudgetItem(context.stats.avgUpdateTime, context.config.budgets?.maxUpdateTime || 16),
|
|
521
|
-
memory: createBudgetItem(memoryCurrent, memoryLimit)
|
|
522
|
-
recomputations: createBudgetItem(recomputationCurrent, recomputationLimit)
|
|
485
|
+
memory: createBudgetItem(memoryCurrent, memoryLimit)
|
|
523
486
|
};
|
|
524
487
|
return {
|
|
525
488
|
timestamp: Date.now(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/guardrails",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.1",
|
|
4
4
|
"description": "Development guardrails for SignalTree reactive JSON. Performance monitoring and anti-pattern detection.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"type-check": "tsc --project tsconfig.lib.json --noEmit"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@signaltree/core": "^
|
|
61
|
-
"@signaltree/shared": "^
|
|
60
|
+
"@signaltree/core": "^9.0.1",
|
|
61
|
+
"@signaltree/shared": "^9.0.1",
|
|
62
62
|
"tslib": "^2.0.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {},
|
package/src/lib/types.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ export interface GuardrailsConfig<T = Record<string, unknown>> {
|
|
|
8
8
|
budgets?: {
|
|
9
9
|
maxUpdateTime?: number;
|
|
10
10
|
maxMemory?: number;
|
|
11
|
-
maxRecomputations?: number;
|
|
12
11
|
maxTreeDepth?: number;
|
|
13
12
|
alertThreshold?: number;
|
|
14
13
|
};
|
|
@@ -116,7 +115,6 @@ export interface HotPath {
|
|
|
116
115
|
export interface BudgetStatus {
|
|
117
116
|
updateTime: BudgetItem;
|
|
118
117
|
memory: BudgetItem;
|
|
119
|
-
recomputations: BudgetItem;
|
|
120
118
|
}
|
|
121
119
|
export interface BudgetItem {
|
|
122
120
|
current: number;
|