@rlabs-inc/signals 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # @rlabs-inc/signals
2
2
 
3
- **Ultra-lightweight fine-grained reactivity for TypeScript**
3
+ **Production-grade fine-grained reactivity for TypeScript.**
4
4
 
5
- A standalone reactive primitives library inspired by Svelte 5 runes, Solid.js, and Vue reactivity. Zero dependencies. ~800 lines of pure TypeScript.
5
+ A complete standalone mirror of Svelte 5's reactivity system. No compiler needed, no DOM, works anywhere - Bun, Node, Deno, or browser.
6
6
 
7
7
  ## Features
8
8
 
9
- - **Fine-grained reactivity** - Only effects that read a signal re-run when it changes
10
- - **Deep reactivity** - Objects and arrays are automatically deeply reactive
11
- - **Lazy deriveds** - Computed values only recompute when read
12
- - **Batching** - Group updates to prevent multiple re-runs
13
- - **Reactive collections** - ReactiveMap, ReactiveSet, and reactiveArray
14
- - **Zero dependencies** - Pure TypeScript, works everywhere
15
- - **Tiny** - ~5KB minified
9
+ - **True Fine-Grained Reactivity** - Changes to deeply nested properties only trigger effects that read that exact path
10
+ - **Per-Property Tracking** - Proxy-based deep reactivity with lazy signal creation per property
11
+ - **Three-State Dirty Tracking** - Efficient CLEAN/MAYBE_DIRTY/DIRTY propagation
12
+ - **Automatic Cleanup** - Effects clean up when disposed, no memory leaks
13
+ - **Batching** - Group updates to prevent redundant effect runs
14
+ - **Self-Referencing Effects** - Effects can write to their own dependencies
15
+ - **Infinite Loop Protection** - Throws after 1000 iterations to catch bugs
16
+ - **Reactive Collections** - ReactiveMap, ReactiveSet, ReactiveDate
17
+ - **TypeScript Native** - Full type safety with generics
16
18
 
17
19
  ## Installation
18
20
 
@@ -25,88 +27,84 @@ npm install @rlabs-inc/signals
25
27
  ## Quick Start
26
28
 
27
29
  ```typescript
28
- import { signal, effect, derived } from '@rlabs-inc/signals'
30
+ import { signal, derived, effect, flushSync } from '@rlabs-inc/signals'
29
31
 
30
- // Simple signal
32
+ // Create a signal
31
33
  const count = signal(0)
32
34
 
33
- // Effect runs when dependencies change
35
+ // Create a derived value
36
+ const doubled = derived(() => count.value * 2)
37
+
38
+ // Create an effect
34
39
  effect(() => {
35
- console.log('Count:', count.value)
40
+ console.log(`Count: ${count.value}, Doubled: ${doubled.value}`)
36
41
  })
37
- // Logs: "Count: 0"
38
42
 
39
- count.value = 1
40
- // Logs: "Count: 1"
43
+ // Flush to run effects synchronously
44
+ flushSync() // Logs: "Count: 0, Doubled: 0"
41
45
 
42
- // Derived values
43
- const doubled = derived(() => count.value * 2)
44
- console.log(doubled.value) // 2
46
+ // Update the signal
47
+ count.value = 5
48
+ flushSync() // Logs: "Count: 5, Doubled: 10"
49
+ ```
45
50
 
46
- // Deep reactivity - signal() is deeply reactive for objects/arrays!
47
- const user = signal({
48
- name: 'John',
49
- address: {
50
- city: 'NYC'
51
- }
52
- })
51
+ ## API Reference
53
52
 
54
- effect(() => {
55
- console.log('City:', user.value.address.city)
56
- })
57
- // Logs: "City: NYC"
53
+ ### Signals
58
54
 
59
- user.value.address.city = 'LA'
60
- // Logs: "City: LA" - mutations at any depth trigger effects!
55
+ #### `signal<T>(initialValue: T, options?): WritableSignal<T>`
61
56
 
62
- // Even deeply nested arrays work
63
- const data = signal({ items: [[1, 2], [3, 4]] })
64
- data.value.items[0][1] = 99 // Triggers effects!
57
+ Create a reactive value with `.value` getter/setter.
58
+
59
+ ```typescript
60
+ const name = signal('John')
61
+ console.log(name.value) // 'John'
62
+ name.value = 'Jane' // Triggers effects
65
63
  ```
66
64
 
67
- ## API Reference
65
+ **Options:**
66
+ - `equals?: (a: T, b: T) => boolean` - Custom equality function
68
67
 
69
- ### signal(initial, options?)
68
+ #### `state<T extends object>(initialValue: T): T`
70
69
 
71
- Create a reactive signal that holds a value. **For objects and arrays, signals are deeply reactive** - mutations at any depth trigger effects.
70
+ Create a deeply reactive object. No `.value` needed - access properties directly.
72
71
 
73
72
  ```typescript
74
- // Primitives
75
- const count = signal(0)
76
- console.log(count.value) // 0
77
- count.value = 5
78
- console.log(count.value) // 5
73
+ const user = state({ name: 'John', address: { city: 'NYC' } })
74
+ user.name = 'Jane' // Reactive
75
+ user.address.city = 'LA' // Also reactive, deeply
76
+ ```
79
77
 
80
- // Objects - deeply reactive!
81
- const user = signal({ name: 'John', address: { city: 'NYC' } })
82
- user.value.address.city = 'LA' // Triggers effects!
78
+ ### Derived Values
83
79
 
84
- // Arrays - deeply reactive!
85
- const matrix = signal([[1, 2], [3, 4]])
86
- matrix.value[0][1] = 99 // Triggers effects!
87
- matrix.value.push([5, 6]) // Triggers effects!
80
+ #### `derived<T>(fn: () => T): DerivedSignal<T>`
88
81
 
89
- // Arbitrarily deep nesting works
90
- const complex = signal({
91
- level1: [{ level2: [[{ level3: 'value' }]] }]
92
- })
93
- complex.value.level1[0].level2[0][0].level3 = 'mutated' // Triggers!
82
+ Create a computed value that automatically updates when dependencies change.
94
83
 
95
- // With custom equality (for full replacement comparison)
96
- const obj = signal({ x: 1 }, {
97
- equals: (a, b) => a.x === b.x
98
- })
84
+ ```typescript
85
+ const firstName = signal('John')
86
+ const lastName = signal('Doe')
87
+
88
+ const fullName = derived(() => `${firstName.value} ${lastName.value}`)
89
+ console.log(fullName.value) // 'John Doe'
99
90
  ```
100
91
 
101
- ### effect(fn)
92
+ Deriveds are:
93
+ - **Lazy** - Only computed when read
94
+ - **Cached** - Value is memoized until dependencies change
95
+ - **Pure** - Cannot write to signals inside (throws error)
96
+
97
+ ### Effects
102
98
 
103
- Create a reactive effect that re-runs when dependencies change.
99
+ #### `effect(fn: () => void | CleanupFn): DisposeFn`
100
+
101
+ Create a side effect that re-runs when dependencies change.
104
102
 
105
103
  ```typescript
106
- const name = signal('John')
104
+ const count = signal(0)
107
105
 
108
106
  const dispose = effect(() => {
109
- console.log('Hello,', name.value)
107
+ console.log('Count is:', count.value)
110
108
 
111
109
  // Optional cleanup function
112
110
  return () => {
@@ -114,224 +112,266 @@ const dispose = effect(() => {
114
112
  }
115
113
  })
116
114
 
117
- name.value = 'Jane' // Effect re-runs
118
-
119
- dispose() // Stop the effect
115
+ // Stop the effect
116
+ dispose()
120
117
  ```
121
118
 
122
- ### derived(fn, options?)
119
+ #### `effect.root(fn: () => T): DisposeFn`
123
120
 
124
- Create a computed/derived value that updates automatically.
121
+ Create an effect scope that can contain nested effects.
125
122
 
126
123
  ```typescript
127
- const count = signal(5)
128
- const doubled = derived(() => count.value * 2)
129
-
130
- console.log(doubled.value) // 10
131
-
132
- count.value = 10
133
- console.log(doubled.value) // 20
124
+ const dispose = effect.root(() => {
125
+ effect(() => { /* ... */ })
126
+ effect(() => { /* ... */ })
127
+ })
134
128
 
135
- // Alias: derived.by() (Svelte compatibility)
136
- const tripled = derived.by(() => count.value * 3)
129
+ // Disposes all nested effects
130
+ dispose()
137
131
  ```
138
132
 
139
- ### state(initial)
133
+ #### `effect.pre(fn: () => void): DisposeFn`
140
134
 
141
- Convenience function for deeply reactive objects **without `.value`**. Use when you want direct property access instead of going through `.value`.
135
+ Create an effect that runs synchronously (like `$effect.pre` in Svelte).
142
136
 
143
137
  ```typescript
144
- // state() - direct access, no .value needed
145
- const app = state({
146
- user: {
147
- name: 'John',
148
- preferences: {
149
- theme: 'dark'
150
- }
151
- },
152
- items: [1, 2, 3]
138
+ effect.pre(() => {
139
+ // Runs immediately, no flushSync needed
153
140
  })
154
-
155
- effect(() => {
156
- console.log(app.user.preferences.theme) // No .value!
157
- })
158
-
159
- app.user.preferences.theme = 'light' // Triggers effect
160
- app.items.push(4) // Arrays are reactive too
161
-
162
- // Equivalent using signal():
163
- const app2 = signal({ ... })
164
- app2.value.user.preferences.theme = 'light' // Same, but with .value
165
141
  ```
166
142
 
167
- **When to use which:**
168
- - `signal()` - Unified API, always use `.value` (recommended)
169
- - `state()` - When you want direct property access without `.value`
143
+ ### Batching & Scheduling
170
144
 
171
- ### batch(fn)
145
+ #### `batch(fn: () => T): T`
172
146
 
173
- Batch multiple updates into a single reaction cycle.
147
+ Batch multiple signal updates into a single effect run.
174
148
 
175
149
  ```typescript
176
150
  const a = signal(1)
177
151
  const b = signal(2)
178
152
 
179
- effect(() => {
180
- console.log('Sum:', a.value + b.value)
181
- })
182
- // Logs: "Sum: 3"
153
+ effect(() => console.log(a.value + b.value))
183
154
 
184
155
  batch(() => {
185
156
  a.value = 10
186
157
  b.value = 20
187
158
  })
188
- // Logs: "Sum: 30" (only once, not twice)
159
+ // Effect runs once with final values, not twice
189
160
  ```
190
161
 
191
- ### untrack(fn)
162
+ #### `flushSync<T>(fn?: () => T): T | undefined`
192
163
 
193
- Read signals without creating dependencies.
164
+ Synchronously flush all pending effects.
194
165
 
195
166
  ```typescript
196
- const a = signal(1)
197
- const b = signal(2)
167
+ count.value = 5
168
+ flushSync() // Effects run NOW, not on next microtask
169
+ ```
170
+
171
+ #### `tick(): Promise<void>`
172
+
173
+ Wait for the next update cycle.
174
+
175
+ ```typescript
176
+ count.value = 5
177
+ await tick() // Effects have run
178
+ ```
198
179
 
180
+ ### Utilities
181
+
182
+ #### `untrack<T>(fn: () => T): T`
183
+
184
+ Read signals without creating dependencies.
185
+
186
+ ```typescript
199
187
  effect(() => {
200
- console.log('a:', a.value) // Creates dependency
201
- untrack(() => {
202
- console.log('b:', b.value) // Does NOT create dependency
203
- })
188
+ const a = count.value // Creates dependency
189
+ const b = untrack(() => other.value) // No dependency
204
190
  })
205
-
206
- b.value = 100 // Effect does NOT re-run
207
- a.value = 100 // Effect re-runs
208
191
  ```
209
192
 
210
- ### watch(source, callback, options?)
193
+ #### `peek<T>(signal: Source<T>): T`
211
194
 
212
- Watch a signal and call callback when it changes.
195
+ Read a signal's value without tracking (low-level).
196
+
197
+ ### Deep Reactivity
198
+
199
+ #### `proxy<T extends object>(value: T): T`
200
+
201
+ Create a deeply reactive proxy (used internally by `state()`).
213
202
 
214
203
  ```typescript
215
- const count = signal(0)
204
+ const obj = proxy({ a: { b: { c: 1 } } })
205
+ obj.a.b.c = 2 // Only triggers effects reading a.b.c
206
+ ```
216
207
 
217
- const dispose = watch(
218
- () => count.value,
219
- (newValue, oldValue) => {
220
- console.log(`Changed from ${oldValue} to ${newValue}`)
221
- }
222
- )
208
+ #### `toRaw<T>(value: T): T`
223
209
 
224
- count.value = 1 // Logs: "Changed from 0 to 1"
210
+ Get the original object from a proxy.
225
211
 
226
- // With immediate option
227
- watch(
228
- () => count.value,
229
- (value) => console.log('Value:', value),
230
- { immediate: true }
231
- )
232
- // Logs immediately: "Value: 1"
212
+ ```typescript
213
+ const raw = toRaw(user) // Original non-reactive object
233
214
  ```
234
215
 
235
- ### ReactiveMap
216
+ #### `isReactive(value: unknown): boolean`
217
+
218
+ Check if a value is a reactive proxy.
236
219
 
237
- A reactive Map that triggers updates on modifications.
220
+ ### Reactive Collections
221
+
222
+ #### `ReactiveMap<K, V>`
223
+
224
+ A Map with per-key reactivity.
238
225
 
239
226
  ```typescript
240
- const map = new ReactiveMap<string, number>()
227
+ const users = new ReactiveMap<string, User>()
241
228
 
242
229
  effect(() => {
243
- console.log('Value:', map.get('key'))
230
+ console.log(users.get('john')) // Only re-runs when 'john' changes
244
231
  })
245
232
 
246
- map.set('key', 42) // Triggers effect
233
+ users.set('jane', { name: 'Jane' }) // Doesn't trigger above effect
247
234
  ```
248
235
 
249
- ### ReactiveSet
236
+ #### `ReactiveSet<T>`
250
237
 
251
- A reactive Set that triggers updates on modifications.
238
+ A Set with per-item reactivity.
252
239
 
253
240
  ```typescript
254
- const set = new ReactiveSet<string>()
241
+ const tags = new ReactiveSet<string>()
255
242
 
256
243
  effect(() => {
257
- console.log('Has item:', set.has('item'))
244
+ console.log(tags.has('important')) // Only re-runs when 'important' changes
258
245
  })
259
-
260
- set.add('item') // Triggers effect
261
246
  ```
262
247
 
263
- ### reactiveArray(initial?)
248
+ #### `ReactiveDate`
264
249
 
265
- Create a reactive array with fine-grained reactivity.
250
+ A Date with reactive getters/setters.
266
251
 
267
252
  ```typescript
268
- const items = reactiveArray([1, 2, 3])
253
+ const date = new ReactiveDate()
269
254
 
270
255
  effect(() => {
271
- console.log('First:', items[0])
272
- console.log('Length:', items.length)
256
+ console.log(date.getHours()) // Re-runs when time changes
273
257
  })
274
258
 
275
- items[0] = 10 // Triggers effect
276
- items.push(4) // Triggers effect
259
+ date.setHours(12) // Triggers effect
277
260
  ```
278
261
 
279
- ### Utilities
262
+ ## Advanced Usage
263
+
264
+ ### Self-Referencing Effects
265
+
266
+ Effects can write to signals they depend on:
280
267
 
281
268
  ```typescript
282
- // Create read-only view
283
269
  const count = signal(0)
284
- const ro = readonly(count)
285
- // ro.value = 5 // TypeScript error
286
270
 
287
- // Read without tracking (alias for untrack)
288
- const value = peek(() => count.value)
271
+ effect(() => {
272
+ if (count.value < 10) {
273
+ count.value++ // Will re-run until count reaches 10
274
+ }
275
+ })
276
+ ```
289
277
 
290
- // Check if value is reactive
291
- isReactive(someObject)
278
+ **Note:** Unguarded self-references throw after 1000 iterations.
292
279
 
293
- // Get raw object from reactive proxy
294
- const raw = toRaw(reactiveObject)
280
+ ### Custom Equality
295
281
 
296
- // Create effect scope
297
- const scope = effectScope()
298
- scope.run(() => {
299
- effect(() => { /* ... */ })
300
- effect(() => { /* ... */ })
282
+ ```typescript
283
+ import { signal, shallowEquals } from '@rlabs-inc/signals'
284
+
285
+ const obj = signal({ a: 1 }, { equals: shallowEquals })
286
+ obj.value = { a: 1 } // Won't trigger - shallowly equal
287
+ ```
288
+
289
+ Built-in equality functions:
290
+ - `equals` - Default, uses `Object.is`
291
+ - `safeEquals` - Handles NaN correctly
292
+ - `shallowEquals` - Shallow object comparison
293
+ - `neverEquals` - Always triggers (always false)
294
+ - `alwaysEquals` - Never triggers (always true)
295
+
296
+ ### Low-Level API
297
+
298
+ For advanced use cases, you can access internal primitives:
299
+
300
+ ```typescript
301
+ import { source, get, set } from '@rlabs-inc/signals'
302
+
303
+ // Create a raw source (no .value wrapper)
304
+ const src = source(0)
305
+
306
+ // Read with tracking
307
+ const value = get(src)
308
+
309
+ // Write with notification
310
+ set(src, 10)
311
+ ```
312
+
313
+ ## Error Handling
314
+
315
+ ### "Cannot write to signals inside a derived"
316
+
317
+ Deriveds must be pure computations:
318
+
319
+ ```typescript
320
+ // BAD - will throw
321
+ const bad = derived(() => {
322
+ otherSignal.value = 10 // Throws!
323
+ return count.value
324
+ })
325
+
326
+ // GOOD - use effects for side effects
327
+ effect(() => {
328
+ if (count.value > 0) {
329
+ otherSignal.value = count.value * 2
330
+ }
331
+ })
332
+ ```
333
+
334
+ ### "Maximum update depth exceeded"
335
+
336
+ Your effect is infinitely re-triggering itself:
337
+
338
+ ```typescript
339
+ // BAD - infinite loop
340
+ effect(() => {
341
+ count.value = count.value + 1 // Always triggers itself
342
+ })
343
+
344
+ // GOOD - add a guard
345
+ effect(() => {
346
+ if (count.value < 100) {
347
+ count.value++
348
+ }
301
349
  })
302
- scope.stop() // Disposes all effects
303
350
  ```
304
351
 
352
+ ## Performance
353
+
354
+ This library is designed for performance:
355
+
356
+ - **Lazy evaluation** - Deriveds only compute when read
357
+ - **Version-based deduplication** - No duplicate dependency tracking
358
+ - **Linked list effect tree** - O(1) effect insertion/removal
359
+ - **Microtask batching** - Updates coalesce automatically
360
+ - **Per-property signals** - Fine-grained updates at any depth
361
+
305
362
  ## Comparison with Svelte 5
306
363
 
307
- | Svelte 5 | @rlabs-inc/signals |
308
- |----------|-------------------|
309
- | `$state(value)` | `signal(value)` - deeply reactive for objects/arrays |
310
- | `$state(obj)` direct access | `state(obj)` - no `.value` needed |
311
- | `$derived(expr)` | `derived(() => expr)` |
312
- | `$derived.by(fn)` | `derived.by(fn)` or `derived(fn)` |
313
- | `$effect(fn)` | `effect(fn)` |
314
- | `SvelteMap` | `ReactiveMap` |
315
- | `SvelteSet` | `ReactiveSet` |
316
-
317
- **Key differences:**
318
- - No compiler needed - works with plain TypeScript
319
- - Use `.value` to read/write signals (like Vue/Solid)
320
- - No Happy DOM or browser environment required
321
- - `signal()` is deeply reactive out of the box - arrays of arrays of objects just work
322
-
323
- ## Why?
324
-
325
- We built this because:
326
- 1. We love Svelte 5's reactivity model
327
- 2. We wanted to use it outside Svelte components
328
- 3. We didn't want the overhead of Happy DOM for server-side usage
329
- 4. We needed a lightweight solution for libraries like [FatherStateDB](https://github.com/rlabs-inc/fatherstatedb)
364
+ | Feature | Svelte 5 | @rlabs-inc/signals |
365
+ |---------|----------|-------------------|
366
+ | Compiler required | Yes | No |
367
+ | DOM integration | Yes | No |
368
+ | Fine-grained reactivity | Yes | Yes |
369
+ | Deep proxy reactivity | Yes | Yes |
370
+ | Batching | Yes | Yes |
371
+ | Effect cleanup | Yes | Yes |
372
+ | TypeScript | Yes | Yes |
373
+ | Runs in Node/Bun | Needs adapter | Native |
330
374
 
331
375
  ## License
332
376
 
333
377
  MIT
334
-
335
- ---
336
-
337
- Built with ❤️ by RLabs Inc.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * A reactive Date
3
+ *
4
+ * All getters are reactive - they track changes to the underlying time.
5
+ * All setters trigger updates.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const date = new ReactiveDate()
10
+ *
11
+ * effect(() => {
12
+ * console.log('Hours:', date.getHours())
13
+ * })
14
+ *
15
+ * date.setHours(12) // Triggers effect
16
+ * ```
17
+ */
18
+ export declare class ReactiveDate extends Date {
19
+ #private;
20
+ constructor();
21
+ constructor(value: number | string | Date);
22
+ constructor(year: number, monthIndex: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number);
23
+ getTime(): number;
24
+ getFullYear(): number;
25
+ getMonth(): number;
26
+ getDate(): number;
27
+ getDay(): number;
28
+ getHours(): number;
29
+ getMinutes(): number;
30
+ getSeconds(): number;
31
+ getMilliseconds(): number;
32
+ getUTCFullYear(): number;
33
+ getUTCMonth(): number;
34
+ getUTCDate(): number;
35
+ getUTCDay(): number;
36
+ getUTCHours(): number;
37
+ getUTCMinutes(): number;
38
+ getUTCSeconds(): number;
39
+ getUTCMilliseconds(): number;
40
+ getTimezoneOffset(): number;
41
+ setTime(time: number): number;
42
+ setFullYear(year: number, month?: number, date?: number): number;
43
+ setMonth(month: number, date?: number): number;
44
+ setDate(date: number): number;
45
+ setHours(hours: number, min?: number, sec?: number, ms?: number): number;
46
+ setMinutes(min: number, sec?: number, ms?: number): number;
47
+ setSeconds(sec: number, ms?: number): number;
48
+ setMilliseconds(ms: number): number;
49
+ setUTCFullYear(year: number, month?: number, date?: number): number;
50
+ setUTCMonth(month: number, date?: number): number;
51
+ setUTCDate(date: number): number;
52
+ setUTCHours(hours: number, min?: number, sec?: number, ms?: number): number;
53
+ setUTCMinutes(min: number, sec?: number, ms?: number): number;
54
+ setUTCSeconds(sec: number, ms?: number): number;
55
+ setUTCMilliseconds(ms: number): number;
56
+ toString(): string;
57
+ toDateString(): string;
58
+ toTimeString(): string;
59
+ toISOString(): string;
60
+ toUTCString(): string;
61
+ toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
62
+ toLocaleDateString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
63
+ toLocaleTimeString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
64
+ toJSON(): string;
65
+ valueOf(): number;
66
+ }
67
+ //# sourceMappingURL=date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/collections/date.ts"],"names":[],"mappings":"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"}