@signaltree/core 6.0.0 → 6.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.
Files changed (78) hide show
  1. package/README.md +76 -76
  2. package/dist/constants.js +6 -0
  3. package/dist/deep-equal.js +41 -0
  4. package/dist/enhancers/batching/batching.js +189 -0
  5. package/dist/enhancers/devtools/devtools.js +306 -0
  6. package/dist/enhancers/effects/effects.js +66 -0
  7. package/dist/enhancers/entities/entities.js +51 -0
  8. package/dist/enhancers/index.js +72 -0
  9. package/dist/enhancers/memoization/memoization.js +420 -0
  10. package/dist/enhancers/presets/lib/presets.js +27 -0
  11. package/dist/enhancers/serialization/constants.js +15 -0
  12. package/dist/enhancers/serialization/serialization.js +656 -0
  13. package/dist/enhancers/time-travel/time-travel.js +231 -0
  14. package/dist/enhancers/time-travel/utils.js +11 -0
  15. package/dist/index.js +19 -0
  16. package/dist/is-built-in-object.js +23 -0
  17. package/dist/lib/async-helpers.js +77 -0
  18. package/dist/lib/constants.js +56 -0
  19. package/dist/lib/entity-signal.js +283 -0
  20. package/dist/lib/memory/memory-manager.js +164 -0
  21. package/dist/lib/path-notifier.js +106 -0
  22. package/dist/lib/presets.js +21 -0
  23. package/dist/lib/security/security-validator.js +121 -0
  24. package/dist/lib/signal-tree.js +277 -0
  25. package/dist/lib/types.js +9 -0
  26. package/dist/lib/utils.js +299 -0
  27. package/dist/lru-cache.js +64 -0
  28. package/dist/parse-path.js +13 -0
  29. package/package.json +1 -1
  30. package/src/enhancers/batching/batching.d.ts +11 -0
  31. package/src/enhancers/batching/batching.types.d.ts +1 -0
  32. package/src/enhancers/batching/index.d.ts +1 -0
  33. package/src/enhancers/batching/test-setup.d.ts +3 -0
  34. package/src/enhancers/devtools/devtools.d.ts +68 -0
  35. package/src/enhancers/devtools/devtools.types.d.ts +1 -0
  36. package/src/enhancers/devtools/index.d.ts +1 -0
  37. package/src/enhancers/devtools/test-setup.d.ts +3 -0
  38. package/src/enhancers/effects/effects.d.ts +9 -0
  39. package/src/enhancers/effects/effects.types.d.ts +1 -0
  40. package/src/enhancers/effects/index.d.ts +1 -0
  41. package/src/enhancers/entities/entities.d.ts +11 -0
  42. package/src/enhancers/entities/entities.types.d.ts +1 -0
  43. package/src/enhancers/entities/index.d.ts +1 -0
  44. package/src/enhancers/entities/test-setup.d.ts +3 -0
  45. package/src/enhancers/index.d.ts +3 -0
  46. package/src/enhancers/memoization/index.d.ts +1 -0
  47. package/src/enhancers/memoization/memoization.d.ts +54 -0
  48. package/src/enhancers/memoization/memoization.types.d.ts +1 -0
  49. package/src/enhancers/memoization/test-setup.d.ts +3 -0
  50. package/src/enhancers/presets/index.d.ts +1 -0
  51. package/src/enhancers/presets/lib/presets.d.ts +8 -0
  52. package/src/enhancers/serialization/constants.d.ts +14 -0
  53. package/src/enhancers/serialization/index.d.ts +2 -0
  54. package/src/enhancers/serialization/serialization.d.ts +68 -0
  55. package/src/enhancers/serialization/test-setup.d.ts +3 -0
  56. package/src/enhancers/test-helpers/types-equals.d.ts +2 -0
  57. package/src/enhancers/time-travel/index.d.ts +1 -0
  58. package/src/enhancers/time-travel/test-setup.d.ts +3 -0
  59. package/src/enhancers/time-travel/time-travel.d.ts +10 -0
  60. package/src/enhancers/time-travel/time-travel.types.d.ts +1 -0
  61. package/src/enhancers/time-travel/utils.d.ts +2 -0
  62. package/src/enhancers/types.d.ts +1 -0
  63. package/src/enhancers/typing/helpers-types.d.ts +2 -0
  64. package/src/index.d.ts +17 -0
  65. package/src/lib/async-helpers.d.ts +8 -0
  66. package/src/lib/constants.d.ts +41 -0
  67. package/src/lib/dev-proxy.d.ts +3 -0
  68. package/src/lib/entity-signal.d.ts +1 -0
  69. package/src/lib/memory/memory-manager.d.ts +30 -0
  70. package/src/lib/path-notifier.d.ts +4 -0
  71. package/src/lib/performance/diff-engine.d.ts +33 -0
  72. package/src/lib/performance/path-index.d.ts +25 -0
  73. package/src/lib/performance/update-engine.d.ts +32 -0
  74. package/src/lib/presets.d.ts +34 -0
  75. package/src/lib/security/security-validator.d.ts +33 -0
  76. package/src/lib/signal-tree.d.ts +3 -0
  77. package/src/lib/types.d.ts +301 -0
  78. package/src/lib/utils.d.ts +32 -0
package/README.md CHANGED
@@ -23,11 +23,11 @@ Modern bundlers (webpack 5+, esbuild, Rollup, Vite) **automatically tree-shake b
23
23
 
24
24
  ```ts
25
25
  // ✅ Recommended: Simple and clean
26
- import { signalTree, withBatching } from '@signaltree/core';
26
+ import { signalTree, batching } from '@signaltree/core';
27
27
 
28
28
  // ✅ Also fine: Explicit subpath (same bundle size)
29
29
  import { signalTree } from '@signaltree/core';
30
- import { withBatching } from '@signaltree/core/enhancers/batching';
30
+ import { batching } from '@signaltree/core/enhancers/batching';
31
31
  ```
32
32
 
33
33
  **Measured impact** (with modern bundlers):
@@ -90,7 +90,7 @@ Follow these principles for idiomatic SignalTree code:
90
90
  ### 1. Expose signals directly (no computed wrappers)
91
91
 
92
92
  ```typescript
93
- const tree = signalTree(initialState).with(withEntities());
93
+ const tree = signalTree(initialState).with(entities());
94
94
  const $ = tree.$; // Shorthand for state access
95
95
 
96
96
  // ✅ SignalTree-first: Direct signal exposure
@@ -115,7 +115,7 @@ export type UserTree = ReturnType<typeof createUserTree>;
115
115
 
116
116
  // Factory function - no explicit return type needed
117
117
  export function createUserTree() {
118
- const tree = signalTree(initialState).with(withEntities());
118
+ const tree = signalTree(initialState).with(entities());
119
119
  return {
120
120
  selectedUserId: tree.$.selected.userId, // Type inferred automatically
121
121
  // ...
@@ -351,7 +351,7 @@ effect(() => {
351
351
  Computed values become even more powerful with the built-in memoization enhancer:
352
352
 
353
353
  ```typescript
354
- import { signalTree, withMemoization } from '@signaltree/core';
354
+ import { signalTree, memoization } from '@signaltree/core';
355
355
 
356
356
  const tree = signalTree({
357
357
  items: Array.from({ length: 10000 }, (_, i) => ({
@@ -359,7 +359,7 @@ const tree = signalTree({
359
359
  value: Math.random(),
360
360
  category: `cat-${i % 10}`,
361
361
  })),
362
- }).with(withMemoization());
362
+ }).with(memoization());
363
363
 
364
364
  // Expensive computation - automatically cached by memoization enhancer
365
365
  const expensiveComputation = computed(() => {
@@ -479,7 +479,7 @@ tree.$.config.settings.nested.set(false); // ✅ boolean
479
479
 
480
480
  ### 3) Manual state management
481
481
 
482
- Core provides basic state updates. For advanced entity management, use the built-in `withEntities` enhancer:
482
+ Core provides basic state updates. For advanced entity management, use the built-in `entities` enhancer:
483
483
 
484
484
  ```typescript
485
485
  interface User {
@@ -568,22 +568,22 @@ All enhancers are exported directly from `@signaltree/core`:
568
568
 
569
569
  **Performance Enhancers:**
570
570
 
571
- - `withBatching()` - Batch updates to reduce recomputation and rendering
572
- - `withMemoization()` - Intelligent caching for expensive computations
573
- - `withHighPerformanceBatching()` - Advanced batching for high-frequency updates
571
+ - `batching()` - Batch updates to reduce recomputation and rendering
572
+ - `memoization()` - Intelligent caching for expensive computations
573
+ - `highPerformanceBatching()` - Advanced batching for high-frequency updates
574
574
  - `withHighPerformanceMemoization()` - Optimized memoization for large state trees
575
575
 
576
576
  **Data Management:**
577
577
 
578
- - `withEntities()` - Advanced CRUD operations for collections
578
+ - `entities()` - Advanced CRUD operations for collections
579
579
  - `createAsyncOperation()` - Async operation management with loading/error states
580
580
  - `trackAsync()` - Track async operations in your state
581
- - `withSerialization()` - State persistence and SSR support
582
- - `withPersistence()` - Auto-save to localStorage/IndexedDB
581
+ - `serialization()` - State persistence and SSR support
582
+ - `persistence()` - Auto-save to localStorage/IndexedDB
583
583
 
584
584
  **Development Tools:**
585
585
 
586
- - `withDevTools()` - Redux DevTools integration
586
+ - `devTools()` - Redux DevTools integration
587
587
  - `withTimeTravel()` - Undo/redo functionality
588
588
 
589
589
  **Presets:**
@@ -604,26 +604,26 @@ These are the **only** separate packages in the SignalTree ecosystem:
604
604
  **Basic Enhancement:**
605
605
 
606
606
  ```typescript
607
- import { signalTree, withBatching, withDevTools } from '@signaltree/core';
607
+ import { signalTree, batching, devTools } from '@signaltree/core';
608
608
 
609
609
  // Apply enhancers in order
610
610
  const tree = signalTree({ count: 0 }).with(
611
- withBatching(), // Performance optimization
612
- withDevTools() // Development tools
611
+ batching(), // Performance optimization
612
+ devTools() // Development tools
613
613
  );
614
614
  ```
615
615
 
616
616
  **Performance-Focused Stack:**
617
617
 
618
618
  ```typescript
619
- import { signalTree, withBatching, withMemoization, withEntities } from '@signaltree/core';
619
+ import { signalTree, batching, memoization, entities } from '@signaltree/core';
620
620
 
621
621
  const tree = signalTree({
622
622
  products: entityMap<Product>(),
623
623
  ui: { loading: false },
624
624
  })
625
- .with(withEntities()) // Efficient CRUD operations (auto-detects entityMap)
626
- .with(withBatching()); // Batch updates for optimal rendering
625
+ .with(entities()) // Efficient CRUD operations (auto-detects entityMap)
626
+ .with(batching()); // Batch updates for optimal rendering
627
627
 
628
628
  // Entity CRUD operations
629
629
  tree.$.products.addOne(newProduct);
@@ -636,14 +636,14 @@ const electronics = tree.$.products.all.filter((p) => p.category === 'electronic
636
636
  **Full-Stack Application:**
637
637
 
638
638
  ```typescript
639
- import { signalTree, withSerialization, withTimeTravel } from '@signaltree/core';
639
+ import { signalTree, serialization, withTimeTravel } from '@signaltree/core';
640
640
 
641
641
  const tree = signalTree({
642
642
  user: null as User | null,
643
643
  preferences: { theme: 'light' },
644
644
  }).with(
645
645
  // withAsync removed — API integration patterns are now covered by async helpers
646
- withSerialization({
646
+ serialization({
647
647
  // Auto-save to localStorage
648
648
  autoSave: true,
649
649
  storage: 'localStorage',
@@ -678,9 +678,9 @@ Enhancers can declare metadata for automatic dependency resolution:
678
678
  ```typescript
679
679
  // Enhancers are automatically ordered based on requirements
680
680
  const tree = signalTree(state).with(
681
- withDevTools(), // Requires: core, provides: debugging
682
- withBatching(), // Requires: core, provides: batching
683
- withMemoization() // Requires: batching, provides: caching
681
+ devTools(), // Requires: core, provides: debugging
682
+ batching(), // Requires: core, provides: batching
683
+ memoization() // Requires: batching, provides: caching
684
684
  );
685
685
  // Automatically ordered: batching -> memoization -> devtools
686
686
  ```
@@ -707,16 +707,16 @@ const customTree = signalTree(state, TREE_PRESETS.DASHBOARD);
707
707
  SignalTree Core includes all enhancer functionality built-in. No separate packages needed:
708
708
 
709
709
  ```typescript
710
- import { signalTree, entityMap, withEntities } from '@signaltree/core';
710
+ import { signalTree, entityMap, entities } from '@signaltree/core';
711
711
 
712
712
  // Without entityMap - use manual array updates
713
713
  const basic = signalTree({ users: [] as User[] });
714
714
  basic.$.users.update((users) => [...users, newUser]);
715
715
 
716
- // With entityMap + withEntities - use entity helpers
716
+ // With entityMap + entities - use entity helpers
717
717
  const enhanced = signalTree({
718
718
  users: entityMap<User>(),
719
- }).with(withEntities());
719
+ }).with(entities());
720
720
 
721
721
  enhanced.$.users.addOne(newUser); // ✅ Advanced CRUD operations
722
722
  enhanced.$.users.byId(123)(); // ✅ O(1) lookups
@@ -881,15 +881,15 @@ tree.effect(() => console.log('State changed'));
881
881
  ### Performance-Enhanced Composition
882
882
 
883
883
  ```typescript
884
- import { signalTree, withBatching, withMemoization } from '@signaltree/core';
884
+ import { signalTree, batching, memoization } from '@signaltree/core';
885
885
 
886
886
  // Add performance optimizations
887
887
  const tree = signalTree({
888
888
  products: [] as Product[],
889
889
  filters: { category: '', search: '' },
890
890
  }).with(
891
- withBatching(), // Batch updates for optimal rendering
892
- withMemoization() // Cache expensive computations
891
+ batching(), // Batch updates for optimal rendering
892
+ memoization() // Cache expensive computations
893
893
  );
894
894
 
895
895
  // Now supports batched updates
@@ -909,14 +909,14 @@ const filteredProducts = computed(() => {
909
909
  ### Data Management Composition
910
910
 
911
911
  ```typescript
912
- import { signalTree, entityMap, withEntities } from '@signaltree/core';
912
+ import { signalTree, entityMap, entities } from '@signaltree/core';
913
913
 
914
914
  // Add data management capabilities (+2.77KB total)
915
915
  const tree = signalTree({
916
916
  users: entityMap<User>(),
917
917
  posts: entityMap<Post>(),
918
918
  ui: { loading: false, error: null as string | null },
919
- }).with(withEntities());
919
+ }).with(entities());
920
920
 
921
921
  // Advanced entity operations via tree.$ accessor
922
922
  tree.$.users.addOne(newUser);
@@ -938,7 +938,7 @@ const appTree = signalTree({
938
938
  reports: entityMap<Report>(),
939
939
  },
940
940
  },
941
- }).with(withEntities());
941
+ }).with(entities());
942
942
 
943
943
  // Access nested entities using tree.$ accessor
944
944
  appTree.$.app.data.users.selectBy((u) => u.isAdmin); // Filtered signal
@@ -963,7 +963,7 @@ async function fetchUsers() {
963
963
  ### Full-Featured Development Composition
964
964
 
965
965
  ```typescript
966
- import { signalTree, withBatching, withEntities, withSerialization, withTimeTravel, withDevTools } from '@signaltree/core';
966
+ import { signalTree, batching, entities, serialization, withTimeTravel, devTools } from '@signaltree/core';
967
967
 
968
968
  // Full development stack (example)
969
969
  const tree = signalTree({
@@ -973,10 +973,10 @@ const tree = signalTree({
973
973
  data: { users: [], posts: [] },
974
974
  },
975
975
  }).with(
976
- withBatching(), // Performance
977
- withEntities(), // Data management
976
+ batching(), // Performance
977
+ entities(), // Data management
978
978
  // withAsync removed — use async helpers for API integration
979
- withSerialization({
979
+ serialization({
980
980
  // State persistence
981
981
  autoSave: true,
982
982
  storage: 'localStorage',
@@ -985,7 +985,7 @@ const tree = signalTree({
985
985
  // Undo/redo
986
986
  maxHistory: 50,
987
987
  }),
988
- withDevTools({
988
+ devTools({
989
989
  // Debug tools (dev only)
990
990
  name: 'MyApp',
991
991
  trace: true,
@@ -1004,14 +1004,14 @@ tree.save(); // Persistence
1004
1004
  ### Production-Ready Composition
1005
1005
 
1006
1006
  ```typescript
1007
- import { signalTree, withBatching, withEntities, withSerialization } from '@signaltree/core';
1007
+ import { signalTree, batching, entities, serialization } from '@signaltree/core';
1008
1008
 
1009
1009
  // Production build (no dev tools)
1010
1010
  const tree = signalTree(initialState).with(
1011
- withBatching(), // Performance optimization
1012
- withEntities(), // Data management
1011
+ batching(), // Performance optimization
1012
+ entities(), // Data management
1013
1013
  // withAsync removed — use async helpers for API integration
1014
- withSerialization({
1014
+ serialization({
1015
1015
  // User preferences
1016
1016
  autoSave: true,
1017
1017
  storage: 'localStorage',
@@ -1025,18 +1025,18 @@ const tree = signalTree(initialState).with(
1025
1025
  ### Conditional Enhancement
1026
1026
 
1027
1027
  ```typescript
1028
- import { signalTree, withBatching, withEntities, withDevTools, withTimeTravel } from '@signaltree/core';
1028
+ import { signalTree, batching, entities, devTools, withTimeTravel } from '@signaltree/core';
1029
1029
 
1030
1030
  const isDevelopment = process.env['NODE_ENV'] === 'development';
1031
1031
 
1032
1032
  // Conditional enhancement based on environment
1033
1033
  const tree = signalTree(state).with(
1034
- withBatching(), // Always include performance
1035
- withEntities(), // Always include data management
1034
+ batching(), // Always include performance
1035
+ entities(), // Always include data management
1036
1036
  ...(isDevelopment
1037
1037
  ? [
1038
1038
  // Development-only features
1039
- withDevTools(),
1039
+ devTools(),
1040
1040
  withTimeTravel(),
1041
1041
  ]
1042
1042
  : [])
@@ -1074,10 +1074,10 @@ Start with core and grow incrementally:
1074
1074
  const tree = signalTree(state);
1075
1075
 
1076
1076
  // Phase 2: Add performance when needed
1077
- const tree2 = tree.with(withBatching());
1077
+ const tree2 = tree.with(batching());
1078
1078
 
1079
1079
  // Phase 3: Add data management for collections
1080
- const tree3 = tree2.with(withEntities());
1080
+ const tree3 = tree2.with(entities());
1081
1081
 
1082
1082
  // Phase 4: Add async for API integration
1083
1083
  // withAsync removed — no explicit async enhancer; use async helpers instead
@@ -1090,11 +1090,11 @@ const tree3 = tree2.with(withEntities());
1090
1090
  let tree = signalTree(initialState);
1091
1091
 
1092
1092
  if (isDevelopment) {
1093
- tree = tree.with(withDevTools());
1093
+ tree = tree.with(devTools());
1094
1094
  }
1095
1095
 
1096
1096
  if (needsPerformance) {
1097
- tree = tree.with(withBatching(), withMemoization());
1097
+ tree = tree.with(batching(), memoization());
1098
1098
  }
1099
1099
 
1100
1100
  if (needsTimeTravel) {
@@ -1365,7 +1365,7 @@ tree.effect(fn); // Create reactive effects
1365
1365
  tree.subscribe(fn); // Manual subscriptions
1366
1366
  tree.destroy(); // Cleanup resources
1367
1367
 
1368
- // Entity helpers (when using entityMap + withEntities)
1368
+ // Entity helpers (when using entityMap + entities)
1369
1369
  // tree.$.users.addOne(user); // Add single entity
1370
1370
  // tree.$.users.byId(id)(); // O(1) lookup by ID
1371
1371
  // tree.$.users.all; // Get all as array
@@ -1377,22 +1377,22 @@ tree.destroy(); // Cleanup resources
1377
1377
  SignalTree Core includes all enhancers built-in:
1378
1378
 
1379
1379
  ```typescript
1380
- import { signalTree, withBatching, withMemoization, withTimeTravel } from '@signaltree/core';
1380
+ import { signalTree, batching, memoization, withTimeTravel } from '@signaltree/core';
1381
1381
 
1382
1382
  // All enhancers available from @signaltree/core
1383
- const tree = signalTree(initialState).with(withBatching(), withMemoization(), withTimeTravel());
1383
+ const tree = signalTree(initialState).with(batching(), memoization(), withTimeTravel());
1384
1384
  ```
1385
1385
 
1386
1386
  ### Available enhancers
1387
1387
 
1388
1388
  All enhancers are included in `@signaltree/core`:
1389
1389
 
1390
- - **withBatching()** - Batch multiple updates for better performance
1391
- - **withMemoization()** - Intelligent caching & performance optimization
1392
- - **withEntities()** - Advanced entity management & CRUD operations
1393
- - **withDevTools()** - Redux DevTools integration for debugging
1390
+ - **batching()** - Batch multiple updates for better performance
1391
+ - **memoization()** - Intelligent caching & performance optimization
1392
+ - **entities()** - Advanced entity management & CRUD operations
1393
+ - **devTools()** - Redux DevTools integration for debugging
1394
1394
  - **withTimeTravel()** - Undo/redo functionality & state history
1395
- - **withSerialization()** - State persistence & SSR support
1395
+ - **serialization()** - State persistence & SSR support
1396
1396
  - **createDevTree()** - Pre-configured development setup
1397
1397
  - **TREE_PRESETS** - Common configuration patterns (PERFORMANCE, DASHBOARD, etc.)
1398
1398
 
@@ -1408,9 +1408,9 @@ Perfect for:
1408
1408
 
1409
1409
  Consider enhancers when you need:
1410
1410
 
1411
- - ⚡ Performance optimization (withBatching, withMemoization)
1412
- - 🐛 Advanced debugging (withDevTools, withTimeTravel)
1413
- - 📦 Entity management (withEntities)
1411
+ - ⚡ Performance optimization (batching, memoization)
1412
+ - 🐛 Advanced debugging (devTools, withTimeTravel)
1413
+ - 📦 Entity management (entities)
1414
1414
 
1415
1415
  Consider separate packages when you need:
1416
1416
 
@@ -1540,21 +1540,21 @@ All enhancers are now consolidated in the core package. The following features a
1540
1540
 
1541
1541
  ### Performance & Optimization
1542
1542
 
1543
- - **withBatching()** (+1.27KB gzipped) - Batch multiple updates for better performance
1544
- - **withMemoization()** (+2.33KB gzipped) - Intelligent caching & performance optimization
1543
+ - **batching()** (+1.27KB gzipped) - Batch multiple updates for better performance
1544
+ - **memoization()** (+2.33KB gzipped) - Intelligent caching & performance optimization
1545
1545
 
1546
1546
  ### Advanced Features
1547
1547
 
1548
- - **withEntities()** (+0.97KB gzipped) - Enhanced CRUD operations & entity management
1548
+ - **entities()** (+0.97KB gzipped) - Enhanced CRUD operations & entity management
1549
1549
 
1550
1550
  ### Development Tools
1551
1551
 
1552
- - **withDevTools()** (+2.49KB gzipped) - Development tools & Redux DevTools integration
1552
+ - **devTools()** (+2.49KB gzipped) - Development tools & Redux DevTools integration
1553
1553
  - **withTimeTravel()** (+1.75KB gzipped) - Undo/redo functionality & state history
1554
1554
 
1555
1555
  ### Integration & Convenience
1556
1556
 
1557
- - **withSerialization()** (+0.84KB gzipped) - State persistence & SSR support
1557
+ - **serialization()** (+0.84KB gzipped) - State persistence & SSR support
1558
1558
  - **ecommercePreset()** - Pre-configured setups for e-commerce applications
1559
1559
  - **dashboardPreset()** - Pre-configured setups for dashboard applications
1560
1560
 
@@ -1569,12 +1569,12 @@ npm install @signaltree/core
1569
1569
  # Everything is available from @signaltree/core:
1570
1570
  import {
1571
1571
  signalTree,
1572
- withBatching,
1573
- withMemoization,
1574
- withEntities,
1575
- withDevTools,
1572
+ batching,
1573
+ memoization,
1574
+ entities,
1575
+ devTools,
1576
1576
  withTimeTravel,
1577
- withSerialization,
1577
+ serialization,
1578
1578
  ecommercePreset,
1579
1579
  dashboardPreset
1580
1580
  } from '@signaltree/core';
@@ -1691,7 +1691,7 @@ npm install @signaltree/enterprise
1691
1691
 
1692
1692
  ```typescript
1693
1693
  import { signalTree } from '@signaltree/core';
1694
- import { withEnterpriseOptimizations } from '@signaltree/enterprise';
1694
+ import { enterpriseOptimizations } from '@signaltree/enterprise';
1695
1695
 
1696
1696
  const tree = signalTree({
1697
1697
  // Large application state with hundreds of signals
@@ -1708,7 +1708,7 @@ const tree = signalTree({
1708
1708
  // ... many more modules
1709
1709
  },
1710
1710
  }).with(
1711
- withEnterpriseOptimizations({
1711
+ enterpriseOptimizations({
1712
1712
  enablePathIndex: true,
1713
1713
  enableMemoryOptimizations: true,
1714
1714
  enablePerformanceMonitoring: true,
@@ -1757,13 +1757,13 @@ npm install --save-dev @signaltree/guardrails
1757
1757
 
1758
1758
  ```typescript
1759
1759
  import { signalTree } from '@signaltree/core';
1760
- import { withGuardrails } from '@signaltree/guardrails';
1760
+ import { guardrails } from '@signaltree/guardrails';
1761
1761
 
1762
1762
  const tree = signalTree({
1763
1763
  users: [] as User[],
1764
1764
  posts: [] as Post[],
1765
1765
  }).with(
1766
- withGuardrails({
1766
+ guardrails({
1767
1767
  hotPathThreshold: 100, // Warn if signal accessed >100 times/sec
1768
1768
  memoryLeakThreshold: 50, // Warn if >50 uncleaned signals
1769
1769
  budgets: {
@@ -0,0 +1,6 @@
1
+ const SHARED_DEFAULTS = Object.freeze({
2
+ PATH_CACHE_SIZE: 1000
3
+ });
4
+ const DEFAULT_PATH_CACHE_SIZE = SHARED_DEFAULTS.PATH_CACHE_SIZE;
5
+
6
+ export { DEFAULT_PATH_CACHE_SIZE, SHARED_DEFAULTS };
@@ -0,0 +1,41 @@
1
+ function deepEqual(a, b) {
2
+ if (a === b) return true;
3
+ if (a == null || b == null) return a === b;
4
+ const typeA = typeof a;
5
+ const typeB = typeof b;
6
+ if (typeA !== typeB) return false;
7
+ if (typeA !== 'object') return false;
8
+ if (a instanceof Date && b instanceof Date) {
9
+ return a.getTime() === b.getTime();
10
+ }
11
+ if (a instanceof RegExp && b instanceof RegExp) {
12
+ return a.source === b.source && a.flags === b.flags;
13
+ }
14
+ if (a instanceof Map && b instanceof Map) {
15
+ if (a.size !== b.size) return false;
16
+ for (const [key, value] of a) {
17
+ if (!b.has(key) || !deepEqual(value, b.get(key))) return false;
18
+ }
19
+ return true;
20
+ }
21
+ if (a instanceof Set && b instanceof Set) {
22
+ if (a.size !== b.size) return false;
23
+ for (const value of a) {
24
+ if (!b.has(value)) return false;
25
+ }
26
+ return true;
27
+ }
28
+ if (Array.isArray(a)) {
29
+ if (!Array.isArray(b) || a.length !== b.length) return false;
30
+ return a.every((item, index) => deepEqual(item, b[index]));
31
+ }
32
+ if (Array.isArray(b)) return false;
33
+ const objA = a;
34
+ const objB = b;
35
+ const keysA = Object.keys(objA);
36
+ const keysB = Object.keys(objB);
37
+ if (keysA.length !== keysB.length) return false;
38
+ return keysA.every(key => key in objB && deepEqual(objA[key], objB[key]));
39
+ }
40
+
41
+ export { deepEqual };
@@ -0,0 +1,189 @@
1
+ import { applyState, isNodeAccessor } from '../../lib/utils.js';
2
+
3
+ let updateQueue = [];
4
+ let isUpdating = false;
5
+ let flushTimeoutId;
6
+ let currentBatchingConfig = {};
7
+ function addToQueue(update, config = currentBatchingConfig) {
8
+ const maxSize = config.maxBatchSize ?? 100;
9
+ if (update.path) {
10
+ updateQueue = updateQueue.filter(existing => existing.path !== update.path);
11
+ }
12
+ updateQueue.push(update);
13
+ if (updateQueue.length > maxSize) {
14
+ flushUpdates();
15
+ return true;
16
+ }
17
+ scheduleFlush(config);
18
+ return false;
19
+ }
20
+ function scheduleFlush(config) {
21
+ if (flushTimeoutId !== undefined) {
22
+ clearTimeout(flushTimeoutId);
23
+ }
24
+ const delay = config.autoFlushDelay ?? config.debounceMs ?? 16;
25
+ flushTimeoutId = setTimeout(() => {
26
+ flushUpdates();
27
+ }, delay);
28
+ }
29
+ function flushUpdates() {
30
+ if (isUpdating) return;
31
+ let queue;
32
+ do {
33
+ if (updateQueue.length === 0) return;
34
+ isUpdating = true;
35
+ queue = updateQueue;
36
+ updateQueue = [];
37
+ if (flushTimeoutId !== undefined) {
38
+ clearTimeout(flushTimeoutId);
39
+ flushTimeoutId = undefined;
40
+ }
41
+ queue.sort((a, b) => (b.depth ?? 0) - (a.depth ?? 0));
42
+ try {
43
+ queue.forEach(({
44
+ fn
45
+ }) => fn());
46
+ } finally {
47
+ isUpdating = false;
48
+ }
49
+ } while (updateQueue.length > 0);
50
+ }
51
+ function batchUpdates(fn, path) {
52
+ const startTime = performance.now();
53
+ const depth = 0;
54
+ const update = {
55
+ fn,
56
+ startTime,
57
+ depth,
58
+ path
59
+ };
60
+ const wasFlushed = addToQueue(update, currentBatchingConfig);
61
+ if (!wasFlushed) {
62
+ const isTimedOut = currentBatchingConfig.batchTimeoutMs && updateQueue.length > 0 && startTime - updateQueue[0].startTime >= currentBatchingConfig.batchTimeoutMs;
63
+ if (isTimedOut) {
64
+ flushUpdates();
65
+ } else if (!isUpdating && updateQueue.length > 0) {
66
+ queueMicrotask(() => {
67
+ flushUpdates();
68
+ });
69
+ }
70
+ }
71
+ }
72
+ function batchingWithConfig(config = {}) {
73
+ const enabled = config.enabled ?? true;
74
+ if (enabled) {
75
+ currentBatchingConfig = {
76
+ ...currentBatchingConfig,
77
+ ...config
78
+ };
79
+ }
80
+ const enhancer = tree => {
81
+ if (!enabled) {
82
+ const enhanced = tree;
83
+ enhanced.batch = updater => {
84
+ try {
85
+ tree.batchUpdate(updater);
86
+ } catch {
87
+ try {
88
+ updater(enhanced.state);
89
+ } catch {}
90
+ }
91
+ };
92
+ enhanced.batchUpdate = updater => {
93
+ try {
94
+ const current = tree();
95
+ const updates = updater(current);
96
+ applyState(enhanced.state, updates);
97
+ } catch (err) {
98
+ try {
99
+ tree.batchUpdate(updater);
100
+ } catch {}
101
+ }
102
+ };
103
+ return enhanced;
104
+ }
105
+ const originalTreeCall = tree.bind(tree);
106
+ const enhancedTree = function (...args) {
107
+ if (args.length === 0) {
108
+ return originalTreeCall();
109
+ } else {
110
+ batchUpdates(() => {
111
+ if (args.length === 1) {
112
+ const arg = args[0];
113
+ if (typeof arg === 'function') {
114
+ originalTreeCall(arg);
115
+ } else {
116
+ originalTreeCall(arg);
117
+ }
118
+ }
119
+ });
120
+ }
121
+ };
122
+ Object.setPrototypeOf(enhancedTree, Object.getPrototypeOf(tree));
123
+ Object.assign(enhancedTree, tree);
124
+ if ('state' in tree) {
125
+ Object.defineProperty(enhancedTree, 'state', {
126
+ value: tree.state,
127
+ enumerable: false,
128
+ configurable: true
129
+ });
130
+ }
131
+ if ('$' in tree) {
132
+ Object.defineProperty(enhancedTree, '$', {
133
+ value: tree.$,
134
+ enumerable: false,
135
+ configurable: true
136
+ });
137
+ }
138
+ enhancedTree.batchUpdate = updater => {
139
+ batchUpdates(() => {
140
+ const current = originalTreeCall();
141
+ const updates = updater(current);
142
+ Object.entries(updates).forEach(([key, value]) => {
143
+ const property = enhancedTree.state[key];
144
+ if (property && 'set' in property) {
145
+ property.set(value);
146
+ } else if (isNodeAccessor(property)) {
147
+ property(value);
148
+ }
149
+ });
150
+ });
151
+ };
152
+ return enhancedTree;
153
+ };
154
+ return enhancer;
155
+ }
156
+ function batching(config = {}) {
157
+ return batchingWithConfig(config);
158
+ }
159
+ function highPerformanceBatching() {
160
+ return batchingWithConfig({
161
+ enabled: true,
162
+ maxBatchSize: 200,
163
+ debounceMs: 0
164
+ });
165
+ }
166
+ function flushBatchedUpdates() {
167
+ if (updateQueue.length > 0) {
168
+ const queue = updateQueue.slice();
169
+ updateQueue = [];
170
+ isUpdating = false;
171
+ queue.sort((a, b) => (b.depth ?? 0) - (a.depth ?? 0));
172
+ queue.forEach(({
173
+ fn
174
+ }) => {
175
+ fn();
176
+ });
177
+ }
178
+ }
179
+ function hasPendingUpdates() {
180
+ return updateQueue.length > 0;
181
+ }
182
+ function getBatchQueueSize() {
183
+ return updateQueue.length;
184
+ }
185
+ Object.assign((config = {}) => batchingWithConfig(config), {
186
+ highPerformance: highPerformanceBatching
187
+ });
188
+
189
+ export { batching, batchingWithConfig, flushBatchedUpdates, getBatchQueueSize, hasPendingUpdates, highPerformanceBatching };