@signaltree/core 1.1.9 β†’ 2.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/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
- 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.
87
+ tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth(25); // Perfect type safety!
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)
@@ -100,26 +103,25 @@ console.log(tree.$.count()); // 0
100
103
  console.log(tree.$.message()); // 'Hello World'
101
104
 
102
105
  // Update values
103
- tree.$.count.set(5);
104
- tree.$.message.set('Updated!');
106
+ tree.$.count(5);
107
+ tree.$.message('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((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
@@ -139,9 +141,9 @@ const tree = signalTree({
139
141
  });
140
142
 
141
143
  // Access nested signals with full type safety
142
- tree.$.user.name.set('Jane Doe');
143
- tree.$.user.preferences.theme.set('light');
144
- tree.$.ui.loading.set(true);
144
+ tree.$.user.name('Jane Doe');
145
+ tree.$.user.preferences.theme('light');
146
+ tree.$.ui.loading(true);
145
147
 
146
148
  // Computed values from nested state
147
149
  const userDisplayName = computed(() => {
@@ -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 {
@@ -185,39 +187,41 @@ const tree = signalTree<AppState>({
185
187
  auth: {
186
188
  user: null,
187
189
  token: null,
188
- isAuthenticated: false
190
+ isAuthenticated: false,
189
191
  },
190
192
  data: {
191
193
  users: [],
192
194
  posts: [],
193
- cache: {}
195
+ cache: {},
194
196
  },
195
197
  ui: {
196
198
  theme: 'light',
197
199
  sidebar: { open: true, width: 250 },
198
- notifications: []
199
- }
200
+ notifications: [],
201
+ },
200
202
  });
201
203
 
202
204
  // Complex updates with type safety
203
- tree.update(state => ({
205
+ tree((state) => ({
204
206
  auth: {
205
207
  ...state.auth,
206
208
  user: { id: '1', name: 'John' },
207
- isAuthenticated: true
209
+ isAuthenticated: true,
208
210
  },
209
211
  ui: {
210
212
  ...state.ui,
211
- notifications: [
212
- ...state.ui.notifications,
213
- // Get entire state as plain object
214
- const currentState = tree.$();
213
+ notifications: [...state.ui.notifications, { id: '1', message: 'Welcome!', type: 'success' }],
214
+ },
215
+ }));
216
+
217
+ // Get entire state as plain object
218
+ const currentState = tree();
215
219
  console.log('Current app state:', currentState);
216
220
  ```
217
221
 
218
- ## πŸ“¦ Core Features
222
+ ## Core features
219
223
 
220
- ### 1. Hierarchical Signal Trees
224
+ ### 1) Hierarchical signal trees
221
225
 
222
226
  Create deeply nested reactive state with automatic type inference:
223
227
 
@@ -234,7 +238,7 @@ tree.$.settings.theme.set('light'); // type-checked value
234
238
  tree.$.todos.update((todos) => [...todos, newTodo]); // array operations
235
239
  ```
236
240
 
237
- ### 2. TypeScript Inference Excellence
241
+ ### 2) TypeScript inference
238
242
 
239
243
  SignalTree provides complete type inference without manual typing:
240
244
 
@@ -260,7 +264,7 @@ tree.$.config.theme.set('light'); // ❌ Type error ('dark' const)
260
264
  tree.$.config.settings.nested.set(false); // βœ… boolean
261
265
  ```
262
266
 
263
- ### 3. Manual State Management
267
+ ### 3) Manual state management
264
268
 
265
269
  Core provides basic state updates - entity management requires `@signaltree/entities`:
266
270
 
@@ -294,7 +298,7 @@ const userById = (id: string) => computed(() => tree.$.users().find((user) => us
294
298
  const activeUsers = computed(() => tree.$.users().filter((user) => user.active));
295
299
  ```
296
300
 
297
- ### 4. Manual Async State Management
301
+ ### 4) Manual async state management
298
302
 
299
303
  Core provides basic state updates - async helpers require `@signaltree/async`:
300
304
 
@@ -339,7 +343,35 @@ class UsersComponent {
339
343
  }
340
344
  ```
341
345
 
342
- ### 5. Performance Optimizations
346
+ ### 5) Performance considerations
347
+
348
+ ### 6) Enhancers and composition
349
+
350
+ Enhancers are optional, tree‑shakable extensions that augment a `SignalTree` via `tree.with(...)`.
351
+
352
+ - `createEnhancer(meta, fn)` attaches metadata to an enhancer function
353
+ - Metadata fields: `name`, `requires`, `provides`
354
+ - Enhancers may mutate the passed tree (preferred) or return a new object
355
+ - A topological sort orders enhancers that declare metadata; on cycles, fallback to user order in debug mode
356
+
357
+ Examples:
358
+
359
+ ```typescript
360
+ import { signalTree } from '@signaltree/core';
361
+ import { withBatching } from '@signaltree/batching';
362
+ import { withDevtools } from '@signaltree/devtools';
363
+
364
+ // Apply in explicit order
365
+ const tree = signalTree({ count: 0 }).with(withBatching, withDevtools);
366
+ ```
367
+
368
+ Presets can provide composed enhancers for quicker onboarding:
369
+
370
+ ```typescript
371
+ import { createDevTree } from '@signaltree/presets';
372
+ const { enhancer } = createDevTree();
373
+ const tree = signalTree({ count: 0 }).with(enhancer);
374
+ ```
343
375
 
344
376
  Core includes several performance optimizations:
345
377
 
@@ -374,9 +406,9 @@ tree.update((state) => ({
374
406
  }));
375
407
  ```
376
408
 
377
- ## πŸš€ Error Handling Examples
409
+ ## Error handling examples
378
410
 
379
- ### Manual Async Error Handling
411
+ ### Manual async error handling
380
412
 
381
413
  ```typescript
382
414
  const tree = signalTree({
@@ -437,7 +469,7 @@ class ErrorHandlingComponent {
437
469
  }
438
470
  ```
439
471
 
440
- ### State Update Error Handling
472
+ ### State update error handling
441
473
 
442
474
  ```typescript
443
475
  const tree = signalTree({
@@ -475,7 +507,7 @@ function safeUpdateItem(id: string, updates: Partial<Item>) {
475
507
  }
476
508
  ```
477
509
 
478
- ## πŸ”— Package Composition Patterns
510
+ ## Package composition patterns
479
511
 
480
512
  ### Basic Composition
481
513
 
@@ -487,33 +519,33 @@ const tree = signalTree({
487
519
  state: 'initial',
488
520
  });
489
521
 
490
- // Extend with additional packages via pipe
491
- const enhancedTree = tree.pipe(
522
+ // Extend with additional packages via .with(...)
523
+ const enhancedTree = tree.with(
492
524
  // Add features as needed
493
525
  someFeatureFunction()
494
526
  );
495
527
  ```
496
528
 
497
- ### Modular Enhancement Pattern
529
+ ### Modular enhancement pattern
498
530
 
499
531
  ```typescript
500
532
  // Start minimal, add features as needed
501
533
  let tree = signalTree(initialState);
502
534
 
503
535
  if (isDevelopment) {
504
- tree = tree.pipe(withDevtools());
536
+ tree = tree.with(withDevTools());
505
537
  }
506
538
 
507
539
  if (needsPerformance) {
508
- tree = tree.pipe(withBatching(), withMemoization());
540
+ tree = tree.with(withBatching(), withMemoization());
509
541
  }
510
542
 
511
543
  if (needsTimeTravel) {
512
- tree = tree.pipe(withTimeTravel());
544
+ tree = tree.with(withTimeTravel());
513
545
  }
514
546
  ```
515
547
 
516
- ### Service-Based Pattern
548
+ ### Service-based pattern
517
549
 
518
550
  ```typescript
519
551
  @Injectable()
@@ -546,11 +578,11 @@ class AppStateService {
546
578
  }
547
579
  ```
548
580
 
549
- ## ⚑ Performance Benchmarks
581
+ ## Performance benchmarks
550
582
 
551
- > **Performance Grade: A+** ⭐ - Sub-millisecond operations across all core functions
583
+ > Sub‑millisecond operations across common core functions
552
584
 
553
- ### Recursive Depth Scaling Performance
585
+ ### Recursive depth scaling (illustrative)
554
586
 
555
587
  | **Depth Level** | **Execution Time** | **Scaling Factor** | **Type Inference** | **Memory Usage** |
556
588
  | -------------------------- | ------------------ | ------------------ | ------------------ | ---------------- |
@@ -559,9 +591,9 @@ class AppStateService {
559
591
  | **Extreme (15 levels)** | **0.021ms** | **1.75x** | βœ… Perfect | ~1.3MB |
560
592
  | **Unlimited (20+ levels)** | 0.023ms | 1.92x | βœ… Perfect | ~1.4MB |
561
593
 
562
- _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
594
+ Note: Scaling depends on state shape and hardware.
563
595
 
564
- ### SignalTree Core Performance Results (Measured)
596
+ ### Example operation timings
565
597
 
566
598
  | Operation | SignalTree Core | Notes |
567
599
  | --------------------------- | --------------- | ---------------- |
@@ -572,16 +604,16 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
572
604
  | Computation (cached) | **0.094ms** | Memoized result |
573
605
  | Memory per 1K entities | **1.2MB** | Measured usage |
574
606
 
575
- ### Advanced Performance Features
607
+ ### Feature impact
576
608
 
577
609
  | Feature | SignalTree Core | With Extensions | Notes |
578
610
  | ------------------- | ----------------- | ---------------------- | ---------------------- |
579
611
  | Batching efficiency | Standard | **455.8x improvement** | vs non-batched |
580
612
  | Memoization speedup | Basic | **197.9x speedup** | vs non-memoized |
581
613
  | Memory efficiency | **Optimized** | **Further optimized** | Lazy signals + cleanup |
582
- | Bundle impact | **5.1KB gzipped** | **+15KB max** | Tree-shakeable |
614
+ | Bundle impact | **7.1KB gzipped** | **+15KB max** | Tree-shakeable |
583
615
 
584
- ### Developer Experience (Core Package)
616
+ ### Developer experience (core)
585
617
 
586
618
  | Metric | SignalTree Core | Traditional State Mgmt | **Improvement** |
587
619
  | ----------------------- | --------------- | ---------------------- | --------------- |
@@ -590,7 +622,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
590
622
  | Setup complexity | **Minimal** | Complex | **Simplified** |
591
623
  | API surface | **Small** | Large | **Focused** |
592
624
 
593
- ### Memory Usage Comparison
625
+ ### Memory usage comparison
594
626
 
595
627
  | Operation | SignalTree Core | NgRx | Akita | Native Signals |
596
628
  | ------------------------ | --------------- | ------ | ------ | -------------- |
@@ -598,7 +630,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
598
630
  | 10K entities | 8.1MB | 28.5MB | 22.1MB | 15.2MB |
599
631
  | Deep nesting (10 levels) | 145KB | 890KB | 720KB | 340KB |
600
632
 
601
- ### TypeScript Inference Speed
633
+ ### TypeScript inference speed
602
634
 
603
635
  ```typescript
604
636
  // SignalTree: Instant inference
@@ -612,7 +644,7 @@ interface State { deeply: { nested: { state: { with: { types: string } } } } }
612
644
  const store: Store<State> = ...; // Requires manual interface definition
613
645
  ```
614
646
 
615
- ## 🎯 Real-World Example
647
+ ## Example
616
648
 
617
649
  ```typescript
618
650
  // Complete user management component
@@ -730,16 +762,16 @@ class UserManagerComponent implements OnInit {
730
762
  }));
731
763
 
732
764
  // Get entire state as plain object
733
- const currentState = tree.$();
765
+ const currentState = tree.unwrap();
734
766
  console.log('Current app state:', currentState);
735
767
 
736
768
  ```
737
769
  });
738
770
  ```
739
771
 
740
- ## πŸ“¦ Core Features
772
+ ## Core features
741
773
 
742
- ### Hierarchical Signal Trees
774
+ ### Hierarchical signal trees
743
775
 
744
776
  ```typescript
745
777
  const tree = signalTree({
@@ -754,7 +786,7 @@ tree.$.settings.theme.set('light');
754
786
  tree.$.todos.update((todos) => [...todos, newTodo]);
755
787
  ```
756
788
 
757
- ### Manual Entity Management
789
+ ### Manual entity management
758
790
 
759
791
  ```typescript
760
792
  // Manual CRUD operations
@@ -780,7 +812,7 @@ const allTodos = computed(() => tree.$.todos());
780
812
  const todoCount = computed(() => tree.$.todos().length);
781
813
  ```
782
814
 
783
- ### Manual Async State Management
815
+ ### Manual async state management
784
816
 
785
817
  ```typescript
786
818
  async function loadUsers() {
@@ -802,7 +834,7 @@ async function handleLoadUsers() {
802
834
  }
803
835
  ```
804
836
 
805
- ### Reactive Effects
837
+ ### Reactive effects
806
838
 
807
839
  ```typescript
808
840
  // Create reactive effects
@@ -816,7 +848,7 @@ const unsubscribe = tree.subscribe((state) => {
816
848
  });
817
849
  ```
818
850
 
819
- ## 🎯 Core API Reference
851
+ ## Core API reference
820
852
 
821
853
  ### signalTree()
822
854
 
@@ -830,7 +862,7 @@ const tree = signalTree(initialState, config?);
830
862
  // State access
831
863
  tree.$.property(); // Read signal value
832
864
  tree.$.property.set(value); // Update signal
833
- // Use callable signal access to read the current values: `tree.$()`
865
+ tree.unwrap(); // Get plain object
834
866
 
835
867
  // Tree operations
836
868
  tree.update(updater); // Update entire tree
@@ -844,7 +876,7 @@ tree.asyncAction(fn, config?); // Async actions (requires @signaltree/async)
844
876
  tree.asyncAction(fn, config?); // Create async action
845
877
  ```
846
878
 
847
- ## πŸ”Œ Extending with Optional Packages
879
+ ## Extending with optional packages
848
880
 
849
881
  SignalTree Core can be extended with additional features:
850
882
 
@@ -854,11 +886,11 @@ import { withBatching } from '@signaltree/batching';
854
886
  import { withMemoization } from '@signaltree/memoization';
855
887
  import { withTimeTravel } from '@signaltree/time-travel';
856
888
 
857
- // Compose features using pipe
858
- const tree = signalTree(initialState).pipe(withBatching(), withMemoization(), withTimeTravel());
889
+ // Compose features using .with(...)
890
+ const tree = signalTree(initialState).with(withBatching(), withMemoization(), withTimeTravel());
859
891
  ```
860
892
 
861
- ### Available Extensions
893
+ ### Available extensions
862
894
 
863
895
  - **@signaltree/batching** (+1.1KB gzipped) - Batch multiple updates
864
896
  - **@signaltree/memoization** (+1.7KB gzipped) - Intelligent caching & performance
@@ -869,9 +901,9 @@ const tree = signalTree(initialState).pipe(withBatching(), withMemoization(), wi
869
901
  - **@signaltree/time-travel** (+1.5KB gzipped) - Undo/redo functionality
870
902
  - **@signaltree/ng-forms** (+3.4KB gzipped) - Complete Angular forms integration
871
903
  - **@signaltree/serialization** (+3.6KB gzipped) - State persistence & SSR support
872
- - **@signaltree/presets** (+0.5KB gzipped) - Environment-based configurations
904
+ - **@signaltree/presets** (+0.8KB gzipped) - Environment-based configurations
873
905
 
874
- ## 🎯 When to Use Core Only
906
+ ## When to use core only
875
907
 
876
908
  Perfect for:
877
909
 
@@ -888,7 +920,7 @@ Consider extensions when you need:
888
920
  - πŸ“ Complex forms (ng-forms)
889
921
  - πŸ”§ Middleware patterns (middleware)
890
922
 
891
- ## πŸ”„ Migration from NgRx
923
+ ## Migration from NgRx
892
924
 
893
925
  ```typescript
894
926
  // Step 1: Create parallel tree
@@ -904,7 +936,7 @@ users = this.tree.$.users;
904
936
  // Step 3: Replace effects with manual async operations
905
937
  // Before (NgRx)
906
938
  loadUsers$ = createEffect(() =>
907
- this.actions$.pipe(
939
+ this.actions$.with(
908
940
  ofType(loadUsers),
909
941
  switchMap(() => this.api.getUsers())
910
942
  )
@@ -926,7 +958,7 @@ loadUsers = tree.asyncAction(() => api.getUsers(), {
926
958
  });
927
959
  ```
928
960
 
929
- ## πŸ“– Examples
961
+ ## Examples
930
962
 
931
963
  ### Simple Counter
932
964
 
@@ -996,7 +1028,7 @@ class UsersComponent {
996
1028
  }
997
1029
  ```
998
1030
 
999
- ## οΏ½ Available Extension Packages
1031
+ ## Available extension packages
1000
1032
 
1001
1033
  Extend the core with optional feature packages:
1002
1034
 
@@ -1018,7 +1050,7 @@ Extend the core with optional feature packages:
1018
1050
 
1019
1051
  ### Integration & Convenience
1020
1052
 
1021
- - **[@signaltree/presets](../presets)** (+0.5KB gzipped) - Pre-configured setups for common patterns
1053
+ - **[@signaltree/presets](../presets)** (+0.8KB gzipped) - Pre-configured setups for common patterns
1022
1054
  - **[@signaltree/ng-forms](../ng-forms)** (+3.4KB gzipped) - Complete Angular Forms integration
1023
1055
 
1024
1056
  ### Quick Start with Extensions
@@ -1034,7 +1066,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
1034
1066
  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
1067
  ```
1036
1068
 
1037
- ## οΏ½πŸ”— Links
1069
+ ## Links
1038
1070
 
1039
1071
  - [SignalTree Documentation](https://signaltree.io)
1040
1072
  - [GitHub Repository](https://github.com/JBorgia/signaltree)
@@ -1043,7 +1075,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
1043
1075
 
1044
1076
  ## πŸ“„ License
1045
1077
 
1046
- MIT License - see the [LICENSE](../../LICENSE) file for details.
1078
+ MIT License with AI Training Restriction - see the [LICENSE](../../LICENSE) file for details.
1047
1079
 
1048
1080
  ---
1049
1081