@signaltree/core 2.0.3 → 3.0.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 CHANGED
@@ -4,7 +4,7 @@ Foundation package for SignalTree. Provides recursive typing, deep nesting suppo
4
4
 
5
5
  ## What is @signaltree/core?
6
6
 
7
- SignalTree Core is a lightweight (about 7.20KB gzipped) package that provides:
7
+ SignalTree Core is a lightweight package that provides:
8
8
 
9
9
  - Recursive typing with deep nesting and accurate type inference
10
10
  - Fast operations with sub‑millisecond measurements at 5–20+ levels
@@ -13,18 +13,42 @@ SignalTree Core is a lightweight (about 7.20KB gzipped) package that provides:
13
13
  - Small API surface with zero-cost abstractions
14
14
  - Compact bundle size suited for production
15
15
 
16
- ### Depth performance (Sept 2025, averaged)
16
+ ### Callable leaf signals (DX sugar only)
17
17
 
18
- Indicative measurements across different depths:
18
+ SignalTree provides TypeScript support for callable syntax on leaf signals as developer experience sugar:
19
19
 
20
- | Depth level | Avg time | Type safety | Range |
21
- | ----------- | -------- | ----------- | ------------- |
22
- | 5 levels | 0.061ms | ✅ | 0.041–0.133ms |
23
- | 10 levels | 0.109ms | ✅ | 0.060–0.181ms |
24
- | 15 levels | 0.098ms | ✅ | 0.088–0.126ms |
25
- | 20+ levels | 0.103ms | ✅ | 0.100–0.106ms |
20
+ ```typescript
21
+ // TypeScript accepts this syntax (with proper tooling):
22
+ tree.$.name('Jane'); // Set value
23
+ tree.$.count((n) => n + 1); // Update with function
24
+
25
+ // At build time, transforms convert to:
26
+ tree.$.name.set('Jane'); // Direct Angular signal API
27
+ tree.$.count.update((n) => n + 1); // Direct Angular signal API
28
+
29
+ // Reading always works directly:
30
+ const name = tree.$.name(); // No transform needed
31
+ ```
32
+
33
+ **Key Points:**
34
+
35
+ - **Zero runtime overhead**: No Proxy wrappers or runtime hooks
36
+ - **Build-time only**: AST transform converts callable syntax to direct `.set/.update` calls
37
+ - **Optional**: Use `@signaltree/callable-syntax` transform or stick with direct `.set/.update`
38
+ - **Type-safe**: Full TypeScript support via module augmentation
39
+
40
+ **Function-valued leaves:**
41
+ When a leaf stores a function as its value, use direct `.set(fn)` to assign. Callable `sig(fn)` is treated as an updater.
42
+
43
+ **Setup:**
44
+ Install `@signaltree/callable-syntax` and configure your build tool to apply the transform. Without the transform, use `.set/.update` directly.
45
+
46
+ ### Measuring performance and size
26
47
 
27
- Note: Results vary by environment; figures are averaged across multiple runs.
48
+ Performance and bundle size vary by app shape, build tooling, device, and runtime. To get meaningful results for your environment:
49
+
50
+ - Use the **Benchmark Orchestrator** in the demo app to run calibrated, scenario-based benchmarks across supported libraries with **real-world frequency weighting**. It applies research-based multipliers derived from 40,000+ developer surveys and GitHub analysis, reports statistical summaries (median/p95/p99/stddev), alternates runs to reduce bias, and can export CSV/JSON. When available, memory usage is also reported.
51
+ - Use the bundle analysis scripts in `scripts/` to measure your min+gz sizes. Sizes are approximate and depend on tree-shaking and configuration.
28
52
 
29
53
  ## Quick start
30
54
 
@@ -58,7 +82,6 @@ const tree = signalTree({
58
82
  tests: {
59
83
  extreme: {
60
84
  depth: 15,
61
- performance: 0.098, // ms (averaged)
62
85
  typeInference: true,
63
86
  },
64
87
  },
@@ -79,9 +102,8 @@ const tree = signalTree({
79
102
  });
80
103
 
81
104
  // Type inference at deep nesting levels
82
- const performance = tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.performance();
83
-
84
- console.log(`Performance: ${performance}ms`); // ~0.098ms (averaged)
105
+ const depth = tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth();
106
+ console.log(`Depth: ${depth}`);
85
107
 
86
108
  // Type-safe updates at unlimited depth
87
109
  tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth(25); // Perfect type safety!
@@ -159,6 +181,99 @@ effect(() => {
159
181
  });
160
182
  ```
161
183
 
184
+ ### Reactive computations with computed()
185
+
186
+ SignalTree works seamlessly with Angular's `computed()` for creating efficient reactive computations. These computations automatically update when their dependencies change and are memoized for optimal performance.
187
+
188
+ ```typescript
189
+ import { computed, effect } from '@angular/core';
190
+ import { signalTree } from '@signaltree/core';
191
+
192
+ const tree = signalTree({
193
+ users: [
194
+ { id: '1', name: 'Alice', active: true, role: 'admin' },
195
+ { id: '2', name: 'Bob', active: false, role: 'user' },
196
+ { id: '3', name: 'Charlie', active: true, role: 'user' },
197
+ ],
198
+ filters: {
199
+ showActive: true,
200
+ role: 'all' as 'all' | 'admin' | 'user',
201
+ },
202
+ });
203
+
204
+ // Basic computed - automatically memoized
205
+ const userCount = computed(() => tree.$.users().length);
206
+
207
+ // Complex filtering computation
208
+ const filteredUsers = computed(() => {
209
+ const users = tree.$.users();
210
+ const filters = tree.$.filters();
211
+
212
+ return users.filter((user) => {
213
+ if (filters.showActive && !user.active) return false;
214
+ if (filters.role !== 'all' && user.role !== filters.role) return false;
215
+ return true;
216
+ });
217
+ });
218
+
219
+ // Derived computation from other computed values
220
+ const activeAdminCount = computed(() => filteredUsers().filter((user) => user.role === 'admin' && user.active).length);
221
+
222
+ // Performance-critical computation with complex logic
223
+ const userStatistics = computed(() => {
224
+ const users = tree.$.users();
225
+
226
+ return {
227
+ total: users.length,
228
+ active: users.filter((u) => u.active).length,
229
+ admins: users.filter((u) => u.role === 'admin').length,
230
+ averageNameLength: users.reduce((acc, u) => acc + u.name.length, 0) / users.length,
231
+ };
232
+ });
233
+
234
+ // Dynamic computed functions (factory pattern)
235
+ const userById = (id: string) => computed(() => tree.$.users().find((user) => user.id === id));
236
+
237
+ // Usage in effects
238
+ effect(() => {
239
+ console.log(`Filtered users: ${filteredUsers().length}`);
240
+ console.log(`Statistics:`, userStatistics());
241
+ });
242
+
243
+ // Best Practices:
244
+ // 1. Use computed() for derived state that depends on signals
245
+ // 2. Keep computations pure - no side effects
246
+ // 3. Leverage automatic memoization for expensive operations
247
+ // 4. Chain computed values for complex transformations
248
+ // 5. Use factory functions for parameterized computations
249
+ ```
250
+
251
+ ### Performance optimization with memoization
252
+
253
+ When combined with `@signaltree/memoization`, computed values become even more powerful:
254
+
255
+ ```typescript
256
+ import { withMemoization } from '@signaltree/memoization';
257
+
258
+ const tree = signalTree({
259
+ items: Array.from({ length: 10000 }, (_, i) => ({
260
+ id: i,
261
+ value: Math.random(),
262
+ category: `cat-${i % 10}`,
263
+ })),
264
+ }).with(withMemoization());
265
+
266
+ // Expensive computation - automatically cached by memoization enhancer
267
+ const expensiveComputation = computed(() => {
268
+ return tree.$.items()
269
+ .filter((item) => item.value > 0.5)
270
+ .reduce((acc, item) => acc + Math.sin(item.value * Math.PI), 0);
271
+ });
272
+
273
+ // The computation only runs when tree.$.items() actually changes
274
+ // Subsequent calls return cached result
275
+ ```
276
+
162
277
  ### Advanced usage (full state tree)
163
278
 
164
279
  ```typescript
@@ -300,7 +415,7 @@ const activeUsers = computed(() => tree.$.users().filter((user) => user.active))
300
415
 
301
416
  ### 4) Manual async state management
302
417
 
303
- Core provides basic state updates - async helpers require `@signaltree/async`:
418
+ Core provides basic state updates - async helpers are now provided via `@signaltree/middleware` helpers:
304
419
 
305
420
  ```typescript
306
421
  const tree = signalTree({
@@ -353,25 +468,25 @@ SignalTree Core provides the foundation, but its real power comes from composabl
353
468
 
354
469
  **Performance Enhancers:**
355
470
 
356
- - `@signaltree/batching` (+1.27KB) - Batch updates for 455.8x performance improvement
357
- - `@signaltree/memoization` (+1.80KB) - Intelligent caching with 197.9x speedup
471
+ - `@signaltree/batching` - Batch updates to reduce recomputation and rendering
472
+ - `@signaltree/memoization` - Intelligent caching for expensive computations
358
473
 
359
474
  **Data Management:**
360
475
 
361
- - `@signaltree/entities` (+0.97KB) - Advanced CRUD operations for collections
362
- - `@signaltree/async` (+1.80KB) - Async actions with loading states
363
- - `@signaltree/serialization` (+4.62KB) - State persistence and SSR support
476
+ - `@signaltree/entities` - Advanced CRUD operations for collections
477
+ - Async helpers are provided via `@signaltree/middleware` (createAsyncOperation / trackAsync)
478
+ - `@signaltree/serialization` - State persistence and SSR support
364
479
 
365
480
  **Development Tools:**
366
481
 
367
- - `@signaltree/devtools` (+2.49KB) - Redux DevTools integration
368
- - `@signaltree/time-travel` (+1.75KB) - Undo/redo functionality
482
+ - `@signaltree/devtools` - Redux DevTools integration
483
+ - `@signaltree/time-travel` - Undo/redo functionality
369
484
 
370
485
  **Integration:**
371
486
 
372
- - `@signaltree/ng-forms` (+3.38KB) - Angular Forms integration
373
- - `@signaltree/middleware` (+1.38KB) - State interceptors and logging
374
- - `@signaltree/presets` (+0.84KB) - Pre-configured common patterns
487
+ - `@signaltree/ng-forms` - Angular Forms integration
488
+ - `@signaltree/middleware` - State interceptors and logging
489
+ - `@signaltree/presets` - Pre-configured common patterns
375
490
 
376
491
  #### Composition Patterns
377
492
 
@@ -418,7 +533,6 @@ products.selectBy((p) => p.category === 'electronics');
418
533
  **Full-Stack Application:**
419
534
 
420
535
  ```typescript
421
- import { withAsync } from '@signaltree/async';
422
536
  import { withSerialization } from '@signaltree/serialization';
423
537
  import { withTimeTravel } from '@signaltree/time-travel';
424
538
 
@@ -426,7 +540,7 @@ const tree = signalTree({
426
540
  user: null as User | null,
427
541
  preferences: { theme: 'light' },
428
542
  }).with(
429
- withAsync(), // API integration
543
+ // withAsync removed API integration patterns are now covered by middleware helpers
430
544
  withSerialization({
431
545
  // Auto-save to localStorage
432
546
  autoSave: true,
@@ -642,7 +756,7 @@ SignalTree Core is designed for modular composition. Start minimal and add featu
642
756
  ```typescript
643
757
  import { signalTree } from '@signaltree/core';
644
758
 
645
- // Core provides the foundation (7.25KB)
759
+ // Core provides the foundation
646
760
  const tree = signalTree({
647
761
  users: [] as User[],
648
762
  ui: { loading: false },
@@ -661,13 +775,13 @@ import { signalTree } from '@signaltree/core';
661
775
  import { withBatching } from '@signaltree/batching';
662
776
  import { withMemoization } from '@signaltree/memoization';
663
777
 
664
- // Add performance optimizations (+3.07KB total)
778
+ // Add performance optimizations
665
779
  const tree = signalTree({
666
780
  products: [] as Product[],
667
781
  filters: { category: '', search: '' },
668
782
  }).with(
669
- withBatching(), // 455.8x performance gain for multiple updates
670
- withMemoization() // 197.9x speedup for expensive computations
783
+ withBatching(), // Batch updates for optimal rendering
784
+ withMemoization() // Cache expensive computations
671
785
  );
672
786
 
673
787
  // Now supports batched updates
@@ -689,7 +803,6 @@ const filteredProducts = computed(() => {
689
803
  ```typescript
690
804
  import { signalTree } from '@signaltree/core';
691
805
  import { withEntities } from '@signaltree/entities';
692
- import { withAsync } from '@signaltree/async';
693
806
 
694
807
  // Add data management capabilities (+2.77KB total)
695
808
  const tree = signalTree({
@@ -697,8 +810,7 @@ const tree = signalTree({
697
810
  posts: [] as Post[],
698
811
  ui: { loading: false, error: null },
699
812
  }).with(
700
- withEntities(), // Advanced CRUD operations
701
- withAsync() // Async state management
813
+ withEntities() // Advanced CRUD operations
702
814
  );
703
815
 
704
816
  // Advanced entity operations
@@ -721,12 +833,11 @@ const fetchUsers = tree.asyncAction(async () => api.getUsers(), {
721
833
  import { signalTree } from '@signaltree/core';
722
834
  import { withBatching } from '@signaltree/batching';
723
835
  import { withEntities } from '@signaltree/entities';
724
- import { withAsync } from '@signaltree/async';
725
836
  import { withSerialization } from '@signaltree/serialization';
726
837
  import { withTimeTravel } from '@signaltree/time-travel';
727
838
  import { withDevtools } from '@signaltree/devtools';
728
839
 
729
- // Full development stack (~22KB total)
840
+ // Full development stack (example)
730
841
  const tree = signalTree({
731
842
  app: {
732
843
  user: null as User | null,
@@ -736,7 +847,7 @@ const tree = signalTree({
736
847
  }).with(
737
848
  withBatching(), // Performance
738
849
  withEntities(), // Data management
739
- withAsync(), // API calls
850
+ // withAsync removed — use middleware helpers for API integration
740
851
  withSerialization({
741
852
  // State persistence
742
853
  autoSave: true,
@@ -766,14 +877,13 @@ tree.save(); // Persistence
766
877
  import { signalTree } from '@signaltree/core';
767
878
  import { withBatching } from '@signaltree/batching';
768
879
  import { withEntities } from '@signaltree/entities';
769
- import { withAsync } from '@signaltree/async';
770
880
  import { withSerialization } from '@signaltree/serialization';
771
881
 
772
882
  // Production build (no dev tools)
773
883
  const tree = signalTree(initialState).with(
774
884
  withBatching(), // Performance optimization
775
885
  withEntities(), // Data management
776
- withAsync(), // API integration
886
+ // withAsync removed — use middleware helpers for API integration
777
887
  withSerialization({
778
888
  // User preferences
779
889
  autoSave: true,
@@ -829,16 +939,9 @@ const dashboardTree = dashboardPreset({
829
939
  // Includes: batching, memoization, devtools
830
940
  ```
831
941
 
832
- ### Bundle Size Planning
942
+ ### Measuring bundle size
833
943
 
834
- | Composition Strategy | Bundle Size | Use Case |
835
- | ------------------------ | ----------- | ------------------------------ |
836
- | Core only | 7.25KB | Simple state, prototypes |
837
- | + Batching + Memoization | 10.32KB | Performance-critical apps |
838
- | + Entities + Async | 13.09KB | Data-driven applications |
839
- | + Serialization | 17.71KB | Persistent state, SSR |
840
- | + DevTools + TimeTravel | 21.95KB | Development (disabled in prod) |
841
- | Full ecosystem | 27.55KB | Feature-rich applications |
944
+ Bundle sizes depend on your build, tree-shaking, and which enhancers you include. Use the scripts in `scripts/` to analyze min+gz for your configuration.
842
945
 
843
946
  ### Migration Strategy
844
947
 
@@ -855,7 +958,7 @@ const tree2 = tree.with(withBatching());
855
958
  const tree3 = tree2.with(withEntities());
856
959
 
857
960
  // Phase 4: Add async for API integration
858
- const tree4 = tree3.with(withAsync());
961
+ // withAsync removed — no explicit async enhancer; use middleware helpers instead
859
962
 
860
963
  // Each phase is fully functional and production-ready
861
964
  ```
@@ -910,71 +1013,9 @@ class AppStateService {
910
1013
  }
911
1014
  ```
912
1015
 
913
- ## Performance benchmarks
914
-
915
- > Sub‑millisecond operations across common core functions
916
-
917
- ### Recursive depth scaling (illustrative)
1016
+ ## Measuring performance
918
1017
 
919
- | **Depth Level** | **Execution Time** | **Scaling Factor** | **Type Inference** | **Memory Usage** |
920
- | -------------------------- | ------------------ | ------------------ | ------------------ | ---------------- |
921
- | **Basic (5 levels)** | 0.012ms | 1.0x (baseline) | ✅ Perfect | ~1.1MB |
922
- | **Medium (10 levels)** | 0.015ms | 1.25x | ✅ Perfect | ~1.2MB |
923
- | **Extreme (15 levels)** | **0.021ms** | **1.75x** | ✅ Perfect | ~1.3MB |
924
- | **Unlimited (20+ levels)** | 0.023ms | 1.92x | ✅ Perfect | ~1.4MB |
925
-
926
- Note: Scaling depends on state shape and hardware.
927
-
928
- ### Example operation timings
929
-
930
- | Operation | SignalTree Core | Notes |
931
- | --------------------------- | --------------- | ---------------- |
932
- | Tree initialization (small) | **0.031ms** | 27 nodes |
933
- | Tree initialization (large) | **0.745ms** | 341 nodes |
934
- | Single update | **0.188ms** | Property update |
935
- | Nested update (5 levels) | **0.188ms** | Deep tree update |
936
- | Computation (cached) | **0.094ms** | Memoized result |
937
- | Memory per 1K entities | **1.2MB** | Measured usage |
938
-
939
- ### Feature impact
940
-
941
- | Feature | SignalTree Core | With Extensions | Notes |
942
- | ------------------- | ------------------ | ---------------------- | ---------------------- |
943
- | Batching efficiency | Standard | **455.8x improvement** | vs non-batched |
944
- | Memoization speedup | Basic | **197.9x speedup** | vs non-memoized |
945
- | Memory efficiency | **Optimized** | **Further optimized** | Lazy signals + cleanup |
946
- | Bundle impact | **7.25KB gzipped** | **+20KB max** | Tree-shakeable |
947
-
948
- ### Developer experience (core)
949
-
950
- | Metric | SignalTree Core | Traditional State Mgmt | **Improvement** |
951
- | ----------------------- | --------------- | ---------------------- | --------------- |
952
- | Lines of code (counter) | **4 lines** | 18-32 lines | **68-88% less** |
953
- | Files required | **1 file** | 3-4 files | **75% fewer** |
954
- | Setup complexity | **Minimal** | Complex | **Simplified** |
955
- | API surface | **Small** | Large | **Focused** |
956
-
957
- ### Memory usage comparison
958
-
959
- | Operation | SignalTree Core | NgRx | Akita | Native Signals |
960
- | ------------------------ | --------------- | ------ | ------ | -------------- |
961
- | 1K entities | 1.2MB | 4.2MB | 3.5MB | 2.3MB |
962
- | 10K entities | 8.1MB | 28.5MB | 22.1MB | 15.2MB |
963
- | Deep nesting (10 levels) | 145KB | 890KB | 720KB | 340KB |
964
-
965
- ### TypeScript inference speed
966
-
967
- ```typescript
968
- // SignalTree: Instant inference
969
- const tree = signalTree({
970
- deeply: { nested: { state: { with: { types: 'instant' } } } }
971
- });
972
- tree.$.deeply.nested.state.with.types.set('updated'); // ✅ <1ms
973
-
974
- // Manual typing required with other solutions
975
- interface State { deeply: { nested: { state: { with: { types: string } } } } }
976
- const store: Store<State> = ...; // Requires manual interface definition
977
- ```
1018
+ For fair, reproducible measurements that reflect your app and hardware, use the **Benchmark Orchestrator** in the demo. It calibrates runs per scenario and library, applies **real-world frequency weighting** based on research analysis, reports robust statistics, and supports CSV/JSON export. Avoid copying fixed numbers from docs; results vary.
978
1019
 
979
1020
  ## Example
980
1021
 
@@ -1204,7 +1245,7 @@ tree.destroy(); // Cleanup resources
1204
1245
 
1205
1246
  // Extended features (require additional packages)
1206
1247
  tree.entities<T>(key); // Entity helpers (requires @signaltree/entities)
1207
- tree.asyncAction(fn, config?); // Async actions (requires @signaltree/async)
1248
+ // tree.asyncAction(fn, config?) example removed use middleware helpers instead
1208
1249
  tree.asyncAction(fn, config?); // Create async action
1209
1250
  ```
1210
1251
 
@@ -1224,16 +1265,16 @@ const tree = signalTree(initialState).with(withBatching(), withMemoization(), wi
1224
1265
 
1225
1266
  ### Available extensions
1226
1267
 
1227
- - **@signaltree/batching** (+1.27KB gzipped) - Batch multiple updates
1228
- - **@signaltree/memoization** (+1.80KB gzipped) - Intelligent caching & performance
1229
- - **@signaltree/middleware** (+1.38KB gzipped) - Middleware system & taps
1230
- - **@signaltree/async** (+1.80KB gzipped) - Advanced async actions & states
1231
- - **@signaltree/entities** (+929B gzipped) - Advanced entity management
1232
- - **@signaltree/devtools** (+2.49KB gzipped) - Redux DevTools integration
1233
- - **@signaltree/time-travel** (+1.75KB gzipped) - Undo/redo functionality
1234
- - **@signaltree/ng-forms** (+3.38KB gzipped) - Complete Angular forms integration
1235
- - **@signaltree/serialization** (+4.62KB gzipped) - State persistence & SSR support
1236
- - **@signaltree/presets** (+0.84KB gzipped) - Environment-based configurations
1268
+ - **@signaltree/batching** - Batch multiple updates
1269
+ - **@signaltree/memoization** - Intelligent caching & performance
1270
+ - **@signaltree/middleware** - Middleware system & taps
1271
+ - Async helpers moved to `@signaltree/middleware` - advanced async operations & loading states
1272
+ - **@signaltree/entities** - Advanced entity management
1273
+ - **@signaltree/devtools** - Redux DevTools integration
1274
+ - **@signaltree/time-travel** - Undo/redo functionality
1275
+ - **@signaltree/ng-forms** - Complete Angular forms integration
1276
+ - **@signaltree/serialization** - State persistence & SSR support
1277
+ - **@signaltree/presets** - Environment-based configurations
1237
1278
 
1238
1279
  ## When to use core only
1239
1280
 
@@ -1284,7 +1325,7 @@ async loadUsers() {
1284
1325
  }
1285
1326
  }
1286
1327
 
1287
- // Or use async actions with @signaltree/async
1328
+ // Or use middleware helpers for async actions (createAsyncOperation / trackAsync)
1288
1329
  loadUsers = tree.asyncAction(() => api.getUsers(), {
1289
1330
  onSuccess: (users) => ({ users }),
1290
1331
  });
@@ -1367,23 +1408,23 @@ Extend the core with optional feature packages:
1367
1408
  ### Performance & Optimization
1368
1409
 
1369
1410
  - **[@signaltree/batching](../batching)** (+1.27KB gzipped) - Batch multiple updates for better performance
1370
- - **[@signaltree/memoization](../memoization)** (+1.80KB gzipped) - Intelligent caching & performance optimization
1411
+ - **[@signaltree/memoization](../memoization)** (+2.33KB gzipped) - Intelligent caching & performance optimization
1371
1412
 
1372
1413
  ### Advanced Features
1373
1414
 
1374
- - **[@signaltree/middleware](../middleware)** (+1.2KB gzipped) - Middleware system & state interceptors
1375
- - **[@signaltree/async](../async)** (+1.7KB gzipped) - Advanced async operations & loading states
1376
- - **[@signaltree/entities](../entities)** (+929B gzipped) - Enhanced CRUD operations & entity management
1415
+ - **[@signaltree/middleware](../middleware)** (+1.89KB gzipped) - Middleware system & state interceptors
1416
+ - Async helpers moved to middleware package (see `packages/middleware`)
1417
+ - **[@signaltree/entities](../entities)** (+0.97KB gzipped) - Enhanced CRUD operations & entity management
1377
1418
 
1378
1419
  ### Development Tools
1379
1420
 
1380
- - **[@signaltree/devtools](../devtools)** (+2.3KB gzipped) - Development tools & Redux DevTools integration
1381
- - **[@signaltree/time-travel](../time-travel)** (+1.5KB gzipped) - Undo/redo functionality & state history
1421
+ - **[@signaltree/devtools](../devtools)** (+2.49KB gzipped) - Development tools & Redux DevTools integration
1422
+ - **[@signaltree/time-travel](../time-travel)** (+1.75KB gzipped) - Undo/redo functionality & state history
1382
1423
 
1383
1424
  ### Integration & Convenience
1384
1425
 
1385
- - **[@signaltree/presets](../presets)** (+0.8KB gzipped) - Pre-configured setups for common patterns
1386
- - **[@signaltree/ng-forms](../ng-forms)** (+3.4KB gzipped) - Complete Angular Forms integration
1426
+ - **[@signaltree/presets](../presets)** (+0.84KB gzipped) - Pre-configured setups for common patterns
1427
+ - **[@signaltree/ng-forms](../ng-forms)** (+3.38KB gzipped) - Complete Angular Forms integration
1387
1428
 
1388
1429
  ### Quick Start with Extensions
1389
1430
 
@@ -1395,7 +1436,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization
1395
1436
  npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/devtools @signaltree/time-travel
1396
1437
 
1397
1438
  # All packages (full-featured)
1398
- npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/async @signaltree/entities @signaltree/devtools @signaltree/time-travel @signaltree/presets @signaltree/ng-forms
1439
+ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/entities @signaltree/devtools @signaltree/time-travel @signaltree/presets @signaltree/ng-forms
1399
1440
  ```
1400
1441
 
1401
1442
  ## Links
@@ -1116,5 +1116,5 @@ function applyEnhancer(tree, enhancer) {
1116
1116
  return enhancer(tree);
1117
1117
  }
1118
1118
 
1119
- export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree, unwrap };
1119
+ export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree };
1120
1120
  //# sourceMappingURL=signaltree-core.mjs.map