@alwatr/signal 4.1.0 → 5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,149 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [5.0.0](https://github.com/Alwatr/flux/compare/v4.1.1...v5.0.0) (2025-09-12)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * Rewrite @alwatr/signal from ground-up — complete API overhaul
11
+
12
+ Summary:
13
+ A full rewrite of the @alwatr/signal package was released. The internal implementation, public exports and types have changed in an incompatible way. Consumers must update imports and call-sites to use the new API.
14
+
15
+ Affected:
16
+ - packages/signal (public package @alwatr/signal)
17
+ - Any repos importing old signal types/exports or relying on previous runtime semantics
18
+
19
+ What changed (high-level):
20
+ - New core primitives and public API (StateSignal, ComputedSignal, EffectSignal, EventSignal) with new constructors and config objects.
21
+ - signalId is now required for identity/logging.
22
+ - Lifecycle semantics: ComputedSignal and EffectSignal must call .destroy() to avoid leaks.
23
+ - Async model explicit: State/Event notify on microtask; Computed/Effect batch on macrotask.
24
+ - subscribe() options changed (once, priority, receivePrevious).
25
+ - Types and exported symbols renamed/reshaped; package.json exports/types updated.
26
+
27
+ Migration notes:
28
+ - Replace old imports with new named exports from '@alwatr/signal'.
29
+ - Instantiate signals with the new config object shape (e.g. new StateSignal({ signalId, initialValue })).
30
+ - Ensure ComputedSignal/EffectSignal .destroy() is called in teardown paths.
31
+ - Update code that relied on previous sync/async timing — recompute batching behavior may differ.
32
+ - Update TypeScript types/usages according to new exports; run yarn build & yarn test after changes.
33
+
34
+ Quick example (new usage):
35
+ const firstName = new StateSignal<string>({ signalId: 'user-firstName', initialValue: 'John' });
36
+ const fullName = new ComputedSignal<string>({ signalId: 'user-fullName', deps: [firstName], get: () => `User: ${firstName.value}` });
37
+ const logger = new EffectSignal({ deps: [fullName], run: () => console.log(fullName.value) });
38
+ // remember to call fullName.destroy()/logger.destroy() when no longer needed
39
+
40
+ Action items for maintainers/releasers:
41
+ - Bump major version.
42
+ - Add migration notes to CHANGELOG and README.
43
+ - Run CI: yarn build && yarn test (Node >=18.16.0).
44
+ - Notify downstream consumers about required code changes.
45
+
46
+ * update package description to accurately reflect the library's capabilities ([785b30b](https://github.com/Alwatr/flux/commit/785b30b5ab694b1165c541a7dbbf6959221f8f46))
47
+
48
+ ### ✨ Features
49
+
50
+ * add abstract SignalBase class for managing observers and subscriptions ([913aee8](https://github.com/Alwatr/flux/commit/913aee840e8f3f82ba865d4db0492a70a8ef8d99))
51
+ * add computed function for creating read-only computed signals ([137bf73](https://github.com/Alwatr/flux/commit/137bf7391b71ce11e77773cc45e030341c2b5408))
52
+ * add destroy method to ComputedSignal interface for cleanup and garbage collection ([67dcc46](https://github.com/Alwatr/flux/commit/67dcc46a4f1330e60a161da4213b58f938534757))
53
+ * add destroy method to EffectResult interface for cleanup ([fe5638a](https://github.com/Alwatr/flux/commit/fe5638ada3f7ebdda67ae3d6538518310684d10c))
54
+ * add destruction check in dispatch method and remove unused notify_ method ([f37086d](https://github.com/Alwatr/flux/commit/f37086d439fbf74e2486586e9e80cc6509e9fc42))
55
+ * add destruction checks and logging in computed function to prevent operations on destroyed signals ([7233967](https://github.com/Alwatr/flux/commit/723396732a9decda613529446e4d095cdecbd57a))
56
+ * add destruction checks in value getter, setter, and subscribe method; remove unused notify_ method ([3e22e63](https://github.com/Alwatr/flux/commit/3e22e633bccf2f04fb989250a623df5d35401042))
57
+ * add effect function to manage side effects with dependency tracking ([6890953](https://github.com/Alwatr/flux/commit/68909538d19df0724e592b77cccd24db645ae9a7))
58
+ * add isDestroyed getter to ComputedSignal for lifecycle management ([b26d9fe](https://github.com/Alwatr/flux/commit/b26d9fe088324ea1246ab5b2164dffae6734b1e5))
59
+ * add isDestroyed getter to EffectSignal for lifecycle management ([c918007](https://github.com/Alwatr/flux/commit/c918007925eb54b73bb54aa06bca16bc65cf6ce6))
60
+ * add isDestroyed property and destroy method to IReadonlySignal for lifecycle management ([a5abfb8](https://github.com/Alwatr/flux/commit/a5abfb8f26c281cfa8e65fa56dcf0dd35f18945c))
61
+ * add isDestroyed property to IEffectSignal for lifecycle management ([45b5b67](https://github.com/Alwatr/flux/commit/45b5b679149098e5498cf37c49e00957efef8305))
62
+ * add ReadonlySignal interface and ComputedOptions type for signal management ([9d475dd](https://github.com/Alwatr/flux/commit/9d475ddcb36ed44509257df18ecb82ddb6fa284d))
63
+ * add StateSignal class for managing stateful signals and notifications ([409f2b9](https://github.com/Alwatr/flux/commit/409f2b9f8abaa74a1b0d761d4513a64a6604b320))
64
+ * add types for signal listener, subscription options, and configuration ([3bebee5](https://github.com/Alwatr/flux/commit/3bebee5ab733d344ea6c1e6f1e7b7f3310cf4a87))
65
+ * add untilNext method to ComputedSignal for improved subscription handling ([c8d333f](https://github.com/Alwatr/flux/commit/c8d333fe860de3714a5946f000a1f83c7ec7144a))
66
+ * add untilNext method to IReadonlySignal for awaiting next dispatched value ([004b228](https://github.com/Alwatr/flux/commit/004b22870d17c86bfa2f2e3b0d68a82376d2a5a1))
67
+ * add untilNext method to SignalBase for awaiting next dispatched value ([5771e72](https://github.com/Alwatr/flux/commit/5771e72bf8876a8feaaebc263394e05003e9d44e))
68
+ * enhance computed function to include logging, improve destruction handling, and return ComputedSignal type ([2446570](https://github.com/Alwatr/flux/commit/24465704b8d7b2ca38c59073b189c2e4410240b3))
69
+ * enhance ReadonlySignal interface with options parameter and improve documentation ([9abed87](https://github.com/Alwatr/flux/commit/9abed875db6cabc709aa63ec4893158db30e0372))
70
+ * enhance SignalBase with destruction checks and logging ([10acb3d](https://github.com/Alwatr/flux/commit/10acb3dedf682f19f94670cd79c8fe5e403e0fc1))
71
+ * implement destroy method to clear observers and manage lifecycle ([50ae3e3](https://github.com/Alwatr/flux/commit/50ae3e30d0aa3fa8137b6ab8e8198c2a931d43bb))
72
+ * implement EventSignal class for dispatching transient events ([4f55a49](https://github.com/Alwatr/flux/commit/4f55a49e2896f52e8b730edf55f9dc431d86d165))
73
+ * implement ReadonlySignal interface in StateSignal class ([748226c](https://github.com/Alwatr/flux/commit/748226c5958ed7985b2fedd93a6d4a1bbde3839e))
74
+ * move notify_ mothod to the base ([4d81348](https://github.com/Alwatr/flux/commit/4d81348cf869187eca7777f7182d19e2256046e6))
75
+ * new EffectSignal class with immediate execution option and improved lifecycle management ([4552fde](https://github.com/Alwatr/flux/commit/4552fde94ac8262e7c8933b53d26bd5ed9b7839e))
76
+ * remove logger and signal classes for cleaner architecture ([0beef9c](https://github.com/Alwatr/flux/commit/0beef9c1fc2e9aff6f9d1028a4bc30b44c10037b))
77
+ * update main entry point documentation and export necessary types ([7c3f12a](https://github.com/Alwatr/flux/commit/7c3f12a67f24f13bd0c9a9ff3ca9e3a14d7afb1c))
78
+
79
+ ### 🐛 Bug Fixes
80
+
81
+ * change notify_ method to fire callbacks synchronously and handle unhandled promise rejections ([2b54d69](https://github.com/Alwatr/flux/commit/2b54d69a45fca9500097f17e99c9572955617e55))
82
+ * change set method to be synchronous ([a0cdaf4](https://github.com/Alwatr/flux/commit/a0cdaf441f888caacc98f8f3017b066ccf6186df))
83
+ * clear value on destroy method in StateSignal class ([0088c03](https://github.com/Alwatr/flux/commit/0088c03ac976b473d0ce7d659cf7cbd0254bfdde))
84
+ * correct logger method call from 'new' to 'initialize' in EventSignal constructor ([f9f7177](https://github.com/Alwatr/flux/commit/f9f7177bf3025b3e1484bab612b35af1c7fd0455))
85
+ * correct logger method call from 'new' to 'initialize' in StateSignal constructor and improve notify_ method documentation ([b0d6981](https://github.com/Alwatr/flux/commit/b0d6981088144f74a78bb412babe077f4fe7d2f9))
86
+ * correct observer array reference and method call in EventSignal ([83a3ddf](https://github.com/Alwatr/flux/commit/83a3ddf7151ef866b1f392fdd56aa0105e742718))
87
+ * correct primitive value comparison logic in StateSignal set method ([93c5319](https://github.com/Alwatr/flux/commit/93c5319d0c1318a2c053373c3e7d8fa839544386))
88
+ * ensure effect runs immediately on initialization ([a7d34d6](https://github.com/Alwatr/flux/commit/a7d34d6203a283faeac821ab0909f5d91802006d))
89
+ * error log in computed-signal.ts ([7c2ab54](https://github.com/Alwatr/flux/commit/7c2ab54de6410ed4287286713fc3a34a9e02ef24))
90
+ * export everything in main ([dc6779e](https://github.com/Alwatr/flux/commit/dc6779eeb0fbce67a3b665e46fc0e0df8583c88e))
91
+ * make dispatch sync ([678ef01](https://github.com/Alwatr/flux/commit/678ef01fdc19b04167f60579e606cbf1fe1fa774))
92
+ * make set method synchronously ([d36cda2](https://github.com/Alwatr/flux/commit/d36cda241c4e0c2bf952590a989c7de40f94bf41))
93
+ * update default value for receivePrevious in SubscribeOptions and make options optional in Observer interface ([a27aa1f](https://github.com/Alwatr/flux/commit/a27aa1fdd106748deab8899d3df9d9a98e29c8eb))
94
+ * update interface names and import type from @alwatr/type-helper ([a855b39](https://github.com/Alwatr/flux/commit/a855b39336f5bd99c822a9f061a84171bce274c9))
95
+
96
+ ### 🔨 Code Refactoring
97
+
98
+ * centralize observer removal logic in SignalBase class ([61c13e9](https://github.com/Alwatr/flux/commit/61c13e96ff1d16651b884822a4b5b808d6c474b2))
99
+ * change dispatch method to async for improved non-blocking behavior ([696d942](https://github.com/Alwatr/flux/commit/696d9423b147743634cd4a87c42e04f8d1f3b5cb))
100
+ * change notify_ method to async for improved observer handling ([dbaec6e](https://github.com/Alwatr/flux/commit/dbaec6e35b4894cc404d3dcbbbdfc4c671fa70ef))
101
+ * change set method to async for improved notification handling ([a42cb1b](https://github.com/Alwatr/flux/commit/a42cb1b438e4652ae9a470d11949895be09782af))
102
+ * enhance documentation for ComputedSignal class and its methods ([e7deac5](https://github.com/Alwatr/flux/commit/e7deac5e4a118faa3ad32746ca6bbff1750d4902))
103
+ * enhance logging and improve dispatch method in EventSignal ([23d717a](https://github.com/Alwatr/flux/commit/23d717ae67bcc437499902822cc50c1a4c291e9d))
104
+ * enhance SignalBase class with improved type imports and access modifiers ([d26efbe](https://github.com/Alwatr/flux/commit/d26efbe09973b65f9720bee7104490b3e080be7b))
105
+ * improve immediate callback execution in subscribe method ([3518aa3](https://github.com/Alwatr/flux/commit/3518aa3355731158f8f4032899a77867f4af16ff))
106
+ * improve logging and error handling in subscribe and notify methods ([fbcc7fa](https://github.com/Alwatr/flux/commit/fbcc7fa4dea17d99600672b4c566f87b5747e651))
107
+ * improve StateSignal implementation by renaming variables and enhancing dispatch logic ([68e7e73](https://github.com/Alwatr/flux/commit/68e7e73eeb5814c95affd2e698131bd8353b4d99))
108
+ * improve value change notification logic in StateSignal ([24ffa82](https://github.com/Alwatr/flux/commit/24ffa82b7b69483095ff80b88d87dfe9ea90fc09))
109
+ * optimize value setting in StateSignal to prevent unnecessary dispatches ([cb00df1](https://github.com/Alwatr/flux/commit/cb00df13b6ea38e23ecb70b1ae73487a18ca85fd))
110
+ * prevent unnecessary promise handling in EffectSignal constructor ([93940b0](https://github.com/Alwatr/flux/commit/93940b0d05345a238111b2443f247859bb08f680))
111
+ * remove 'disabled' option from subscribe options in README and tests ([73ee9db](https://github.com/Alwatr/flux/commit/73ee9db4fbb01cc87d0e1c38f2c27398c53a6157))
112
+ * remove 'disabled' option from SubscribeOptions and clean up related logic in SignalBase and StateSignal ([381356a](https://github.com/Alwatr/flux/commit/381356a02f4972a8ab2eff5653be867f4b57010c))
113
+ * remove checkDestroyed_ method from EffectSignal class ([9e42492](https://github.com/Alwatr/flux/commit/9e42492ce9ba84794ef0a57527b8275bfe78a3e8))
114
+ * remove unused imports in ComputedSignal ([d797820](https://github.com/Alwatr/flux/commit/d7978208e34f46e98f0fbaf15fd4a4703dce7d16))
115
+ * remove unused Observer_ type import in StateSignal ([29d95a4](https://github.com/Alwatr/flux/commit/29d95a47305d474ad2d9c3634ebf91b598fb2bc2))
116
+ * reorganize EffectResult interface and add runImmediately option to EffectOptions ([e4825a1](https://github.com/Alwatr/flux/commit/e4825a19464d52bcdcb47f8e6a027fbc2a5ceee6))
117
+ * reorganize imports and enhance EventSignal constructor and dispatch method visibility ([1d25544](https://github.com/Alwatr/flux/commit/1d2554471dbc430bb12edc4a94ea33d4a1922814))
118
+ * reset config_ in ComputedSignal's destroy method to improve memory management ([b5bcb20](https://github.com/Alwatr/flux/commit/b5bcb204addc639e611ca0ba47640eaf31372ff6))
119
+ * reset config_ in EffectSignal's destroy method to improve memory management ([81a9748](https://github.com/Alwatr/flux/commit/81a9748cdaf121d3a0ae872c23fe691c1f51acf9))
120
+ * simplify dispatch method in EventSignal by removing error handling ([7777299](https://github.com/Alwatr/flux/commit/7777299b31a38fdd31ae6a96bc6a34bd270dc831))
121
+ * simplify exports in main entry point of Signal package ([3039eca](https://github.com/Alwatr/flux/commit/3039eca5eebd43937937b2eac6aa65e649cc5da8))
122
+ * simplify ListenerCallback and Observer_ type definitions ([dc95f09](https://github.com/Alwatr/flux/commit/dc95f098c57277a1f4af05d21e2017c1e8bfc2d5))
123
+ * simplify observer type definitions in SignalBase class ([a579ec4](https://github.com/Alwatr/flux/commit/a579ec43040da719d43a08544448340c17243c54))
124
+ * streamline dispatch logic and enhance error handling in StateSignal ([eec0a43](https://github.com/Alwatr/flux/commit/eec0a430c9dc18c082b00765781a3333c48b51d8))
125
+ * streamline internal signal initialization in ComputedSignal ([3791208](https://github.com/Alwatr/flux/commit/3791208298b884183e202694f451185b3ae9b524))
126
+ * streamline microtask dispatch in set and subscribe methods ([598eef3](https://github.com/Alwatr/flux/commit/598eef334cfb3c34ee1dd38178fd94fc4a2fae56))
127
+ * update ComputedSignal class structure and improve dependency management ([7947b61](https://github.com/Alwatr/flux/commit/7947b61fd77fc46f69ad95016dac0f890f2c30c9))
128
+ * update EffectOptions to EffectSignalConfig with improved dependency handling and runImmediately option ([7d162fc](https://github.com/Alwatr/flux/commit/7d162fc77d0aca04744369306b6b13d506cbdc04))
129
+ * update import statements and enhance access modifiers in StateSignal class ([fe12bf2](https://github.com/Alwatr/flux/commit/fe12bf2d4e47ac88f0e1b74e3f506046c136c1b1))
130
+ * update observer handling in SignalBase for consistency and clarity ([f97c51d](https://github.com/Alwatr/flux/commit/f97c51d404616e90931db3547171b4e0cf0a60f0))
131
+
132
+ ### 🧹 Miscellaneous Chores
133
+
134
+ * add @jest/globals dependency to package.json and update yarn.lock ([2105405](https://github.com/Alwatr/flux/commit/2105405afe5e747b92ab59fc7de4b4bbdcc0bdb6))
135
+ * remove reference to @alwatr/observable from package.json and tsconfig.json ([30ead90](https://github.com/Alwatr/flux/commit/30ead9083f19cda76873ed227c76476926175eca))
136
+ * update @alwatr/nanolib dependency to version 6.0.2 ([134d3e7](https://github.com/Alwatr/flux/commit/134d3e7878c7a22d5f7994c671b5dceabfd29b57))
137
+
138
+ ### 🔗 Dependencies update
139
+
140
+ * update dependencies and devDependencies in package.json ([d2cf47c](https://github.com/Alwatr/flux/commit/d2cf47c26b65f41eb8de0873fe7065d0a42aaecf))
141
+ * update workspace dependency versions for consistency ([b004468](https://github.com/Alwatr/flux/commit/b0044682805a6f5842214755de109034ec4d0405))
142
+
143
+ ## [4.1.1](https://github.com/Alwatr/flux/compare/v4.1.0...v4.1.1) (2025-09-08)
144
+
145
+ ### 🔗 Dependencies update
146
+
147
+ * update @alwatr/nanolib to version 6.0.2 across multiple packages ([2d18fb0](https://github.com/Alwatr/flux/commit/2d18fb0e7311321200b1ed37381308b1dacae4b2))
148
+
6
149
  ## [4.1.0](https://github.com/Alwatr/flux/compare/v4.0.5...v4.1.0) (2025-09-08)
7
150
 
8
151
  ### 🧹 Miscellaneous Chores
package/README.md CHANGED
@@ -1,74 +1,423 @@
1
- # Flux: Signal
1
+ # Alwatr Signal
2
2
 
3
- A simple and efficient TypeScript library for event-driven communication using signals.
3
+ Alwatr Signal is a powerful, lightweight, and modern reactive programming library. It is inspired by the best concepts from major reactive libraries but engineered to be faster and more efficient than all of them. It provides a robust and elegant way to manage application state through a system of signals, offering fine-grained reactivity, predictability, and excellent performance.
4
+
5
+ It's designed to be simple to learn, yet capable of handling complex state management scenarios.
4
6
 
5
7
  ## Features
6
8
 
7
- * **Lightweight and focused:** Provides a streamlined implementation of the signal pattern for event handling.
8
- * **TypeScript Support:** Written in TypeScript with full type definitions for improved code quality and developer experience.
9
- * **Easy to use:** Intuitive API for emitting and subscribing to events with strongly-typed messages.
10
- * **Asynchronous Support:** Handle asynchronous events with Promise-based `untilNewNotify` method.
11
- * **Built-in Logging:** Integrated logging for debugging and monitoring.
9
+ - **Type-Safe**: Fully implemented in TypeScript for robust, type-safe code.
10
+ - **Lightweight**: A small footprint with zero third-party dependencies.
11
+ - **Performant**: Smart change detection and batched updates prevent unnecessary computations and re-renders.
12
+ - **Predictable**: Asynchronous, non-blocking notifications ensure a consistent and understandable data flow.
13
+ - **Lifecycle Management**: Built-in `destroy()` methods for easy cleanup and memory leak prevention.
14
+ - **Easy to Debug**: Unique `signalId` for each signal makes logging and tracing a breeze.
15
+
16
+ ## Core Concepts
17
+
18
+ Signals are the fundamental building blocks in Alwatr Signal. They are special objects that hold a value and can notify interested consumers when that value changes. There are three main types of signals:
19
+
20
+ 1. **`StateSignal`**: The foundation of reactivity. It holds a mutable value. When you `set()` a new value, it notifies all its dependents.
21
+ 2. **`ComputedSignal`**: A read-only signal that derives its value from other signals. It automatically updates when its dependencies change. The result is memoized, so the calculation only runs when needed.
22
+ 3. **`EffectSignal`**: The bridge to the "outside world." It executes a side effect (like logging or rendering) in response to changes in the signals it depends on.
23
+
24
+ There is also a fourth type for stateless events:
25
+
26
+ 4. **`EventSignal`**: A stateless signal for dispatching one-off events that don't have a persistent value.
27
+
28
+ ---
29
+
30
+ ## Getting Started: A Practical Example
31
+
32
+ Let's build a simple reactive system to see how the different signal types work together.
33
+
34
+ ### 1. Install
12
35
 
13
- ## Installation
36
+ First, ensure you have the package installed:
14
37
 
15
38
  ```bash
16
- npm install @alwatr/signal
39
+ npm i @alwatr/signal
17
40
  ```
18
41
 
19
- ## Usage
42
+ ### 2. Create State Signals
43
+
44
+ `StateSignal` is where your application's state lives. Let's create signals for a user's name and a counter.
20
45
 
21
46
  ```typescript
22
- import {AlwatrSignal} from '@alwatr/signal';
47
+ import {StateSignal} from '@alwatr/signal';
23
48
 
24
- // Create a new signal
25
- const mySignal = new AlwatrSignal<{message: string}>({name: 'my-signal'});
49
+ // A signal to hold the user's first name.
50
+ const firstName = new StateSignal<string>({
51
+ signalId: 'user-firstName',
52
+ initialValue: 'John',
53
+ });
26
54
 
27
- // Subscribe to the signal
28
- const subscription = mySignal.subscribe((message) => {
29
- console.log('Received message:', message);
55
+ // A signal to hold a simple counter.
56
+ const counter = new StateSignal<number>({
57
+ signalId: 'app-counter',
58
+ initialValue: 0,
30
59
  });
60
+ ```
31
61
 
32
- // Emit an event
33
- mySignal.notify({message: 'Hello, world!'});
62
+ ### 3. Create a Computed Signal
34
63
 
35
- // Wait for the next event asynchronously
36
- const nextMessage = await mySignal.untilNewNotify();
37
- console.log('Next message:', nextMessage);
64
+ A `ComputedSignal` combines other signals into a new, read-only value. Let's create a `fullName` signal that automatically updates when `firstName` changes.
65
+
66
+ ```typescript
67
+ import {ComputedSignal} from '@alwatr/signal';
38
68
 
39
- // Unsubscribe when done
40
- subscription.unsubscribe();
69
+ const fullName = new ComputedSignal<string>({
70
+ signalId: 'user-fullName',
71
+ deps: [firstName], // This computed signal depends on firstName.
72
+ get: () => `User: ${firstName.value}`,
73
+ });
74
+
75
+ console.log(fullName.value); // Outputs: "User: John"
41
76
  ```
42
77
 
43
- ## API
78
+ ### 4. Create an Effect Signal
44
79
 
45
- ### `AlwatrSignal`
80
+ An `EffectSignal` runs a side effect whenever one of its dependencies changes. This is perfect for logging, updating the DOM, or making network requests.
46
81
 
47
- * **`constructor(config: {name: string; loggerPrefix?: string})`:** Creates a new `AlwatrSignal` instance.
48
- * `config.name`: The name of the signal (used for logging).
49
- * `config.loggerPrefix`: Optional prefix for log messages.
82
+ ```typescript
83
+ import {EffectSignal} from '@alwatr/signal';
50
84
 
51
- * **`subscribe(listenerCallback: ListenerCallback<this, T>, options: SubscribeOptions = {}): SubscribeResult`:** (Inherited from `AlwatrObservable`) Subscribes to the signal.
52
- * `listenerCallback`: The function to be called when an event is emitted.
53
- * `options`:
54
- * `once`: If `true`, the listener will be automatically unsubscribed after the first event.
55
- * `priority`: If `true`, the listener will be executed before other listeners.
56
- * `receivePrevious`: If `true`, the listener will be immediately called with the last emitted event (if available).
57
- * `disabled`: If `true`, the listener will not be executed.
85
+ const loggerEffect = new EffectSignal({
86
+ deps: [fullName, counter], // This effect depends on fullName and counter.
87
+ run: () => {
88
+ console.log(`${fullName.value} has clicked ${counter.value} times.`);
89
+ },
90
+ });
91
+ ```
92
+
93
+ ### 5. Putting It All Together
94
+
95
+ Now, let's see the magic happen. When we update a `StateSignal`, the changes automatically propagate through the system.
96
+
97
+ ```typescript
98
+ // Subscribe to changes for demonstration
99
+ fullName.subscribe((newFullName) => {
100
+ console.log(`Full name signal updated to: ${newFullName}`);
101
+ });
102
+
103
+ // Let's change the first name.
104
+ firstName.set('Jane');
105
+ // This will trigger:
106
+ // 1. `fullName` to recalculate its value.
107
+ // 2. The `fullName.subscribe` callback to run.
108
+ // 3. The `loggerEffect` to run.
109
+
110
+ // Let's increment the counter.
111
+ counter.set(1);
112
+ // This will trigger:
113
+ // 1. The `loggerEffect` to run again.
114
+ ```
58
115
 
59
- * **`unsubscribe(listenerCallback: ListenerCallback<this, T>)`:** (Inherited from `AlwatrObservable`) Unsubscribes a listener from the signal.
116
+ The output would be:
60
117
 
61
- * **`notify(message: T)`:** Emits an event to all subscribers.
62
- * `message`: The data to be sent to the subscribers.
118
+ ```
119
+ User: John
120
+ Full name signal updated to: User: Jane
121
+ User: Jane has clicked 0 times.
122
+ User: Jane has clicked 1 times.
123
+ ```
124
+
125
+ ## Advanced Topics
126
+
127
+ ### Lifecycle Management and Memory Leaks
128
+
129
+ Signals that depend on other signals (like `ComputedSignal` and `EffectSignal`) create subscriptions internally. If you don't clean these up, they can lead to memory leaks.
130
+
131
+ **Always call `destroy()` on `ComputedSignal` and `EffectSignal` when they are no longer needed.**
132
+
133
+ ```typescript
134
+ // Create a computed signal
135
+ const isEven = new ComputedSignal({
136
+ deps: [counter],
137
+ get: () => counter.value % 2 === 0,
138
+ });
63
139
 
64
- * **`untilNewNotify()`:** Returns a Promise that resolves with the next emitted event.
140
+ // ... use it for a while ...
141
+
142
+ // When the component/logic using it is about to be removed:
143
+ isEven.destroy();
144
+ ```
145
+
146
+ Calling `destroy()` unsubscribes the signal from all its dependencies, allowing it to be safely garbage collected.
147
+
148
+ ### Asynchronous Notifications
149
+
150
+ Alwatr Signal uses a predictable asynchronous model for notifications:
151
+
152
+ - **`StateSignal` and `EventSignal`** schedule notifications on the **microtask** queue (`Promise.resolve().then(...)`). This ensures that multiple synchronous `set()` calls within the same event loop tick are batched, and listeners are notified shortly after, but not immediately.
153
+ - **`ComputedSignal` and `EffectSignal`** schedule their recalculations/runs on the **macrotask** queue (e.g., `setTimeout(..., 0)`). This is a crucial optimization. If multiple dependencies change in the same event loop, the computed signal will only recalculate _once_ per tick, avoiding redundant work.
154
+
155
+ ### Subscription Options
156
+
157
+ The `subscribe` method accepts an optional second argument to customize its behavior:
158
+
159
+ - `once: true`: The listener is called only once and then automatically removed.
160
+ - `priority: true`: The listener is moved to the front of the queue and is executed before other listeners.
161
+ - `receivePrevious: false` (For `StateSignal` only): Prevents the listener from being called immediately with the current value upon subscription.
162
+
163
+ ## API Overview
164
+
165
+ ### `StateSignal<T>`
166
+
167
+ - **`constructor(config)`**: Creates a new state signal.
168
+ - `config.signalId`: `string`
169
+ - `config.initialValue`: `T`
170
+ - **`.value`**: `T` - Gets the current value.
171
+ - **`.set(newValue: T)`**: Sets a new value and notifies listeners.
172
+
173
+ ### `ComputedSignal<T>`
174
+
175
+ - **`constructor(config)`**: Creates a new computed signal.
176
+ - `config.signalId`: `string`
177
+ - `config.deps`: `IReadonlySignal<unknown>[]` - Array of dependency signals.
178
+ - `config.get`: `() => T` - The function to compute the value.
179
+ - **`.value`**: `T` - Gets the current (memoized) value.
180
+ - **`.destroy()`**: Cleans up the signal's subscriptions. **(Important!)**
181
+
182
+ ### `EffectSignal`
183
+
184
+ - **`constructor(config)`**: Creates a new effect signal.
185
+ - `config.deps`: `IReadonlySignal<unknown>[]` - Array of dependency signals.
186
+ - `config.run`: `() => void | Promise<void>` - The side effect function.
187
+ - `config.runImmediately`: `boolean` (optional) - Whether to run the effect on creation.
188
+ - **`.destroy()`**: Cleans up the signal's subscriptions. **(Important!)**
189
+
190
+ ### `EventSignal<T>`
191
+
192
+ - **`constructor(config)`**: Creates a new event signal.
193
+ - `config.signalId`: `string`
194
+ - **`.dispatch(payload: T)`**: Dispatches an event to all listeners.
195
+
196
+ ### Common Methods
197
+
198
+ - **`.subscribe(callback, options?)`**: Subscribes a listener. Returns `{ unsubscribe: () => void }`.
199
+ - **`.untilNext()`**: Returns a `Promise` that resolves with the next value/payload.
200
+ - **`.destroy()`**: (On all but `StateSignal`) Cleans up the signal.
65
201
 
66
202
  ## Sponsors
67
203
 
68
204
  The following companies, organizations, and individuals support flux ongoing maintenance and development. Become a Sponsor to get your logo on our README and website.
69
205
 
70
-
71
- ### Contributing
206
+ ## Contributing
72
207
 
73
208
  Contributions are welcome! Please read our [contribution guidelines](https://github.com/Alwatr/.github/blob/next/CONTRIBUTING.md) before submitting a pull request.
74
209
 
210
+ ---
211
+
212
+ <br>
213
+ <br>
214
+ <br>
215
+
216
+ # Alwatr Signal (راهنمای فارسی)
217
+
218
+ کتابخانه Alwatr Signal یک ابزار قدرتمند، سبک و مدرن برای برنامه‌نویسی واکنشی (Reactive Programming) است. این کتابخانه با الگوبرداری از بهترین مفاهیم بزرگترین کتابخانه‌های واکنشی طراحی شده، اما مهندسی آن به گونه‌ای است که از تمام آن‌ها سریع‌تر و کارآمدتر باشد. این کتابخانه روشی استوار و زیبا برای مدیریت وضعیت برنامه از طریق سیگنال‌ها ارائه می‌دهد و واکنش‌پذیری دقیق (fine-grained reactivity)، پیش‌بینی‌پذیری و عملکرد عالی را به ارمغان می‌آورد.
219
+
220
+ طراحی آن به گونه‌ای است که یادگیری آن ساده باشد، اما در عین حال قادر به مدیریت سناریوهای پیچیده مدیریت وضعیت نیز باشد.
221
+
222
+ ## ویژگی‌ها
223
+
224
+ - **ایمنی نوع (Type-Safe)**: به طور کامل با TypeScript پیاده‌سازی شده تا کدی قوی و ایمن از نظر نوع داشته باشید.
225
+ - **سبک**: حجم بسیار کم و بدون هیچ وابستگی (dependency) خارجی.
226
+ - **عملکرد بالا**: تشخیص هوشمند تغییرات و به‌روزرسانی‌های دسته‌ای از محاسبات و رندرهای غیرضروری جلوگیری می‌کند.
227
+ - **پیش‌بینی‌پذیر**: نوتیفیکیشن‌های ناهمزمان (asynchronous) و غیرمسدودکننده (non-blocking) جریان داده‌ای سازگار و قابل فهم را تضمین می‌کنند.
228
+ - **مدیریت چرخه حیات (Lifecycle)**: متدهای داخلی `destroy()` برای پاک‌سازی آسان و جلوگیری از نشت حافظه (memory leak).
229
+ - **اشکال‌زدایی آسان**: شناسه‌های منحصر به فرد (`signalId`) برای هر سیگنال، لاگ‌گیری و ردیابی را بسیار ساده می‌کند.
230
+
231
+ ## مفاهیم اصلی
232
+
233
+ سیگنال‌ها بلوک‌های سازنده اصلی در Alwatr Signal هستند. آن‌ها اشیاء خاصی هستند که یک مقدار را نگه می‌دارند و می‌توانند مصرف‌کنندگان علاقه‌مند را هنگام تغییر آن مقدار مطلع کنند. سه نوع اصلی سیگنال وجود دارد:
234
+
235
+ 1. **`StateSignal`**: پایه و اساس واکنش‌پذیری. این سیگنال یک مقدار قابل تغییر را نگه می‌دارد. وقتی شما مقدار جدیدی را `set()` می‌کنید، تمام وابستگان خود را مطلع می‌سازد.
236
+ 2. **`ComputedSignal`**: یک سیگنال فقط-خواندنی (read-only) که مقدار خود را از سیگنال‌های دیگر استخراج می‌کند. این سیگنال به طور خودکار با تغییر وابستگی‌هایش به‌روز می‌شود. نتیجه کش (memoized) می‌شود، بنابراین محاسبات فقط در صورت نیاز انجام می‌شود.
237
+ 3. **`EffectSignal`**: پلی به "دنیای بیرون". این سیگنال یک اثر جانبی (side effect) مانند لاگ‌گیری یا رندر کردن را در پاسخ به تغییرات سیگنال‌هایی که به آن‌ها وابسته است، اجرا می‌کند.
238
+
239
+ یک نوع چهارم نیز برای رویدادهای بدون حالت وجود دارد:
240
+
241
+ 4. **`EventSignal`**: یک سیگنال بدون حالت برای ارسال رویدادهای یک‌باره که مقدار پایداری ندارند.
242
+
243
+ ---
244
+
245
+ ## شروع به کار: یک مثال عملی
246
+
247
+ بیایید یک سیستم واکنشی ساده بسازیم تا ببینیم انواع مختلف سیگنال‌ها چگونه با هم کار می‌کنند.
248
+
249
+ ### ۱. نصب
250
+
251
+ ابتدا، اطمینان حاصل کنید که بسته را نصب کرده‌اید:
252
+
253
+ ```bash
254
+ npm i @alwatr/signal
255
+ ```
256
+
257
+ ### ۲. ایجاد `StateSignal`
258
+
259
+ `StateSignal` جایی است که وضعیت برنامه شما زندگی می‌کند. بیایید سیگنال‌هایی برای نام یک کاربر و یک شمارنده ایجاد کنیم.
260
+
261
+ ```typescript
262
+ import {StateSignal} from '@alwatr/signal';
263
+
264
+ // سیگنالی برای نگهداری نام کوچک کاربر
265
+ const firstName = new StateSignal<string>({
266
+ signalId: 'user-firstName',
267
+ initialValue: 'John',
268
+ });
269
+
270
+ // سیگنالی برای نگهداری یک شمارنده ساده
271
+ const counter = new StateSignal<number>({
272
+ signalId: 'app-counter',
273
+ initialValue: 0,
274
+ });
275
+ ```
276
+
277
+ ### ۳. ایجاد `ComputedSignal`
278
+
279
+ یک `ComputedSignal` سیگنال‌های دیگر را ترکیب کرده و یک مقدار جدید و فقط-خواندنی ایجاد می‌کند. بیایید یک سیگنال `fullName` بسازیم که با تغییر `firstName` به طور خودکار به‌روز شود.
280
+
281
+ ```typescript
282
+ import {ComputedSignal} from '@alwatr/signal';
283
+
284
+ const fullName = new ComputedSignal<string>({
285
+ signalId: 'user-fullName',
286
+ deps: [firstName], // این سیگنال محاسباتی به firstName وابسته است
287
+ get: () => `User: ${firstName.value}`,
288
+ });
289
+
290
+ console.log(fullName.value); // خروجی: "User: John"
291
+ ```
292
+
293
+ ### ۴. ایجاد `EffectSignal`
294
+
295
+ یک `EffectSignal` هر زمان که یکی از وابستگی‌هایش تغییر کند، یک اثر جانبی اجرا می‌کند. این برای لاگ‌گیری، به‌روزرسانی DOM یا ارسال درخواست‌های شبکه عالی است.
296
+
297
+ ```typescript
298
+ import {EffectSignal} from '@alwatr/signal';
299
+
300
+ const loggerEffect = new EffectSignal({
301
+ deps: [fullName, counter], // این افکت به fullName و counter وابسته است
302
+ run: () => {
303
+ console.log(`${fullName.value} has clicked ${counter.value} times.`);
304
+ },
305
+ });
306
+ ```
307
+
308
+ ### ۵. کنار هم قرار دادن همه چیز
309
+
310
+ حالا، بیایید جادو را ببینیم. وقتی ما یک `StateSignal` را به‌روز می‌کنیم، تغییرات به طور خودکار در سراسر سیستم پخش می‌شوند.
311
+
312
+ ```typescript
313
+ // برای نمایش، در تغییرات مشترک می‌شویم
314
+ fullName.subscribe((newFullName) => {
315
+ console.log(`Full name signal updated to: ${newFullName}`);
316
+ });
317
+
318
+ // بیایید نام کوچک را تغییر دهیم
319
+ firstName.set('Jane');
320
+ // این کار باعث می‌شود:
321
+ // ۱. `fullName` مقدار خود را دوباره محاسبه کند.
322
+ // ۲. کال‌بک `fullName.subscribe` اجرا شود.
323
+ // ۳. `loggerEffect` اجرا شود.
324
+
325
+ // بیایید شمارنده را افزایش دهیم
326
+ counter.set(1);
327
+ // این کار باعث می‌شود:
328
+ // ۱. `loggerEffect` دوباره اجرا شود.
329
+ ```
330
+
331
+ خروجی به این صورت خواهد بود:
332
+
333
+ ```
334
+ User: John
335
+ Full name signal updated to: User: Jane
336
+ User: Jane has clicked 0 times.
337
+ User: Jane has clicked 1 times.
338
+ ```
339
+
340
+ ## مباحث پیشرفته
341
+
342
+ ### مدیریت چرخه حیات و نشت حافظه
343
+
344
+ سیگنال‌هایی که به سیگنال‌های دیگر وابسته‌اند (مانند `ComputedSignal` و `EffectSignal`) به صورت داخلی اشتراک (subscription) ایجاد می‌کنند. اگر این اشتراک‌ها را پاک‌سازی نکنید، می‌توانند منجر به نشت حافظه شوند.
345
+
346
+ **همیشه متد `destroy()` را روی `ComputedSignal` و `EffectSignal` زمانی که دیگر به آن‌ها نیازی نیست، فراخوانی کنید.**
347
+
348
+ ```typescript
349
+ // یک سیگنال محاسباتی ایجاد کنید
350
+ const isEven = new ComputedSignal({
351
+ deps: [counter],
352
+ get: () => counter.value % 2 === 0,
353
+ });
354
+
355
+ // ... مدتی از آن استفاده کنید ...
356
+
357
+ // زمانی که کامپوننت/منطقی که از آن استفاده می‌کند در شرف حذف شدن است:
358
+ isEven.destroy();
359
+ ```
360
+
361
+ فراخوانی `destroy()` اشتراک سیگنال را از تمام وابستگی‌هایش لغو می‌کند و به сборщик زباله (garbage collector) اجازه می‌دهد آن را با خیال راحت پاک کند.
362
+
363
+ ### نوتیفیکیشن‌های ناهمزمان (Asynchronous)
364
+
365
+ Alwatr Signal از یک مدل ناهمزمان قابل پیش‌بینی برای نوتیفیکیشن‌ها استفاده می‌کند:
366
+
367
+ - **`StateSignal` و `EventSignal`** نوتیفیکیشن‌ها را در صف **microtask** (`Promise.resolve().then(...)`) زمان‌بندی می‌کنند. این تضمین می‌کند که چندین فراخوانی `set()` همزمان در یک تیک حلقه رویداد (event loop) دسته‌بندی شده و شنوندگان کمی بعد، اما نه بلافاصله، مطلع می‌شوند.
368
+ - **`ComputedSignal` و `EffectSignal`** محاسبات/اجراهای خود را در صف **macrotask** (مانند `setTimeout(..., 0)`) زمان‌بندی می‌کنند. این یک بهینه‌سازی حیاتی است. اگر چندین وابستگی در یک حلقه رویداد تغییر کنند، سیگنال محاسباتی فقط _یک بار_ در هر تیک دوباره محاسبه می‌شود و از کار اضافی جلوگیری می‌کند.
369
+
370
+ ### گزینه‌های اشتراک (`subscribe`)
371
+
372
+ متد `subscribe` یک آرگومان دوم اختیاری برای سفارشی‌سازی رفتار خود می‌پذیرد:
373
+
374
+ - `once: true`: شنونده فقط یک بار فراخوانی شده و سپس به طور خودکار حذف می‌شود.
375
+ - `priority: true`: شنونده به ابتدای صف منتقل شده و قبل از سایر شنوندگان اجرا می‌شود.
376
+ - `receivePrevious: false` (فقط برای `StateSignal`): از فراخوانی فوری شنونده با مقدار فعلی در هنگام اشتراک جلوگیری می‌کند.
377
+
378
+ ## مرور کلی API
379
+
380
+ ### `StateSignal<T>`
381
+
382
+ - **`constructor(config)`**: یک سیگنال وضعیت جدید ایجاد می‌کند.
383
+ - `config.signalId`: `string`
384
+ - `config.initialValue`: `T`
385
+ - **`.value`**: `T` - مقدار فعلی را دریافت می‌کند.
386
+ - **`.set(newValue: T)`**: مقدار جدیدی را تنظیم کرده و شنوندگان را مطلع می‌کند.
387
+
388
+ ### `ComputedSignal<T>`
389
+
390
+ - **`constructor(config)`**: یک سیگنال محاسباتی جدید ایجاد می‌کند.
391
+ - `config.signalId`: `string`
392
+ - `config.deps`: `IReadonlySignal<unknown>[]` - آرایه‌ای از سیگنال‌های وابسته.
393
+ - `config.get`: `() => T` - تابعی برای محاسبه مقدار.
394
+ - **`.value`**: `T` - مقدار فعلی (کش شده) را دریافت می‌کند.
395
+ - **`.destroy()`**: اشتراک‌های سیگنال را پاک‌سازی می‌کند. **(مهم!)**
396
+
397
+ ### `EffectSignal`
398
+
399
+ - **`constructor(config)`**: یک سیگنال افکت جدید ایجاد می‌کند.
400
+ - `config.deps`: `IReadonlySignal<unknown>[]` - آرایه‌ای از سیگنال‌های وابسته.
401
+ - `config.run`: `() => void | Promise<void>` - تابع اثر جانبی.
402
+ - `config.runImmediately`: `boolean` (اختیاری) - آیا افکت در هنگام ایجاد اجرا شود یا خیر.
403
+ - **`.destroy()`**: اشتراک‌های سیگنال را پاک‌سازی می‌کند. **(مهم!)**
404
+
405
+ ### `EventSignal<T>`
406
+
407
+ - **`constructor(config)`**: یک سیگنال رویداد جدید ایجاد می‌کند.
408
+ - `config.signalId`: `string`
409
+ - **`.dispatch(payload: T)`**: یک رویداد را به تمام شنوندگان ارسال می‌کند.
410
+
411
+ ### متدهای مشترک
412
+
413
+ - **`.subscribe(callback, options?)`**: یک شنونده را مشترک می‌کند. `{ unsubscribe: () => void }` را برمی‌گرداند.
414
+ - **`.untilNext()`**: یک `Promise` برمی‌گرداند که با مقدار/پیام بعدی resolve می‌شود.
415
+ - **`.destroy()`**: (روی همه سیگنال‌ها به جز `StateSignal`) سیگنال را پاک‌سازی می‌کند.
416
+
417
+ ## حامیان (Sponsors)
418
+
419
+ شرکت‌ها، سازمان‌ها و افراد زیر از نگهداری و توسعه مداوم flux حمایت می‌کنند. با تبدیل شدن به یک حامی، لوگوی خود را در README و وب‌سایت ما قرار دهید.
420
+
421
+ ## مشارکت (Contributing)
422
+
423
+ از مشارکت‌ها استقبال می‌شود! لطفاً قبل از ارسال pull request، [راهنمای مشارکت ما](https://github.com/Alwatr/.github/blob/next/CONTRIBUTING.md) را مطالعه کنید.