@alwatr/signal 5.0.0 → 5.1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/{computed-signal.d.ts → core/computed-signal.d.ts} +3 -7
  3. package/dist/core/computed-signal.d.ts.map +1 -0
  4. package/dist/{effect-signal.d.ts → core/effect-signal.d.ts} +1 -5
  5. package/dist/core/effect-signal.d.ts.map +1 -0
  6. package/dist/{event-signal.d.ts → core/event-signal.d.ts} +1 -5
  7. package/dist/core/event-signal.d.ts.map +1 -0
  8. package/dist/{signal-base.d.ts → core/signal-base.d.ts} +3 -6
  9. package/dist/core/signal-base.d.ts.map +1 -0
  10. package/dist/{state-signal.d.ts → core/state-signal.d.ts} +20 -5
  11. package/dist/core/state-signal.d.ts.map +1 -0
  12. package/dist/creators/computed.d.ts +34 -0
  13. package/dist/creators/computed.d.ts.map +1 -0
  14. package/dist/creators/effect.d.ts +43 -0
  15. package/dist/creators/effect.d.ts.map +1 -0
  16. package/dist/creators/event.d.ts +28 -0
  17. package/dist/creators/event.d.ts.map +1 -0
  18. package/dist/creators/state.d.ts +25 -0
  19. package/dist/creators/state.d.ts.map +1 -0
  20. package/dist/main.cjs +100 -33
  21. package/dist/main.cjs.map +3 -3
  22. package/dist/main.d.ts +10 -5
  23. package/dist/main.d.ts.map +1 -1
  24. package/dist/main.mjs +94 -32
  25. package/dist/main.mjs.map +3 -3
  26. package/dist/operators/debounce.d.ts +57 -0
  27. package/dist/operators/debounce.d.ts.map +1 -0
  28. package/dist/operators/filter.d.ts +47 -0
  29. package/dist/operators/filter.d.ts.map +1 -0
  30. package/dist/operators/map.d.ts +36 -0
  31. package/dist/operators/map.d.ts.map +1 -0
  32. package/dist/type.d.ts +33 -15
  33. package/dist/type.d.ts.map +1 -1
  34. package/package.json +8 -8
  35. package/dist/computed-signal.d.ts.map +0 -1
  36. package/dist/effect-signal.d.ts.map +0 -1
  37. package/dist/event-signal.d.ts.map +0 -1
  38. package/dist/signal-base.d.ts.map +0 -1
  39. package/dist/state-signal.d.ts.map +0 -1
  40. /package/src/{computed-signal.test.js → core/computed-signal.test.js} +0 -0
  41. /package/src/{effect-signal.test.js → core/effect-signal.test.js} +0 -0
  42. /package/src/{event-signal.test.js → core/event-signal.test.js} +0 -0
  43. /package/src/{state-signal.test.js → core/state-signal.test.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,48 @@
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.1.0](https://github.com/Alwatr/flux/compare/v5.0.0...v5.1.0) (2025-09-14)
7
+
8
+ ### ✨ Features
9
+
10
+ * add createComputedSignal function for reactive value management ([da4ad2e](https://github.com/Alwatr/flux/commit/da4ad2ec31e24d0756007b666e6c6c3c3ad75709))
11
+ * add createEventSignal function for dispatching transient events ([0729eca](https://github.com/Alwatr/flux/commit/0729eca8ad7ed9fd4fca02c5f2c5f5d2f1a5acf4))
12
+ * add createFilteredSignal function to emit values from a source signal based on a predicate ([ad4873c](https://github.com/Alwatr/flux/commit/ad4873c2f5ca8d26e44db371c1387f450e12189b))
13
+ * add createMappedSignal function for transforming source signal values ([6fcefed](https://github.com/Alwatr/flux/commit/6fcefed778bd6007c639d218e3736aaf9d071d10))
14
+ * add createStateSignal function for creating stateful signals ([2764b50](https://github.com/Alwatr/flux/commit/2764b501dfc39488f7b5446935e7ebdfe06fcd35))
15
+ * add optional onDestroy callback to SignalConfig and EffectSignalConfig for resource cleanup ([d0ed93a](https://github.com/Alwatr/flux/commit/d0ed93a1f7e9da5c73222fb9a3e7e1b95fa88212))
16
+ * add signalId property to IReadonlySignal for debugging and update DebounceSignalConfig type ([d7a43ba](https://github.com/Alwatr/flux/commit/d7a43bad568d12264482475bddb045467dfe229c))
17
+ * add update method for state transitions based on previous value ([77b3593](https://github.com/Alwatr/flux/commit/77b3593df19e166b0446938104a9795b037b2d3d))
18
+ * call optional onDestroy callback in createDebouncedSignal for improved resource cleanup ([8eef425](https://github.com/Alwatr/flux/commit/8eef4252d193db5809850bd624e739bcc8549077))
19
+ * call optional onDestroy callback in destroy method for resource cleanup ([64a0e3b](https://github.com/Alwatr/flux/commit/64a0e3b6f242e91bccc48fe0cf8d1e214bcc2a5e))
20
+ * enhance createDebouncedSignal with optional signalId and onDestroy callback for improved resource management ([7ce880a](https://github.com/Alwatr/flux/commit/7ce880a40b96a3aaa78297d68cd3e7e9e05b7a20))
21
+ * enhance destroy method in SignalBase and StateSignal for improved memory management ([a81f005](https://github.com/Alwatr/flux/commit/a81f0057803fe1c0c0650d0a2223319064739067))
22
+ * implement createDebouncedSignal function for debouncing updates from a source signal ([42bd6a9](https://github.com/Alwatr/flux/commit/42bd6a915494222171317142bd21e11ff3ef2e25))
23
+ * implement createEffect function for managing reactive side-effects ([730c847](https://github.com/Alwatr/flux/commit/730c847ed6720ca7761dfb5745d957a681352a9c))
24
+ * implement IReadonlySignal interface in ComputedSignal and call optional onDestroy callback in destroy method ([8828230](https://github.com/Alwatr/flux/commit/8828230fa2ea8246d6b08d73dfee863eceea4c82))
25
+ * improve resource cleanup in createDebouncedSignal by checking internalSignal state before destruction ([36b8505](https://github.com/Alwatr/flux/commit/36b850505c0541906038a05f2cf5967baac1b2cb))
26
+ * update createDebouncedSignal to use ComputedSignal type and streamline resource cleanup in onDestroy callback ([bb0908a](https://github.com/Alwatr/flux/commit/bb0908a03ad9a86e432b8bfa17e21ced881c8f41))
27
+
28
+ ### 🐛 Bug Fixes
29
+
30
+ * debounce destroy ([e14a39a](https://github.com/Alwatr/flux/commit/e14a39a6b4729980d5aa7486873b4aae272bec0b))
31
+ * initialize signalId in constructor and call optional onDestroy callback in destroy method ([198f9b3](https://github.com/Alwatr/flux/commit/198f9b3b08a259d118b8645bb144677ea7f24613))
32
+ * remove unused dependency @alwatr/package-tracer from package.json ([9008a40](https://github.com/Alwatr/flux/commit/9008a40b8eb7e996ee8995956ab14d93bf021407))
33
+
34
+ ### 🔨 Code Refactoring
35
+
36
+ * move fundamental signals to core ([5fc4cd9](https://github.com/Alwatr/flux/commit/5fc4cd90cb3463a876bc21f4699510aace7db8f4))
37
+ * remove packageTracer import and related dev mode initialization ([d02276e](https://github.com/Alwatr/flux/commit/d02276eed37337b1f68d2c74cc5ee366add55f35))
38
+ * remove unused IComputedSignal and IEffectSignal imports from computed and effect creators ([bf7d3f2](https://github.com/Alwatr/flux/commit/bf7d3f287ee2db101b6ca0ad30eccf5f1af4bdd1))
39
+ * reorganize exports to use core and creators directories ([cdb5225](https://github.com/Alwatr/flux/commit/cdb5225773c5a909f176bb5550ce4f3a0517f09f))
40
+ * simplify parameter and return type annotations in createComputedSignal, createEffect, and createEventSignal ([024025e](https://github.com/Alwatr/flux/commit/024025e68fb4793ab7ecd97e51ccb5f271002a52))
41
+
42
+ ### 🔗 Dependencies update
43
+
44
+ * bump the npm-dependencies group with 6 updates ([f6ae979](https://github.com/Alwatr/flux/commit/f6ae9795e34ba3913fa208f7f94794b5753b90c9))
45
+ * update @alwatr/debounce dependency to version 1.1.0 ([bce3ffe](https://github.com/Alwatr/flux/commit/bce3ffe6c174c05aef60dc9fdc7e78aa31dcc71b))
46
+ * update @types/node dependency to version 22.18.3 ([6e1a847](https://github.com/Alwatr/flux/commit/6e1a8477095f102d09b020dccfe4e638c1d058ca))
47
+
6
48
  ## [5.0.0](https://github.com/Alwatr/flux/compare/v4.1.1...v5.0.0) (2025-09-12)
7
49
 
8
50
  ### ⚠ BREAKING CHANGES
@@ -1,5 +1,5 @@
1
1
  import { StateSignal } from './state-signal.js';
2
- import type { ComputedSignalConfig, IComputedSignal, SubscribeResult } from './type.js';
2
+ import type { ComputedSignalConfig, IReadonlySignal, SubscribeResult } from '../type.js';
3
3
  /**
4
4
  * A read-only signal that derives its value from a set of dependency signals.
5
5
  *
@@ -39,7 +39,7 @@ import type { ComputedSignalConfig, IComputedSignal, SubscribeResult } from './t
39
39
  * // --- IMPORTANT: Clean up when done ---
40
40
  * fullName.destroy();
41
41
  */
42
- export declare class ComputedSignal<T> implements IComputedSignal<T> {
42
+ export declare class ComputedSignal<T> implements IReadonlySignal<T> {
43
43
  protected config_: ComputedSignalConfig<T>;
44
44
  readonly signalId: string;
45
45
  protected readonly logger_: import("@alwatr/logger").AlwatrLogger;
@@ -51,10 +51,6 @@ export declare class ComputedSignal<T> implements IComputedSignal<T> {
51
51
  protected readonly internalSignal_: StateSignal<T>;
52
52
  private readonly subscriptionList__;
53
53
  private isRecalculating__;
54
- /**
55
- * Initializes a new `ComputedSignal`.
56
- * @param config The configuration, including dependencies (`deps`) and the getter function (`get`).
57
- */
58
54
  constructor(config_: ComputedSignalConfig<T>);
59
55
  /**
60
56
  * The current value of the computed signal.
@@ -70,7 +66,7 @@ export declare class ComputedSignal<T> implements IComputedSignal<T> {
70
66
  * @returns `true` if the signal is destroyed, `false` otherwise.
71
67
  */
72
68
  get isDestroyed(): boolean;
73
- readonly subscribe: (callback: import("./type.js").ListenerCallback<T>, options?: import("./type.js").SubscribeOptions) => SubscribeResult;
69
+ readonly subscribe: (callback: import("../type.js").ListenerCallback<T>, options?: import("../type.js").SubscribeOptions) => SubscribeResult;
74
70
  readonly untilNext: () => Promise<T>;
75
71
  /**
76
72
  * Permanently disposes of the computed signal.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-signal.d.ts","sourceRoot":"","sources":["../../src/core/computed-signal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,YAAY,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,cAAc,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IAkBvC,SAAS,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAjB7D,SAAgB,QAAQ,SAAyB;IAEjD,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAqD;IAE/E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,iBAG/B;IAEH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;IAC5D,OAAO,CAAC,iBAAiB,CAAS;gBAEL,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAU7D;;;;;;OAMG;IACH,IAAW,KAAK,IAAI,CAAC,CAEpB;IAED;;;;OAIG;IACH,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,SAAgB,SAAS,2HAA6D;IAEtF,SAAgB,SAAS,mBAA6D;IAEtF;;;;;;;;OAQG;IACI,OAAO,IAAI,IAAI;IAsBtB;;;;;;;OAOG;cACa,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAqC9C"}
@@ -1,4 +1,4 @@
1
- import type { EffectSignalConfig, IEffectSignal } from './type.js';
1
+ import type { EffectSignalConfig, IEffectSignal } from '../type.js';
2
2
  /**
3
3
  * Manages a side-effect that runs in response to changes in dependency signals.
4
4
  *
@@ -49,10 +49,6 @@ export declare class EffectSignal implements IEffectSignal {
49
49
  * @returns `true` if the signal is destroyed, `false` otherwise.
50
50
  */
51
51
  get isDestroyed(): boolean;
52
- /**
53
- * Initializes a new `EffectSignal`.
54
- * @param config The configuration, including dependencies (`deps`) and the `run` function.
55
- */
56
52
  constructor(config_: EffectSignalConfig);
57
53
  /**
58
54
  * Schedules the execution of the effect's `run` function.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-signal.d.ts","sourceRoot":"","sources":["../../src/core/effect-signal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,YAAa,YAAW,aAAa;IAgB7B,SAAS,CAAC,OAAO,EAAE,kBAAkB;IAfxD,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAiC;IAE3D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;IAC5D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;OAIG;IACH,IAAW,WAAW,IAAI,OAAO,CAEhC;gBAE4B,OAAO,EAAE,kBAAkB;IAiBxD;;;;;;;OAOG;cACa,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCrC;;;;;;OAMG;IACI,OAAO,IAAI,IAAI;CAmBvB"}
@@ -1,5 +1,5 @@
1
1
  import { SignalBase } from './signal-base.js';
2
- import type { SignalConfig } from './type.js';
2
+ import type { SignalConfig } from '../type.js';
3
3
  /**
4
4
  * A stateless signal for dispatching transient events.
5
5
  *
@@ -29,10 +29,6 @@ import type { SignalConfig } from './type.js';
29
29
  */
30
30
  export declare class EventSignal<T = void> extends SignalBase<T> {
31
31
  protected logger_: import("@alwatr/logger").AlwatrLogger;
32
- /**
33
- * Initializes a new `EventSignal`.
34
- * @param config The configuration for the signal, containing its `signalId`.
35
- */
36
32
  constructor(config: SignalConfig);
37
33
  /**
38
34
  * Dispatches an event with an optional payload to all active listeners.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-signal.d.ts","sourceRoot":"","sources":["../../src/core/event-signal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,WAAW,CAAC,CAAC,GAAG,IAAI,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,OAAO,wCAAkD;gBAEhD,MAAM,EAAE,YAAY;IAKvC;;;;;;OAMG;IACI,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI;CAQlC"}
@@ -1,4 +1,4 @@
1
- import type { Observer_, SubscribeOptions, SubscribeResult, ListenerCallback, SignalConfig } from './type.js';
1
+ import type { Observer_, SubscribeOptions, SubscribeResult, ListenerCallback, SignalConfig } from '../type.js';
2
2
  import type { AlwatrLogger } from '@alwatr/logger';
3
3
  /**
4
4
  * An abstract base class for signal implementations.
@@ -10,6 +10,7 @@ import type { AlwatrLogger } from '@alwatr/logger';
10
10
  * @template T The type of data the signal will handle.
11
11
  */
12
12
  export declare abstract class SignalBase<T> {
13
+ protected config_: SignalConfig;
13
14
  /**
14
15
  * The unique identifier for this signal instance. Useful for debugging.
15
16
  */
@@ -27,11 +28,7 @@ export declare abstract class SignalBase<T> {
27
28
  * @returns `true` if the signal is destroyed, `false` otherwise.
28
29
  */
29
30
  get isDestroyed(): boolean;
30
- /**
31
- * Initializes a new `SignalBase`.
32
- * @param config The configuration for the signal, containing its `signalId`.
33
- */
34
- constructor(config: SignalConfig);
31
+ constructor(config_: SignalConfig);
35
32
  /**
36
33
  * Removes a specific observer from the observers list.
37
34
  * @param observer The observer instance to remove.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal-base.d.ts","sourceRoot":"","sources":["../../src/core/signal-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAC,MAAM,YAAY,CAAC;AAC7G,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAGjD;;;;;;;;GAQG;AACH,8BAAsB,UAAU,CAAC,CAAC;IAyBb,SAAS,CAAC,OAAO,EAAE,YAAY;IAxBlD;;OAEG;IACH,SAAgB,QAAQ,EAAE,MAAM,CAAyB;IAEzD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAEzC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAM;IAEnD,SAAS,CAAC,YAAY,UAAS;IAE/B;;;;OAIG;IACH,IAAW,WAAW,IAAI,OAAO,CAEhC;gBAE4B,OAAO,EAAE,YAAY;IAElD;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAYvD;;;;;;;;OAQG;IACI,SAAS,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe;IAoB5F;;;;;;;;OAQG;IACH,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAkCjC;;;;;;;;;;;;OAYG;IACI,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC;IAY9B;;;;;;OAMG;IACI,OAAO,IAAI,IAAI;IAStB;;;;OAIG;IACH,SAAS,CAAC,eAAe,QAAO,IAAI,CAKlC;CACH"}
@@ -1,5 +1,5 @@
1
1
  import { SignalBase } from './signal-base.js';
2
- import type { StateSignalConfig, ListenerCallback, SubscribeOptions, SubscribeResult, IReadonlySignal } from './type.js';
2
+ import type { StateSignalConfig, ListenerCallback, SubscribeOptions, SubscribeResult, IReadonlySignal } from '../type.js';
3
3
  /**
4
4
  * A stateful signal that holds a value and notifies listeners when the value changes.
5
5
  *
@@ -27,16 +27,15 @@ import type { StateSignalConfig, ListenerCallback, SubscribeOptions, SubscribeRe
27
27
  * // Set a new value, which triggers the notification.
28
28
  * counter.set(1); // Outputs: "Counter changed to: 1"
29
29
  *
30
+ * // Update value based on the previous value.
31
+ * counter.update(current => current + 1); // Outputs: "Counter changed to: 2"
32
+ *
30
33
  * // Unsubscribe when no longer needed.
31
34
  * subscription.unsubscribe();
32
35
  */
33
36
  export declare class StateSignal<T> extends SignalBase<T> implements IReadonlySignal<T> {
34
37
  private value__;
35
38
  protected logger_: import("@alwatr/logger").AlwatrLogger;
36
- /**
37
- * Initializes a new `StateSignal`.
38
- * @param config The configuration for the state signal, including `signalId` and `initialValue`.
39
- */
40
39
  constructor(config: StateSignalConfig<T>);
41
40
  /**
42
41
  * Retrieves the current value of the signal.
@@ -63,6 +62,22 @@ export declare class StateSignal<T> extends SignalBase<T> implements IReadonlySi
63
62
  * mySignal.set({ ...mySignal.value, property: 'new-value' });
64
63
  */
65
64
  set(newValue: T): void;
65
+ /**
66
+ * Updates the signal's value based on its previous value.
67
+ *
68
+ * This method is particularly useful for state transitions that depend on the current value,
69
+ * especially for objects or arrays, as it promotes an immutable update pattern.
70
+ *
71
+ * @param updater A function that receives the current value and returns the new value.
72
+ *
73
+ * @example
74
+ * // For a counter
75
+ * counterSignal.update(current => current + 1);
76
+ *
77
+ * // For an object state
78
+ * userSignal.update(currentUser => ({ ...currentUser, loggedIn: true }));
79
+ */
80
+ update(updater: (previousValue: T) => T): void;
66
81
  /**
67
82
  * Subscribes a listener to this signal.
68
83
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-signal.d.ts","sourceRoot":"","sources":["../../src/core/state-signal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,EAAC,iBAAiB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,YAAY,CAAC;AAExH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,OAAO,CAAI;IACnB,SAAS,CAAC,OAAO,wCAAkD;gBAEhD,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAM/C;;;;;;;OAOG;IACH,IAAW,KAAK,IAAI,CAAC,CAGpB;IAED;;;;;;;;;;;;;;OAcG;IACI,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI;IAe7B;;;;;;;;;;;;;;OAcG;IACI,MAAM,CAAC,OAAO,EAAE,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI;IAQrD;;;;;;;;;OASG;IACa,SAAS,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe;IA4BzG;;;OAGG;IACa,OAAO,IAAI,IAAI;CAKhC"}
@@ -0,0 +1,34 @@
1
+ import { ComputedSignal } from '../core/computed-signal.js';
2
+ import type { ComputedSignalConfig } from '../type.js';
3
+ /**
4
+ * Creates a read-only signal that derives its value from a set of dependency signals.
5
+ *
6
+ * `ComputedSignal` is a powerful tool for creating values that reactively update when their underlying
7
+ * data sources change. Its value is memoized, meaning the `get` function is only re-evaluated when
8
+ * one of its dependencies has actually changed.
9
+ *
10
+ * A key feature is its lifecycle management: a `ComputedSignal` **must** be destroyed when no longer
11
+ * needed to prevent memory leaks from its subscriptions to dependency signals.
12
+ *
13
+ * @template T The type of the computed value.
14
+ *
15
+ * @param config The configuration for the computed signal.
16
+ * @returns A new, read-only computed signal.
17
+ *
18
+ * @example
19
+ * const firstName = createStateSignal({ signalId: 'firstName', initialValue: 'John' });
20
+ * const lastName = createStateSignal({ signalId: 'lastName', initialValue: 'Doe' });
21
+ *
22
+ * const fullName = createComputedSignal({
23
+ * signalId: 'fullName',
24
+ * deps: [firstName, lastName],
25
+ * get: () => `${firstName.value} ${lastName.value}`,
26
+ * });
27
+ *
28
+ * console.log(fullName.value); // "John Doe"
29
+ *
30
+ * // IMPORTANT: Always destroy a computed signal when no longer needed.
31
+ * // fullName.destroy();
32
+ */
33
+ export declare function createComputedSignal<T>(config: ComputedSignalConfig<T>): ComputedSignal<T>;
34
+ //# sourceMappingURL=computed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../../src/creators/computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE1D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAE1F"}
@@ -0,0 +1,43 @@
1
+ import { EffectSignal } from '../core/effect-signal.js';
2
+ import type { EffectSignalConfig } from '../type.js';
3
+ /**
4
+ * Creates a side-effect that runs in response to changes in dependency signals.
5
+ *
6
+ * `EffectSignal` is designed for running logic that interacts with the "outside world"—such as
7
+ * logging, network requests, or DOM manipulation—whenever its dependencies are updated.
8
+ * It encapsulates the subscription and cleanup logic, providing a robust and memory-safe
9
+ * way to handle reactive side-effects.
10
+ *
11
+ * A key feature is its lifecycle management: an `EffectSignal` **must** be destroyed when no longer
12
+ * needed to prevent memory leaks and stop the effect from running unnecessarily.
13
+ *
14
+ * @param config The configuration for the effect.
15
+ * @returns An object with a `destroy` method to stop the effect.
16
+ *
17
+ * @example
18
+ * // --- Create dependency signals ---
19
+ * const counter = createStateSignal({ initialValue: 0, signalId: 'counter' });
20
+ * const user = createStateSignal({ initialValue: 'guest', signalId: 'user' });
21
+ *
22
+ * // --- Create an effect ---
23
+ * const analyticsEffect = createEffect({
24
+ * deps: [counter, user],
25
+ * run: () => {
26
+ * console.log(`Analytics: User '${user.value}' clicked ${counter.value} times.`);
27
+ * },
28
+ * runImmediately: true, // Optional: run once on creation
29
+ * });
30
+ * // Immediately logs: "Analytics: User 'guest' clicked 0 times."
31
+ *
32
+ * // --- Trigger the effect by updating a dependency ---
33
+ * counter.set(1);
34
+ * // After a macrotask, logs: "Analytics: User 'guest' clicked 1 times."
35
+ *
36
+ * // --- IMPORTANT: Clean up when the effect is no longer needed ---
37
+ * analyticsEffect.destroy();
38
+ *
39
+ * // Further updates will not trigger the effect.
40
+ * counter.set(2); // Nothing is logged.
41
+ */
42
+ export declare function createEffect(config: EffectSignalConfig): EffectSignal;
43
+ //# sourceMappingURL=effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/creators/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAEtD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAErE"}
@@ -0,0 +1,28 @@
1
+ import { EventSignal } from '../core/event-signal.js';
2
+ import type { SignalConfig } from '../type.js';
3
+ /**
4
+ * Creates a stateless signal for dispatching transient events.
5
+ *
6
+ * `EventSignal` is ideal for broadcasting events that do not have a persistent state.
7
+ * Unlike `StateSignal`, it does not hold a value. Listeners are only notified of new
8
+ * events as they are dispatched. This makes it suitable for modeling user interactions,
9
+ * system notifications, or any one-off message.
10
+ *
11
+ * @template T The type of the payload for the events.
12
+ *
13
+ * @param config The configuration for the event signal.
14
+ * @returns A new instance of EventSignal.
15
+ *
16
+ * @example
17
+ * const onUserClick = createEventSignal<{ x: number, y: number }>({
18
+ * signalId: 'on-user-click'
19
+ * });
20
+ *
21
+ * onUserClick.subscribe(pos => {
22
+ * console.log(`User clicked at: ${pos.x}, ${pos.y}`);
23
+ * });
24
+ *
25
+ * onUserClick.dispatch({ x: 100, y: 250 });
26
+ */
27
+ export declare function createEventSignal<T = void>(config: SignalConfig): EventSignal<T>;
28
+ //# sourceMappingURL=event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/creators/event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,CAEhF"}
@@ -0,0 +1,25 @@
1
+ import { StateSignal } from '../core/state-signal.js';
2
+ import type { StateSignalConfig } from '../type.js';
3
+ /**
4
+ * Creates a stateful signal that holds a value and notifies listeners when the value changes.
5
+ *
6
+ * `StateSignal` is the core of the signal library, representing a piece of mutable state.
7
+ * It always has a value, and new subscribers immediately receive the current value by default.
8
+ *
9
+ * @template T The type of the state it holds.
10
+ *
11
+ * @param config The configuration for the state signal.
12
+ * @returns A new instance of StateSignal.
13
+ *
14
+ * @example
15
+ * const counter = createStateSignal({
16
+ * signalId: 'counter-signal',
17
+ * initialValue: 0,
18
+ * });
19
+ *
20
+ * console.log(counter.value); // Outputs: 0
21
+ * counter.set(1);
22
+ * console.log(counter.value); // Outputs: 1
23
+ */
24
+ export declare function createStateSignal<T>(config: StateSignalConfig<T>): StateSignal<T>;
25
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/creators/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAEjF"}
package/dist/main.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /* @alwatr/signal v5.0.0 */
1
+ /* @alwatr/signal v5.1.0 */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -25,19 +25,23 @@ __export(main_exports, {
25
25
  EffectSignal: () => EffectSignal,
26
26
  EventSignal: () => EventSignal,
27
27
  SignalBase: () => SignalBase,
28
- StateSignal: () => StateSignal
28
+ StateSignal: () => StateSignal,
29
+ createComputedSignal: () => createComputedSignal,
30
+ createDebouncedSignal: () => createDebouncedSignal,
31
+ createEffect: () => createEffect,
32
+ createEventSignal: () => createEventSignal,
33
+ createStateSignal: () => createStateSignal
29
34
  });
30
35
  module.exports = __toCommonJS(main_exports);
31
36
 
32
- // src/signal-base.ts
33
- var import_package_tracer = require("@alwatr/package-tracer");
34
- __dev_mode__: import_package_tracer.packageTracer.add("@alwatr/signal", "5.0.0");
37
+ // src/core/signal-base.ts
35
38
  var SignalBase = class {
36
- /**
37
- * Initializes a new `SignalBase`.
38
- * @param config The configuration for the signal, containing its `signalId`.
39
- */
40
- constructor(config) {
39
+ constructor(config_) {
40
+ this.config_ = config_;
41
+ /**
42
+ * The unique identifier for this signal instance. Useful for debugging.
43
+ */
44
+ this.signalId = this.config_.signalId;
41
45
  /**
42
46
  * The list of observers (listeners) subscribed to this signal.
43
47
  * @protected
@@ -55,7 +59,6 @@ var SignalBase = class {
55
59
  throw new Error(`Cannot interact with a destroyed signal (id: ${this.signalId})`);
56
60
  }
57
61
  };
58
- this.signalId = config.signalId;
59
62
  }
60
63
  /**
61
64
  * Indicates whether the signal has been destroyed.
@@ -169,19 +172,18 @@ var SignalBase = class {
169
172
  */
170
173
  destroy() {
171
174
  this.logger_.logMethod?.("destroy");
175
+ if (this.isDestroyed_) return;
172
176
  this.isDestroyed_ = true;
173
177
  this.observers_.length = 0;
178
+ this.config_.onDestroy?.();
179
+ this.config_ = null;
174
180
  }
175
181
  };
176
182
 
177
- // src/event-signal.ts
183
+ // src/core/event-signal.ts
178
184
  var import_delay = require("@alwatr/delay");
179
185
  var import_logger = require("@alwatr/logger");
180
186
  var EventSignal = class extends SignalBase {
181
- /**
182
- * Initializes a new `EventSignal`.
183
- * @param config The configuration for the signal, containing its `signalId`.
184
- */
185
187
  constructor(config) {
186
188
  super(config);
187
189
  this.logger_ = (0, import_logger.createLogger)(`event-signal: ${this.signalId}`);
@@ -203,14 +205,10 @@ var EventSignal = class extends SignalBase {
203
205
  }
204
206
  };
205
207
 
206
- // src/state-signal.ts
208
+ // src/core/state-signal.ts
207
209
  var import_delay2 = require("@alwatr/delay");
208
210
  var import_logger2 = require("@alwatr/logger");
209
211
  var StateSignal = class extends SignalBase {
210
- /**
211
- * Initializes a new `StateSignal`.
212
- * @param config The configuration for the state signal, including `signalId` and `initialValue`.
213
- */
214
212
  constructor(config) {
215
213
  super(config);
216
214
  this.logger_ = (0, import_logger2.createLogger)(`state-signal: ${this.signalId}`);
@@ -253,6 +251,26 @@ var StateSignal = class extends SignalBase {
253
251
  this.notify_(newValue);
254
252
  });
255
253
  }
254
+ /**
255
+ * Updates the signal's value based on its previous value.
256
+ *
257
+ * This method is particularly useful for state transitions that depend on the current value,
258
+ * especially for objects or arrays, as it promotes an immutable update pattern.
259
+ *
260
+ * @param updater A function that receives the current value and returns the new value.
261
+ *
262
+ * @example
263
+ * // For a counter
264
+ * counterSignal.update(current => current + 1);
265
+ *
266
+ * // For an object state
267
+ * userSignal.update(currentUser => ({ ...currentUser, loggedIn: true }));
268
+ */
269
+ update(updater) {
270
+ this.logger_.logMethod?.("update");
271
+ this.checkDestroyed_();
272
+ this.set(updater(this.value__));
273
+ }
256
274
  /**
257
275
  * Subscribes a listener to this signal.
258
276
  *
@@ -283,19 +301,15 @@ var StateSignal = class extends SignalBase {
283
301
  * This is crucial for memory management to prevent leaks.
284
302
  */
285
303
  destroy() {
286
- super.destroy();
287
304
  this.value__ = null;
305
+ super.destroy();
288
306
  }
289
307
  };
290
308
 
291
- // src/computed-signal.ts
309
+ // src/core/computed-signal.ts
292
310
  var import_delay3 = require("@alwatr/delay");
293
311
  var import_logger3 = require("@alwatr/logger");
294
312
  var ComputedSignal = class {
295
- /**
296
- * Initializes a new `ComputedSignal`.
297
- * @param config The configuration, including dependencies (`deps`) and the getter function (`get`).
298
- */
299
313
  constructor(config_) {
300
314
  this.config_ = config_;
301
315
  this.signalId = this.config_.signalId;
@@ -357,6 +371,7 @@ var ComputedSignal = class {
357
371
  }
358
372
  this.subscriptionList__.length = 0;
359
373
  this.internalSignal_.destroy();
374
+ this.config_.onDestroy?.();
360
375
  this.config_ = null;
361
376
  }
362
377
  /**
@@ -393,14 +408,10 @@ var ComputedSignal = class {
393
408
  }
394
409
  };
395
410
 
396
- // src/effect-signal.ts
411
+ // src/core/effect-signal.ts
397
412
  var import_delay4 = require("@alwatr/delay");
398
413
  var import_logger4 = require("@alwatr/logger");
399
414
  var EffectSignal = class {
400
- /**
401
- * Initializes a new `EffectSignal`.
402
- * @param config The configuration, including dependencies (`deps`) and the `run` function.
403
- */
404
415
  constructor(config_) {
405
416
  this.config_ = config_;
406
417
  this.logger_ = (0, import_logger4.createLogger)(`effect-signal`);
@@ -475,15 +486,71 @@ var EffectSignal = class {
475
486
  subscription.unsubscribe();
476
487
  }
477
488
  this.subscriptionList__.length = 0;
489
+ this.config_.onDestroy?.();
478
490
  this.config_ = null;
479
491
  }
480
492
  };
493
+
494
+ // src/creators/event.ts
495
+ function createEventSignal(config) {
496
+ return new EventSignal(config);
497
+ }
498
+
499
+ // src/creators/state.ts
500
+ function createStateSignal(config) {
501
+ return new StateSignal(config);
502
+ }
503
+
504
+ // src/creators/computed.ts
505
+ function createComputedSignal(config) {
506
+ return new ComputedSignal(config);
507
+ }
508
+
509
+ // src/creators/effect.ts
510
+ function createEffect(config) {
511
+ return new EffectSignal(config);
512
+ }
513
+
514
+ // src/operators/debounce.ts
515
+ var import_debounce = require("@alwatr/debounce");
516
+ function createDebouncedSignal(sourceSignal, config) {
517
+ const signalId = config.signalId ?? `${sourceSignal.signalId}-debounced`;
518
+ const internalSignal = new StateSignal({
519
+ signalId: `${signalId}-internal`,
520
+ initialValue: sourceSignal.value
521
+ });
522
+ const debouncer = (0, import_debounce.createDebouncer)({
523
+ ...config,
524
+ func: (value) => {
525
+ internalSignal.set(value);
526
+ }
527
+ });
528
+ const subscription = sourceSignal.subscribe(debouncer.trigger);
529
+ return createComputedSignal({
530
+ signalId,
531
+ deps: [internalSignal],
532
+ get: () => internalSignal.value,
533
+ onDestroy: () => {
534
+ if (internalSignal.isDestroyed) return;
535
+ subscription.unsubscribe();
536
+ debouncer.cancel();
537
+ internalSignal.destroy();
538
+ config.onDestroy?.();
539
+ config = null;
540
+ }
541
+ });
542
+ }
481
543
  // Annotate the CommonJS export names for ESM import in node:
482
544
  0 && (module.exports = {
483
545
  ComputedSignal,
484
546
  EffectSignal,
485
547
  EventSignal,
486
548
  SignalBase,
487
- StateSignal
549
+ StateSignal,
550
+ createComputedSignal,
551
+ createDebouncedSignal,
552
+ createEffect,
553
+ createEventSignal,
554
+ createStateSignal
488
555
  });
489
556
  //# sourceMappingURL=main.cjs.map