@xmachines/play-signals 2.0.0 → 2.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.
package/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # @xmachines/play-signals
2
2
 
3
- TC39 Signals polyfill for XMachines fine-grained reactive state primitives that enable glitch-free, subscription-free state propagation in the Play Architecture.
3
+ TC39 Signals polyfill for XMachines. It gives the Play Architecture fine-grained reactive state primitives. The primitives propagate state without a glitch and without a subscription.
4
4
 
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.0.0-blue)](https://www.npmjs.com/package/@xmachines/play-signals)
6
-
7
- Part of the [xmachines-js monorepo](../../README.md).
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.1.0-blue)](https://www.npmjs.com/package/@xmachines/play-signals)
8
6
 
9
7
  ## Installation
10
8
 
@@ -14,9 +12,9 @@ pnpm add @xmachines/play-signals
14
12
 
15
13
  ## Overview
16
14
 
17
- This package wraps the [`signal-polyfill`](https://github.com/nicolo-ribaudo/tc39-proposal-signals-polyfill) reference implementation of the [TC39 Signals proposal](https://github.com/tc39/proposal-signals) (Stage 1). It re-exports the full `Signal` namespace and adds a memory-safe `watchSignal` utility, isolating the rest of the codebase from potential Stage 1 API churn.
15
+ This package wraps the [`signal-polyfill`](https://github.com/nicolo-ribaudo/tc39-proposal-signals-polyfill) reference implementation of the [TC39 Signals proposal](https://github.com/tc39/proposal-signals) (Stage 1). It re-exports the complete `Signal` namespace, and it adds the memory-safe `watchSignal` utility. The wrapper keeps the rest of the code away from a Stage 1 API that can still change.
18
16
 
19
- **All signal imports in the XMachines ecosystem should come from this package**, not directly from `signal-polyfill`, so that polyfill version bumps or API adaptations can be made in one place.
17
+ **Import every signal in the XMachines ecosystem from this package**, not from `signal-polyfill`. One import point keeps each polyfill update and each API change in one place.
20
18
 
21
19
  ## Usage
22
20
 
@@ -46,11 +44,11 @@ console.log(doubled.get()); // 10 (recomputed because dependency changed)
46
44
  console.log(doubled.get()); // 10 (memoized — no recomputation)
47
45
  ```
48
46
 
49
- Computations automatically track every signal accessed inside them. Dynamic branching is fully supported only signals read in the _current_ execution path are tracked as dependencies.
47
+ A computation tracks each signal that it reads. A dynamic branch is safe: the computation keeps only the signals of the _current_ execution path as its dependencies.
50
48
 
51
49
  ### `watchSignal` — memory-safe one-shot effect
52
50
 
53
- Use `watchSignal` to subscribe to a `Signal.State` or `Signal.Computed` and receive its value after each change. Updates are coalesced into a single microtask per synchronous batch.
51
+ Use `watchSignal` to subscribe to a `Signal.State` or to a `Signal.Computed`. The callback receives the value after each change. `watchSignal` groups the updates of one synchronous batch into a single microtask.
54
52
 
55
53
  ```typescript
56
54
  import { Signal, watchSignal } from "@xmachines/play-signals";
@@ -69,11 +67,11 @@ count.set(3); // → logs "count changed: 3" once
69
67
  cleanup();
70
68
  ```
71
69
 
72
- The returned cleanup function is idempotent calling it multiple times is safe and will not throw.
70
+ The cleanup function is idempotent. A second call is safe, and it does not throw.
73
71
 
74
72
  ### `Signal.subtle.Watcher` — low-level multi-signal observation
75
73
 
76
- For advanced use cases such as framework integrations, the full `Signal.subtle.Watcher` API is available:
74
+ Advanced code, such as a framework integration, can use the complete `Signal.subtle.Watcher` API:
77
75
 
78
76
  ```typescript
79
77
  import { Signal } from "@xmachines/play-signals";
@@ -97,7 +95,7 @@ count.set(5); // schedules microtask notification
97
95
 
98
96
  ### Custom equality
99
97
 
100
- Both `Signal.State` and `Signal.Computed` accept an `equals` option to control when dependents are notified:
98
+ Both `Signal.State` and `Signal.Computed` accept an `equals` option. The option controls when a signal notifies its dependents:
101
99
 
102
100
  ```typescript
103
101
  import { Signal } from "@xmachines/play-signals";
@@ -108,7 +106,7 @@ const options: SignalOptions<{ name: string; age: number }> = {
108
106
  };
109
107
 
110
108
  const person = new Signal.State({ name: "Alice", age: 30 }, options);
111
- // Setting structurally identical value will not notify dependents
109
+ // A structurally identical value does not notify the dependents
112
110
  person.set({ name: "Alice", age: 30 });
113
111
  ```
114
112
 
@@ -117,13 +115,13 @@ person.set({ name: "Alice", age: 30 });
117
115
  | Export | Kind | Description |
118
116
  | ------------------------------ | --------- | ------------------------------------------------------------------------------------------------------ |
119
117
  | `Signal` | namespace | Full TC39 Signals namespace (`State`, `Computed`, `subtle.Watcher`) re-exported from `signal-polyfill` |
120
- | `watchSignal(signal, onValue)` | function | Memory-safe subscription helper; returns a cleanup function |
118
+ | `watchSignal(signal, onValue)` | function | The memory-safe subscription helper. It returns a cleanup function |
121
119
  | `SignalState<T>` | interface | Shape of `Signal.State<T>` (`.get()`, `.set()`) |
122
120
  | `SignalComputed<T>` | interface | Shape of `Signal.Computed<T>` (`.get()`) |
123
121
  | `SignalWatcher` | interface | Shape of `Signal.subtle.Watcher` (`.watch()`, `.unwatch()`, `.getPending()`) |
124
- | `SignalOptions<T>` | interface | Options bag for `Signal.State` constructor (`equals?`) |
125
- | `ComputedOptions<T>` | interface | Options bag for `Signal.Computed` constructor (`equals?`) |
126
- | `WatcherNotify` | type | Callback signature for `Signal.subtle.Watcher` notify function |
122
+ | `SignalOptions<T>` | interface | The options object for the `Signal.State` constructor (`equals?`) |
123
+ | `ComputedOptions<T>` | interface | The options object for the `Signal.Computed` constructor (`equals?`) |
124
+ | `WatcherNotify` | type | The callback signature of the `Signal.subtle.Watcher` notify function |
127
125
 
128
126
  ## Testing
129
127
 
@@ -150,7 +148,7 @@ pnpm run test:coverage
150
148
  ## Requirements
151
149
 
152
150
  - **Node.js** `>= 22.0.0`
153
- - **TypeScript** `5.7+` (for consumers using TypeScript)
151
+ - **TypeScript** `5.7+` (for a consumer that uses TypeScript)
154
152
 
155
153
  ## License
156
154
 
package/dist/index.d.ts CHANGED
@@ -1,29 +1,31 @@
1
1
  /**
2
- * TC39 Signals Polyfill for XMachines Play Architecture
2
+ * The TC39 Signals polyfill of the XMachines Play Architecture
3
3
  *
4
- * Provides fine-grained reactive state primitives based on the TC39 Signals proposal (Stage 1).
5
- * This package isolates the TC39 polyfill to protect the codebase from Stage 1 API changes.
4
+ * This package gives you the fine-grained reactive state primitives of the TC39
5
+ * Signals proposal (Stage 1). It keeps the TC39 polyfill in one place, and it
6
+ * therefore protects the code from a change of the Stage 1 API.
6
7
  *
7
- * **Architectural Context:** Implements **Signal-Only Reactivity (INV-05)** by providing
8
- * the reactive primitives that enable Actor-to-Infrastructure communication without
9
- * subscriptions or event emitters. All state propagation in Play Architecture uses
10
- * TC39 Signals for automatic dependency tracking and glitch-free updates.
8
+ * **Architectural context:** the package implements **Signal-Only Reactivity
9
+ * (INV-05)**. It gives the reactive primitives that carry the communication from
10
+ * the Actor to the infrastructure, without a subscription and without an event
11
+ * emitter. Every propagation of state in the Play Architecture uses a TC39 Signal,
12
+ * which tracks each dependency and updates without a glitch.
11
13
  *
12
14
  * @packageDocumentation
13
15
  * @module @xmachines/play-signals
14
16
  *
15
17
  * @example
16
- * Basic Signal usage
18
+ * The basic use of a signal
17
19
  * ```typescript
18
20
  * import { Signal } from "@xmachines/play-signals";
19
21
  *
20
- * // Create state signal
22
+ * // Create a state signal
21
23
  * const count = new Signal.State(0);
22
24
  *
23
- * // Create computed signal
25
+ * // Create a computed signal
24
26
  * const doubled = new Signal.Computed(() => count.get() * 2);
25
27
  *
26
- * // Observe changes
28
+ * // Observe the changes
27
29
  * const watcher = new Signal.subtle.Watcher(() => {
28
30
  * console.log('Count:', count.get(), 'Doubled:', doubled.get());
29
31
  * });
@@ -32,18 +34,20 @@
32
34
  * count.set(5); // Logs: Count: 5 Doubled: 10
33
35
  * ```
34
36
  *
35
- * @see [Play RFC](../../docs/rfc/play.md) - Invariant INV-05
37
+ * @see [Play RFC](../../docs/rfc/play.md) - invariant INV-05
36
38
  * @see {@link https://github.com/tc39/proposal-signals | TC39 Signals Proposal}
37
39
  *
38
40
  * @remarks
39
- * **Stage 1 Status:** TC39 Signals is currently Stage 1 in the TC39 process. This package
40
- * uses the official `signal-polyfill` reference implementation to isolate the codebase
41
- * from potential API changes as the proposal evolves. All signal imports should go through
42
- * this package to maintain isolation.
43
- *
44
- * **Why Isolation:** By re-exporting the polyfill through this dedicated package, we can
45
- * update the polyfill version or adapt to API changes in one place without touching
46
- * consuming packages. This architectural decision protects against Stage 1 API churn.
41
+ * **Stage 1 status:** TC39 Signals is at Stage 1 in the TC39 process now. This
42
+ * package uses the official `signal-polyfill` reference implementation. The code
43
+ * therefore stays separate from an API that can change while the proposal
44
+ * develops. Import every signal through this package, and the separation stays
45
+ * complete.
46
+ *
47
+ * **The reason for the separation:** this dedicated package re-exports the
48
+ * polyfill. Therefore one place holds each new polyfill version and each change of
49
+ * the API, and no consuming package changes. This architectural decision protects
50
+ * the code from a change of the Stage 1 API.
47
51
  */
48
52
  export { Signal } from "signal-polyfill";
49
53
  export { watchSignal } from "./watch-signal.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,YAAY,EACX,WAAW,EACX,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,GACb,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,YAAY,EACX,WAAW,EACX,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,GACb,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,29 +1,31 @@
1
1
  /**
2
- * TC39 Signals Polyfill for XMachines Play Architecture
2
+ * The TC39 Signals polyfill of the XMachines Play Architecture
3
3
  *
4
- * Provides fine-grained reactive state primitives based on the TC39 Signals proposal (Stage 1).
5
- * This package isolates the TC39 polyfill to protect the codebase from Stage 1 API changes.
4
+ * This package gives you the fine-grained reactive state primitives of the TC39
5
+ * Signals proposal (Stage 1). It keeps the TC39 polyfill in one place, and it
6
+ * therefore protects the code from a change of the Stage 1 API.
6
7
  *
7
- * **Architectural Context:** Implements **Signal-Only Reactivity (INV-05)** by providing
8
- * the reactive primitives that enable Actor-to-Infrastructure communication without
9
- * subscriptions or event emitters. All state propagation in Play Architecture uses
10
- * TC39 Signals for automatic dependency tracking and glitch-free updates.
8
+ * **Architectural context:** the package implements **Signal-Only Reactivity
9
+ * (INV-05)**. It gives the reactive primitives that carry the communication from
10
+ * the Actor to the infrastructure, without a subscription and without an event
11
+ * emitter. Every propagation of state in the Play Architecture uses a TC39 Signal,
12
+ * which tracks each dependency and updates without a glitch.
11
13
  *
12
14
  * @packageDocumentation
13
15
  * @module @xmachines/play-signals
14
16
  *
15
17
  * @example
16
- * Basic Signal usage
18
+ * The basic use of a signal
17
19
  * ```typescript
18
20
  * import { Signal } from "@xmachines/play-signals";
19
21
  *
20
- * // Create state signal
22
+ * // Create a state signal
21
23
  * const count = new Signal.State(0);
22
24
  *
23
- * // Create computed signal
25
+ * // Create a computed signal
24
26
  * const doubled = new Signal.Computed(() => count.get() * 2);
25
27
  *
26
- * // Observe changes
28
+ * // Observe the changes
27
29
  * const watcher = new Signal.subtle.Watcher(() => {
28
30
  * console.log('Count:', count.get(), 'Doubled:', doubled.get());
29
31
  * });
@@ -32,20 +34,22 @@
32
34
  * count.set(5); // Logs: Count: 5 Doubled: 10
33
35
  * ```
34
36
  *
35
- * @see [Play RFC](../../docs/rfc/play.md) - Invariant INV-05
37
+ * @see [Play RFC](../../docs/rfc/play.md) - invariant INV-05
36
38
  * @see {@link https://github.com/tc39/proposal-signals | TC39 Signals Proposal}
37
39
  *
38
40
  * @remarks
39
- * **Stage 1 Status:** TC39 Signals is currently Stage 1 in the TC39 process. This package
40
- * uses the official `signal-polyfill` reference implementation to isolate the codebase
41
- * from potential API changes as the proposal evolves. All signal imports should go through
42
- * this package to maintain isolation.
43
- *
44
- * **Why Isolation:** By re-exporting the polyfill through this dedicated package, we can
45
- * update the polyfill version or adapt to API changes in one place without touching
46
- * consuming packages. This architectural decision protects against Stage 1 API churn.
41
+ * **Stage 1 status:** TC39 Signals is at Stage 1 in the TC39 process now. This
42
+ * package uses the official `signal-polyfill` reference implementation. The code
43
+ * therefore stays separate from an API that can change while the proposal
44
+ * develops. Import every signal through this package, and the separation stays
45
+ * complete.
46
+ *
47
+ * **The reason for the separation:** this dedicated package re-exports the
48
+ * polyfill. Therefore one place holds each new polyfill version and each change of
49
+ * the API, and no consuming package changes. This architectural decision protects
50
+ * the code from a change of the Stage 1 API.
47
51
  */
48
- // Re-export complete Signal namespace from official polyfill
52
+ // Re-export the complete Signal namespace of the official polyfill
49
53
  export { Signal } from "signal-polyfill";
50
54
  export { watchSignal } from "./watch-signal.js";
51
55
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,6DAA6D;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,mEAAmE;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  /**
2
- * Type definitions for TC39 Signals API
2
+ * The type definitions of the TC39 Signals API
3
3
  *
4
- * These types align with the signal-polyfill implementation and TC39 proposal.
5
- * Note: Signal is Stage 1 - API may change in future spec updates.
4
+ * These types follow the signal-polyfill implementation and the TC39 proposal.
5
+ * Note: Signal is at Stage 1, and a later version of the specification can change
6
+ * the API.
6
7
  *
7
8
  * @see {@link https://github.com/tc39/proposal-signals | TC39 Signals Proposal}
8
9
  */
9
10
  /**
10
- * Options for creating Signal.State
11
+ * The options of a Signal.State
11
12
  *
12
- * @param equals - Optional custom equality function for determining if value changed
13
+ * @param equals - The optional equality function of your own. It decides if the value changed
13
14
  *
14
15
  * @example
15
16
  * ```typescript
@@ -24,19 +25,19 @@
24
25
  */
25
26
  export interface SignalOptions<T> {
26
27
  /**
27
- * Custom equality function for determining if value changed
28
- * @param a - Previous value
29
- * @param b - New value
30
- * @returns true if values are equal (no notification needed)
28
+ * The equality function of your own. It decides if the value changed
29
+ * @param a - The previous value
30
+ * @param b - The new value
31
+ * @returns true when the two values are equal, and no notification is necessary
31
32
  */
32
33
  equals?: (a: T, b: T) => boolean;
33
34
  }
34
35
  /**
35
- * Writable state signal holding a single reactive value
36
+ * The writable state signal. It holds one reactive value
36
37
  *
37
- * Signal.State is the fundamental primitive for reactive state. Calling `get()` within
38
- * a computed signal or watcher automatically tracks the state as a dependency. Calling
39
- * `set()` notifies all dependent computations and watchers.
38
+ * Signal.State is the base primitive of a reactive state. A `get()` call inside a
39
+ * computed signal or inside a watcher tracks the state as a dependency. A `set()`
40
+ * call notifies every computation and every watcher that depends on the state.
40
41
  *
41
42
  * @example
42
43
  * ```typescript
@@ -50,22 +51,22 @@ export interface SignalOptions<T> {
50
51
  */
51
52
  export interface SignalState<T> {
52
53
  /**
53
- * Read current value and track as dependency
54
+ * Reads the current value, and tracks the signal as a dependency
54
55
  *
55
- * @returns Current value of the signal
56
+ * @returns The current value of the signal
56
57
  */
57
58
  get(): T;
58
59
  /**
59
- * Write new value and notify watchers if changed
60
+ * Writes a new value, and notifies the watchers when the value changed
60
61
  *
61
- * @param value - New value to set
62
+ * @param value - The new value
62
63
  */
63
64
  set(value: T): void;
64
65
  }
65
66
  /**
66
- * Options for creating Signal.Computed
67
+ * The options of a Signal.Computed
67
68
  *
68
- * @param equals - Optional custom equality function for memoization
69
+ * @param equals - The optional equality function of your own, for the memoization
69
70
  *
70
71
  * @example
71
72
  * ```typescript
@@ -79,16 +80,16 @@ export interface SignalState<T> {
79
80
  */
80
81
  export interface ComputedOptions<T> {
81
82
  /**
82
- * Custom equality function for memoization
83
+ * The equality function of your own, for the memoization
83
84
  */
84
85
  equals?: (a: T, b: T) => boolean;
85
86
  }
86
87
  /**
87
- * Lazily-evaluated, memoized computed signal
88
+ * The computed signal. It evaluates late, and it memoizes the result
88
89
  *
89
- * Signal.Computed automatically tracks dependencies when its callback is executed.
90
- * The computation is memoized and only re-runs when dependencies change. This enables
91
- * automatic dependency tracking without manual subscription management.
90
+ * Signal.Computed tracks each dependency when it runs its callback. It memoizes the
91
+ * result, and it runs the callback again only after a dependency changes. It
92
+ * therefore tracks each dependency for you, and you manage no subscription.
92
93
  *
93
94
  * @example
94
95
  * ```typescript
@@ -99,23 +100,24 @@ export interface ComputedOptions<T> {
99
100
  *
100
101
  * console.log(doubled.get()); // 0
101
102
  * count.set(5);
102
- * console.log(doubled.get()); // 10 (recomputed)
103
- * console.log(doubled.get()); // 10 (memoized, not recomputed)
103
+ * console.log(doubled.get()); // 10 (the signal computed it again)
104
+ * console.log(doubled.get()); // 10 (from the memory, with no new computation)
104
105
  * ```
105
106
  */
106
107
  export interface SignalComputed<T> {
107
108
  /**
108
- * Read computed value (recalculates only if dependencies changed)
109
+ * Reads the computed value. It computes the value again only after a dependency changed
109
110
  *
110
- * @returns Computed value based on current dependencies
111
+ * @returns The value from the current dependencies
111
112
  */
112
113
  get(): T;
113
114
  }
114
115
  /**
115
- * Notification callback for Signal.subtle.Watcher
116
+ * The notification callback of a Signal.subtle.Watcher
116
117
  *
117
- * Invoked when watched signals change. Use microtask batching pattern to coalesce
118
- * rapid updates (see signal-polyfill README for best practices).
118
+ * The watcher calls it after a signal that it watches changes. Use the microtask
119
+ * batching pattern to group rapid updates. The README of signal-polyfill gives the
120
+ * best practice.
119
121
  *
120
122
  * @example
121
123
  * ```typescript
@@ -124,7 +126,7 @@ export interface SignalComputed<T> {
124
126
  * const notify: WatcherNotify = () => {
125
127
  * queueMicrotask(() => {
126
128
  * const pending = watcher.getPending();
127
- * // Process pending signal changes
129
+ * // Process the signal changes that wait
128
130
  * });
129
131
  * };
130
132
  * const watcher = new Signal.subtle.Watcher(notify);
@@ -132,10 +134,10 @@ export interface SignalComputed<T> {
132
134
  */
133
135
  export type WatcherNotify = () => void;
134
136
  /**
135
- * Watcher for observing signal changes and scheduling effects
137
+ * The watcher. It observes each signal change and schedules an effect
136
138
  *
137
- * Signal.subtle.Watcher enables observing multiple signals and batching updates.
138
- * This is the low-level primitive used by frameworks to implement reactive effects.
139
+ * Signal.subtle.Watcher observes more than one signal, and it groups the updates.
140
+ * It is the low-level primitive, and a framework uses it to make a reactive effect.
139
141
  *
140
142
  * @example
141
143
  * ```typescript
@@ -154,26 +156,26 @@ export type WatcherNotify = () => void;
154
156
  * watcher.watch(count);
155
157
  * watcher.watch(doubled);
156
158
  *
157
- * count.set(5); // Notification scheduled via microtask
159
+ * count.set(5); // The watcher schedules the notification in a microtask
158
160
  * ```
159
161
  */
160
162
  export interface SignalWatcher {
161
163
  /**
162
- * Start watching a signal for changes
164
+ * Starts the watch of one signal
163
165
  *
164
- * @param signal - Signal to observe (State or Computed)
166
+ * @param signal - The signal to observe: a State or a Computed
165
167
  */
166
168
  watch(signal: SignalState<unknown> | SignalComputed<unknown>): void;
167
169
  /**
168
- * Stop watching a signal
170
+ * Stops the watch of one signal
169
171
  *
170
- * @param signal - Signal to stop observing
172
+ * @param signal - The signal to leave
171
173
  */
172
174
  unwatch(signal: SignalState<unknown> | SignalComputed<unknown>): void;
173
175
  /**
174
- * Get signals that changed since last check
176
+ * Returns the signals that changed after the last check
175
177
  *
176
- * @returns Array of signals that have pending updates
178
+ * @returns The array of the signals with an update that waits
177
179
  */
178
180
  getPending(): Array<SignalState<unknown> | SignalComputed<unknown>>;
179
181
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B;;;;OAIG;IACH,GAAG,IAAI,CAAC,CAAC;IAET;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC;;;;OAIG;IACH,GAAG,IAAI,CAAC,CAAC;CACT;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAEpE;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAEtE;;;;OAIG;IACH,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;CACpE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B;;;;OAIG;IACH,GAAG,IAAI,CAAC,CAAC;IAET;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC;;;;OAIG;IACH,GAAG,IAAI,CAAC,CAAC;CACT;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAEpE;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAEtE;;;;OAIG;IACH,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;CACpE"}
package/dist/types.js CHANGED
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Type definitions for TC39 Signals API
2
+ * The type definitions of the TC39 Signals API
3
3
  *
4
- * These types align with the signal-polyfill implementation and TC39 proposal.
5
- * Note: Signal is Stage 1 - API may change in future spec updates.
4
+ * These types follow the signal-polyfill implementation and the TC39 proposal.
5
+ * Note: Signal is at Stage 1, and a later version of the specification can change
6
+ * the API.
6
7
  *
7
8
  * @see {@link https://github.com/tc39/proposal-signals | TC39 Signals Proposal}
8
9
  */
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -1,21 +1,21 @@
1
1
  import { Signal } from "signal-polyfill";
2
2
  /**
3
- * Subscribe to a single signal using the canonical one-shot watcher lifecycle.
3
+ * Subscribes to one signal, with the canonical one-shot watcher lifecycle.
4
4
  *
5
- * The callback runs from a queued microtask after pending notifications are
6
- * drained, then the watcher re-arms itself so future updates are not missed.
7
- * The returned cleanup keeps teardown idempotent by tolerating already-detached
8
- * watchers.
5
+ * The callback runs from a microtask in the queue, after the watcher drains the
6
+ * notifications that wait. The watcher then arms itself again, so that it misses no
7
+ * later update. The cleanup function is idempotent, because it accepts a watcher
8
+ * that is detached already.
9
9
  *
10
10
  * **Memory safety (Phase 29):**
11
- * - `disposed` flag prevents post-cleanup callback execution: if cleanup is
12
- * called before a pending microtask fires, the microtask returns early.
13
- * - `needsEnqueue` guard dedups rapid synchronous signal changes: only one
14
- * microtask is ever queued per batch of synchronous mutations.
11
+ * - The `disposed` flag stops a callback after the cleanup: the microtask returns at
12
+ * once when the cleanup runs before the microtask fires.
13
+ * - The `needsEnqueue` guard removes the duplicates of rapid synchronous signal
14
+ * changes: one batch of synchronous changes queues one microtask only.
15
15
  *
16
- * @param signal - A `Signal.State` or `Signal.Computed` to subscribe to.
17
- * @param onValue - Called with the current signal value after each change.
18
- * @returns A cleanup function that unregisters the watcher.
16
+ * @param signal - The `Signal.State` or `Signal.Computed` to subscribe to.
17
+ * @param onValue - The watcher calls it with the current signal value after each change.
18
+ * @returns The cleanup function. It removes the watcher.
19
19
  */
20
20
  export declare function watchSignal<T>(signal: Signal.State<T> | Signal.Computed<T>, onValue: (value: T) => void): () => void;
21
21
  //# sourceMappingURL=watch-signal.d.ts.map
@@ -1,21 +1,21 @@
1
1
  import { Signal } from "signal-polyfill";
2
2
  /**
3
- * Subscribe to a single signal using the canonical one-shot watcher lifecycle.
3
+ * Subscribes to one signal, with the canonical one-shot watcher lifecycle.
4
4
  *
5
- * The callback runs from a queued microtask after pending notifications are
6
- * drained, then the watcher re-arms itself so future updates are not missed.
7
- * The returned cleanup keeps teardown idempotent by tolerating already-detached
8
- * watchers.
5
+ * The callback runs from a microtask in the queue, after the watcher drains the
6
+ * notifications that wait. The watcher then arms itself again, so that it misses no
7
+ * later update. The cleanup function is idempotent, because it accepts a watcher
8
+ * that is detached already.
9
9
  *
10
10
  * **Memory safety (Phase 29):**
11
- * - `disposed` flag prevents post-cleanup callback execution: if cleanup is
12
- * called before a pending microtask fires, the microtask returns early.
13
- * - `needsEnqueue` guard dedups rapid synchronous signal changes: only one
14
- * microtask is ever queued per batch of synchronous mutations.
11
+ * - The `disposed` flag stops a callback after the cleanup: the microtask returns at
12
+ * once when the cleanup runs before the microtask fires.
13
+ * - The `needsEnqueue` guard removes the duplicates of rapid synchronous signal
14
+ * changes: one batch of synchronous changes queues one microtask only.
15
15
  *
16
- * @param signal - A `Signal.State` or `Signal.Computed` to subscribe to.
17
- * @param onValue - Called with the current signal value after each change.
18
- * @returns A cleanup function that unregisters the watcher.
16
+ * @param signal - The `Signal.State` or `Signal.Computed` to subscribe to.
17
+ * @param onValue - The watcher calls it with the current signal value after each change.
18
+ * @returns The cleanup function. It removes the watcher.
19
19
  */
20
20
  export function watchSignal(signal, onValue) {
21
21
  let disposed = false;
@@ -40,7 +40,7 @@ export function watchSignal(signal, onValue) {
40
40
  watcher.unwatch(signal);
41
41
  }
42
42
  catch {
43
- // Ignore detached watcher errors to keep cleanup idempotent.
43
+ // Ignore an error of a detached watcher. The cleanup therefore stays idempotent.
44
44
  }
45
45
  };
46
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"watch-signal.js","sourceRoot":"","sources":["../src/watch-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,WAAW,CAC1B,MAA4C,EAC5C,OAA2B;IAE3B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,YAAY,GAAG,IAAI,CAAC;IAExB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAC9C,IAAI,QAAQ,IAAI,CAAC,YAAY;YAAE,OAAO;QACtC,YAAY,GAAG,KAAK,CAAC;QACrB,cAAc,CAAC,GAAG,EAAE;YACnB,IAAI,QAAQ;gBAAE,OAAO;YACrB,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtB,OAAO,GAAG,EAAE;QACX,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC;YACJ,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACR,6DAA6D;QAC9D,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"watch-signal.js","sourceRoot":"","sources":["../src/watch-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,WAAW,CAC1B,MAA4C,EAC5C,OAA2B;IAE3B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,YAAY,GAAG,IAAI,CAAC;IAExB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAC9C,IAAI,QAAQ,IAAI,CAAC,YAAY;YAAE,OAAO;QACtC,YAAY,GAAG,KAAK,CAAC;QACrB,cAAc,CAAC,GAAG,EAAE;YACnB,IAAI,QAAQ;gBAAE,OAAO;YACrB,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtB,OAAO,GAAG,EAAE;QACX,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC;YACJ,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACR,iFAAiF;QAClF,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmachines/play-signals",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
5
  "description": "TC39 Signals polyfill for XMachines - Fine-grained reactive state primitives",
6
6
  "keywords": [
@@ -41,6 +41,7 @@
41
41
  "build": "vite build && tsc --build",
42
42
  "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__ node_modules/.svelte2tsx-* node_modules/.vite*",
43
43
  "test": "vitest",
44
+ "test:coverage": "vitest run --coverage",
44
45
  "lint": "oxlint .",
45
46
  "lint:fix": "oxlint --fix .",
46
47
  "format": "oxfmt .",