@signaltree/core 1.1.9 β†’ 2.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
@@ -1,32 +1,32 @@
1
- # 🌳 SignalTree Core
1
+ # SignalTree Core
2
2
 
3
- The foundation package for SignalTree - featuring revolutionary recursive typing with deep nesting support and excellent performance.
3
+ Foundation package for SignalTree. Provides recursive typing, deep nesting support, and strong performance.
4
4
 
5
- ## ✨ What is @signaltree/core?
5
+ ## What is @signaltree/core?
6
6
 
7
- SignalTree Core is the lightweight (5.1KB gzipped) foundation that provides:
7
+ SignalTree Core is a lightweight (about 7.25KB gzipped) package that provides:
8
8
 
9
- - **πŸ”₯ Revolutionary Recursive Typing** with deep nesting support and strong type inference
10
- - **⚑ Excellent Performance** - 0.021ms at 15+ levels with consistent speed
11
- - **πŸ† Strong Type Safety** with TypeScript inference at 25+ recursive levels
12
- - **πŸ’Ύ Memory Efficient** through structural sharing and lazy signals
13
- - **🌳 Lightweight Abstractions** for recursive patterns
14
- - **πŸ“¦ Compact Bundle Size** - Complete recursive power in just 5.1KB gzipped
9
+ - Recursive typing with deep nesting and accurate type inference
10
+ - Fast operations with sub‑millisecond measurements at 5–20+ levels
11
+ - Strong TypeScript safety across nested structures
12
+ - Memory efficiency via structural sharing and lazy signals
13
+ - Small API surface with zero-cost abstractions
14
+ - Compact bundle size suited for production
15
15
 
16
- ### πŸ”₯ Recursive Depth Performance Metrics
16
+ ### Depth performance (Sept 2025, averaged)
17
17
 
18
- Core performance scales exceptionally across all depth levels:
18
+ Indicative measurements across different depths:
19
19
 
20
- | **Depth Level** | **Execution Time** | **Type Safety** | **Performance Grade** |
21
- | -------------------------- | ------------------ | --------------- | --------------------- |
22
- | **Basic (5 levels)** | 0.012ms | βœ… Perfect | A+ Excellent |
23
- | **Medium (10 levels)** | 0.015ms | βœ… Perfect | A+ Excellent |
24
- | **Extreme (15 levels)** | **0.021ms** | βœ… Perfect | A+ **Outstanding** πŸ”₯ |
25
- | **Unlimited (20+ levels)** | 0.023ms | βœ… Perfect | A+ **Exceptional** πŸš€ |
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 |
26
26
 
27
- _Revolutionary achievement: Performance remains sub-millisecond with consistent scaling._
27
+ Note: Results vary by environment; figures are averaged across multiple runs.
28
28
 
29
- ## πŸš€ Quick Start
29
+ ## Quick start
30
30
 
31
31
  ### Installation
32
32
 
@@ -34,12 +34,12 @@ _Revolutionary achievement: Performance remains sub-millisecond with consistent
34
34
  npm install @signaltree/core
35
35
  ```
36
36
 
37
- ### Elegant Usage - Deep Nesting Support
37
+ ### Deep nesting example
38
38
 
39
39
  ```typescript
40
40
  import { signalTree } from '@signaltree/core';
41
41
 
42
- // Powerful: Strong type inference at deep nesting levels!
42
+ // Strong type inference at deep nesting levels
43
43
  const tree = signalTree({
44
44
  enterprise: {
45
45
  divisions: {
@@ -58,7 +58,7 @@ const tree = signalTree({
58
58
  tests: {
59
59
  extreme: {
60
60
  depth: 15,
61
- performance: 0.021, // ms - Excellent!
61
+ performance: 0.098, // ms (averaged)
62
62
  typeInference: true,
63
63
  },
64
64
  },
@@ -78,21 +78,24 @@ const tree = signalTree({
78
78
  },
79
79
  });
80
80
 
81
- // Perfect type inference at extreme depth - no 'any' types!
81
+ // Type inference at deep nesting levels
82
82
  const performance = tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.performance();
83
83
 
84
- console.log(`Excellent performance: ${performance}ms`); // 0.021ms
84
+ console.log(`Performance: ${performance}ms`); // ~0.098ms (averaged)
85
85
 
86
86
  // Type-safe updates at unlimited depth
87
87
  tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth.set(25); // Perfect type safety!
88
-
89
- Note: Prefer calling signals to read their current value (e.g. `tree.$.path.to.value()`). The older `unwrap()` helper is still present for compatibility but using the callable signal form is the recommended approach for new code and examples.
90
88
  ```
91
89
 
92
- ### Basic Usage (Perfect for Getting Started)
90
+ ### Basic usage
91
+
92
+ ```typescript
93
+ import { signalTree } from '@signaltree/core';
93
94
 
94
- count: 0,
95
- message: 'Hello World',
95
+ // Create a simple tree
96
+ const tree = signalTree({
97
+ count: 0,
98
+ message: 'Hello World',
96
99
  });
97
100
 
98
101
  // Read values (these are Angular signals)
@@ -103,23 +106,22 @@ console.log(tree.$.message()); // 'Hello World'
103
106
  tree.$.count.set(5);
104
107
  tree.$.message.set('Updated!');
105
108
 
106
- // Use in Angular components
109
+ // Use in an Angular component
107
110
  @Component({
108
- template: ` <div>Count: {{ tree.$.count() }}</div>
111
+ template: ` <div>Count: {{ tree.$.count() }}</div>
109
112
  <div>Message: {{ tree.$.message() }}</div>
110
113
  <button (click)="increment()">+1</button>`,
111
114
  })
112
115
  class SimpleComponent {
113
- tree = tree;
116
+ tree = tree;
114
117
 
115
- increment() {
116
- this.tree.$.count.update((n) => n + 1);
117
- }
118
+ increment() {
119
+ this.tree.$.count.update((n) => n + 1);
120
+ }
118
121
  }
122
+ ```
119
123
 
120
- ````
121
-
122
- ### Intermediate Usage (Nested State)
124
+ ### Intermediate usage (nested state)
123
125
 
124
126
  ```typescript
125
127
  // Create hierarchical state
@@ -155,9 +157,9 @@ effect(() => {
155
157
  console.log('Loading started...');
156
158
  }
157
159
  });
158
- ````
160
+ ```
159
161
 
160
- ### Advanced Usage (Full State Tree)
162
+ ### Advanced usage (full state tree)
161
163
 
162
164
  ```typescript
163
165
  interface AppState {
@@ -211,13 +213,13 @@ tree.update(state => ({
211
213
  notifications: [
212
214
  ...state.ui.notifications,
213
215
  // Get entire state as plain object
214
- const currentState = tree.$();
216
+ const currentState = tree.unwrap();
215
217
  console.log('Current app state:', currentState);
216
218
  ```
217
219
 
218
- ## πŸ“¦ Core Features
220
+ ## Core features
219
221
 
220
- ### 1. Hierarchical Signal Trees
222
+ ### 1) Hierarchical signal trees
221
223
 
222
224
  Create deeply nested reactive state with automatic type inference:
223
225
 
@@ -234,7 +236,7 @@ tree.$.settings.theme.set('light'); // type-checked value
234
236
  tree.$.todos.update((todos) => [...todos, newTodo]); // array operations
235
237
  ```
236
238
 
237
- ### 2. TypeScript Inference Excellence
239
+ ### 2) TypeScript inference
238
240
 
239
241
  SignalTree provides complete type inference without manual typing:
240
242
 
@@ -260,7 +262,7 @@ tree.$.config.theme.set('light'); // ❌ Type error ('dark' const)
260
262
  tree.$.config.settings.nested.set(false); // βœ… boolean
261
263
  ```
262
264
 
263
- ### 3. Manual State Management
265
+ ### 3) Manual state management
264
266
 
265
267
  Core provides basic state updates - entity management requires `@signaltree/entities`:
266
268
 
@@ -294,7 +296,7 @@ const userById = (id: string) => computed(() => tree.$.users().find((user) => us
294
296
  const activeUsers = computed(() => tree.$.users().filter((user) => user.active));
295
297
  ```
296
298
 
297
- ### 4. Manual Async State Management
299
+ ### 4) Manual async state management
298
300
 
299
301
  Core provides basic state updates - async helpers require `@signaltree/async`:
300
302
 
@@ -339,7 +341,35 @@ class UsersComponent {
339
341
  }
340
342
  ```
341
343
 
342
- ### 5. Performance Optimizations
344
+ ### 5) Performance considerations
345
+
346
+ ### 6) Enhancers and composition
347
+
348
+ Enhancers are optional, tree‑shakable extensions that augment a `SignalTree` via `tree.with(...)`.
349
+
350
+ - `createEnhancer(meta, fn)` attaches metadata to an enhancer function
351
+ - Metadata fields: `name`, `requires`, `provides`
352
+ - Enhancers may mutate the passed tree (preferred) or return a new object
353
+ - A topological sort orders enhancers that declare metadata; on cycles, fallback to user order in debug mode
354
+
355
+ Examples:
356
+
357
+ ```typescript
358
+ import { signalTree } from '@signaltree/core';
359
+ import { withBatching } from '@signaltree/batching';
360
+ import { withDevtools } from '@signaltree/devtools';
361
+
362
+ // Apply in explicit order
363
+ const tree = signalTree({ count: 0 }).with(withBatching, withDevtools);
364
+ ```
365
+
366
+ Presets can provide composed enhancers for quicker onboarding:
367
+
368
+ ```typescript
369
+ import { createDevTree } from '@signaltree/presets';
370
+ const { enhancer } = createDevTree();
371
+ const tree = signalTree({ count: 0 }).with(enhancer);
372
+ ```
343
373
 
344
374
  Core includes several performance optimizations:
345
375
 
@@ -374,9 +404,9 @@ tree.update((state) => ({
374
404
  }));
375
405
  ```
376
406
 
377
- ## πŸš€ Error Handling Examples
407
+ ## Error handling examples
378
408
 
379
- ### Manual Async Error Handling
409
+ ### Manual async error handling
380
410
 
381
411
  ```typescript
382
412
  const tree = signalTree({
@@ -437,7 +467,7 @@ class ErrorHandlingComponent {
437
467
  }
438
468
  ```
439
469
 
440
- ### State Update Error Handling
470
+ ### State update error handling
441
471
 
442
472
  ```typescript
443
473
  const tree = signalTree({
@@ -475,7 +505,7 @@ function safeUpdateItem(id: string, updates: Partial<Item>) {
475
505
  }
476
506
  ```
477
507
 
478
- ## πŸ”— Package Composition Patterns
508
+ ## Package composition patterns
479
509
 
480
510
  ### Basic Composition
481
511
 
@@ -487,33 +517,33 @@ const tree = signalTree({
487
517
  state: 'initial',
488
518
  });
489
519
 
490
- // Extend with additional packages via pipe
491
- const enhancedTree = tree.pipe(
520
+ // Extend with additional packages via .with(...)
521
+ const enhancedTree = tree.with(
492
522
  // Add features as needed
493
523
  someFeatureFunction()
494
524
  );
495
525
  ```
496
526
 
497
- ### Modular Enhancement Pattern
527
+ ### Modular enhancement pattern
498
528
 
499
529
  ```typescript
500
530
  // Start minimal, add features as needed
501
531
  let tree = signalTree(initialState);
502
532
 
503
533
  if (isDevelopment) {
504
- tree = tree.pipe(withDevtools());
534
+ tree = tree.with(withDevTools());
505
535
  }
506
536
 
507
537
  if (needsPerformance) {
508
- tree = tree.pipe(withBatching(), withMemoization());
538
+ tree = tree.with(withBatching(), withMemoization());
509
539
  }
510
540
 
511
541
  if (needsTimeTravel) {
512
- tree = tree.pipe(withTimeTravel());
542
+ tree = tree.with(withTimeTravel());
513
543
  }
514
544
  ```
515
545
 
516
- ### Service-Based Pattern
546
+ ### Service-based pattern
517
547
 
518
548
  ```typescript
519
549
  @Injectable()
@@ -546,11 +576,11 @@ class AppStateService {
546
576
  }
547
577
  ```
548
578
 
549
- ## ⚑ Performance Benchmarks
579
+ ## Performance benchmarks
550
580
 
551
- > **Performance Grade: A+** ⭐ - Sub-millisecond operations across all core functions
581
+ > Sub‑millisecond operations across common core functions
552
582
 
553
- ### Recursive Depth Scaling Performance
583
+ ### Recursive depth scaling (illustrative)
554
584
 
555
585
  | **Depth Level** | **Execution Time** | **Scaling Factor** | **Type Inference** | **Memory Usage** |
556
586
  | -------------------------- | ------------------ | ------------------ | ------------------ | ---------------- |
@@ -559,9 +589,9 @@ class AppStateService {
559
589
  | **Extreme (15 levels)** | **0.021ms** | **1.75x** | βœ… Perfect | ~1.3MB |
560
590
  | **Unlimited (20+ levels)** | 0.023ms | 1.92x | βœ… Perfect | ~1.4MB |
561
591
 
562
- _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
592
+ Note: Scaling depends on state shape and hardware.
563
593
 
564
- ### SignalTree Core Performance Results (Measured)
594
+ ### Example operation timings
565
595
 
566
596
  | Operation | SignalTree Core | Notes |
567
597
  | --------------------------- | --------------- | ---------------- |
@@ -572,16 +602,16 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
572
602
  | Computation (cached) | **0.094ms** | Memoized result |
573
603
  | Memory per 1K entities | **1.2MB** | Measured usage |
574
604
 
575
- ### Advanced Performance Features
605
+ ### Feature impact
576
606
 
577
607
  | Feature | SignalTree Core | With Extensions | Notes |
578
608
  | ------------------- | ----------------- | ---------------------- | ---------------------- |
579
609
  | Batching efficiency | Standard | **455.8x improvement** | vs non-batched |
580
610
  | Memoization speedup | Basic | **197.9x speedup** | vs non-memoized |
581
611
  | Memory efficiency | **Optimized** | **Further optimized** | Lazy signals + cleanup |
582
- | Bundle impact | **5.1KB gzipped** | **+15KB max** | Tree-shakeable |
612
+ | Bundle impact | **7.1KB gzipped** | **+15KB max** | Tree-shakeable |
583
613
 
584
- ### Developer Experience (Core Package)
614
+ ### Developer experience (core)
585
615
 
586
616
  | Metric | SignalTree Core | Traditional State Mgmt | **Improvement** |
587
617
  | ----------------------- | --------------- | ---------------------- | --------------- |
@@ -590,7 +620,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
590
620
  | Setup complexity | **Minimal** | Complex | **Simplified** |
591
621
  | API surface | **Small** | Large | **Focused** |
592
622
 
593
- ### Memory Usage Comparison
623
+ ### Memory usage comparison
594
624
 
595
625
  | Operation | SignalTree Core | NgRx | Akita | Native Signals |
596
626
  | ------------------------ | --------------- | ------ | ------ | -------------- |
@@ -598,7 +628,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
598
628
  | 10K entities | 8.1MB | 28.5MB | 22.1MB | 15.2MB |
599
629
  | Deep nesting (10 levels) | 145KB | 890KB | 720KB | 340KB |
600
630
 
601
- ### TypeScript Inference Speed
631
+ ### TypeScript inference speed
602
632
 
603
633
  ```typescript
604
634
  // SignalTree: Instant inference
@@ -612,7 +642,7 @@ interface State { deeply: { nested: { state: { with: { types: string } } } } }
612
642
  const store: Store<State> = ...; // Requires manual interface definition
613
643
  ```
614
644
 
615
- ## 🎯 Real-World Example
645
+ ## Example
616
646
 
617
647
  ```typescript
618
648
  // Complete user management component
@@ -730,16 +760,16 @@ class UserManagerComponent implements OnInit {
730
760
  }));
731
761
 
732
762
  // Get entire state as plain object
733
- const currentState = tree.$();
763
+ const currentState = tree.unwrap();
734
764
  console.log('Current app state:', currentState);
735
765
 
736
766
  ```
737
767
  });
738
768
  ```
739
769
 
740
- ## πŸ“¦ Core Features
770
+ ## Core features
741
771
 
742
- ### Hierarchical Signal Trees
772
+ ### Hierarchical signal trees
743
773
 
744
774
  ```typescript
745
775
  const tree = signalTree({
@@ -754,7 +784,7 @@ tree.$.settings.theme.set('light');
754
784
  tree.$.todos.update((todos) => [...todos, newTodo]);
755
785
  ```
756
786
 
757
- ### Manual Entity Management
787
+ ### Manual entity management
758
788
 
759
789
  ```typescript
760
790
  // Manual CRUD operations
@@ -780,7 +810,7 @@ const allTodos = computed(() => tree.$.todos());
780
810
  const todoCount = computed(() => tree.$.todos().length);
781
811
  ```
782
812
 
783
- ### Manual Async State Management
813
+ ### Manual async state management
784
814
 
785
815
  ```typescript
786
816
  async function loadUsers() {
@@ -802,7 +832,7 @@ async function handleLoadUsers() {
802
832
  }
803
833
  ```
804
834
 
805
- ### Reactive Effects
835
+ ### Reactive effects
806
836
 
807
837
  ```typescript
808
838
  // Create reactive effects
@@ -816,7 +846,7 @@ const unsubscribe = tree.subscribe((state) => {
816
846
  });
817
847
  ```
818
848
 
819
- ## 🎯 Core API Reference
849
+ ## Core API reference
820
850
 
821
851
  ### signalTree()
822
852
 
@@ -830,7 +860,7 @@ const tree = signalTree(initialState, config?);
830
860
  // State access
831
861
  tree.$.property(); // Read signal value
832
862
  tree.$.property.set(value); // Update signal
833
- // Use callable signal access to read the current values: `tree.$()`
863
+ tree.unwrap(); // Get plain object
834
864
 
835
865
  // Tree operations
836
866
  tree.update(updater); // Update entire tree
@@ -844,7 +874,7 @@ tree.asyncAction(fn, config?); // Async actions (requires @signaltree/async)
844
874
  tree.asyncAction(fn, config?); // Create async action
845
875
  ```
846
876
 
847
- ## πŸ”Œ Extending with Optional Packages
877
+ ## Extending with optional packages
848
878
 
849
879
  SignalTree Core can be extended with additional features:
850
880
 
@@ -854,11 +884,11 @@ import { withBatching } from '@signaltree/batching';
854
884
  import { withMemoization } from '@signaltree/memoization';
855
885
  import { withTimeTravel } from '@signaltree/time-travel';
856
886
 
857
- // Compose features using pipe
858
- const tree = signalTree(initialState).pipe(withBatching(), withMemoization(), withTimeTravel());
887
+ // Compose features using .with(...)
888
+ const tree = signalTree(initialState).with(withBatching(), withMemoization(), withTimeTravel());
859
889
  ```
860
890
 
861
- ### Available Extensions
891
+ ### Available extensions
862
892
 
863
893
  - **@signaltree/batching** (+1.1KB gzipped) - Batch multiple updates
864
894
  - **@signaltree/memoization** (+1.7KB gzipped) - Intelligent caching & performance
@@ -869,9 +899,9 @@ const tree = signalTree(initialState).pipe(withBatching(), withMemoization(), wi
869
899
  - **@signaltree/time-travel** (+1.5KB gzipped) - Undo/redo functionality
870
900
  - **@signaltree/ng-forms** (+3.4KB gzipped) - Complete Angular forms integration
871
901
  - **@signaltree/serialization** (+3.6KB gzipped) - State persistence & SSR support
872
- - **@signaltree/presets** (+0.5KB gzipped) - Environment-based configurations
902
+ - **@signaltree/presets** (+0.8KB gzipped) - Environment-based configurations
873
903
 
874
- ## 🎯 When to Use Core Only
904
+ ## When to use core only
875
905
 
876
906
  Perfect for:
877
907
 
@@ -888,7 +918,7 @@ Consider extensions when you need:
888
918
  - πŸ“ Complex forms (ng-forms)
889
919
  - πŸ”§ Middleware patterns (middleware)
890
920
 
891
- ## πŸ”„ Migration from NgRx
921
+ ## Migration from NgRx
892
922
 
893
923
  ```typescript
894
924
  // Step 1: Create parallel tree
@@ -904,7 +934,7 @@ users = this.tree.$.users;
904
934
  // Step 3: Replace effects with manual async operations
905
935
  // Before (NgRx)
906
936
  loadUsers$ = createEffect(() =>
907
- this.actions$.pipe(
937
+ this.actions$.with(
908
938
  ofType(loadUsers),
909
939
  switchMap(() => this.api.getUsers())
910
940
  )
@@ -926,7 +956,7 @@ loadUsers = tree.asyncAction(() => api.getUsers(), {
926
956
  });
927
957
  ```
928
958
 
929
- ## πŸ“– Examples
959
+ ## Examples
930
960
 
931
961
  ### Simple Counter
932
962
 
@@ -996,7 +1026,7 @@ class UsersComponent {
996
1026
  }
997
1027
  ```
998
1028
 
999
- ## οΏ½ Available Extension Packages
1029
+ ## Available extension packages
1000
1030
 
1001
1031
  Extend the core with optional feature packages:
1002
1032
 
@@ -1018,7 +1048,7 @@ Extend the core with optional feature packages:
1018
1048
 
1019
1049
  ### Integration & Convenience
1020
1050
 
1021
- - **[@signaltree/presets](../presets)** (+0.5KB gzipped) - Pre-configured setups for common patterns
1051
+ - **[@signaltree/presets](../presets)** (+0.8KB gzipped) - Pre-configured setups for common patterns
1022
1052
  - **[@signaltree/ng-forms](../ng-forms)** (+3.4KB gzipped) - Complete Angular Forms integration
1023
1053
 
1024
1054
  ### Quick Start with Extensions
@@ -1034,7 +1064,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
1034
1064
  npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/async @signaltree/entities @signaltree/devtools @signaltree/time-travel @signaltree/presets @signaltree/ng-forms
1035
1065
  ```
1036
1066
 
1037
- ## οΏ½πŸ”— Links
1067
+ ## Links
1038
1068
 
1039
1069
  - [SignalTree Documentation](https://signaltree.io)
1040
1070
  - [GitHub Repository](https://github.com/JBorgia/signaltree)
@@ -1043,7 +1073,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
1043
1073
 
1044
1074
  ## πŸ“„ License
1045
1075
 
1046
- MIT License - see the [LICENSE](../../LICENSE) file for details.
1076
+ MIT License with AI Training Restriction - see the [LICENSE](../../LICENSE) file for details.
1047
1077
 
1048
1078
  ---
1049
1079