@zeix/cause-effect 0.16.0 → 0.17.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 (62) hide show
  1. package/.ai-context.md +71 -21
  2. package/.cursorrules +3 -2
  3. package/.github/copilot-instructions.md +59 -13
  4. package/CLAUDE.md +170 -24
  5. package/LICENSE +1 -1
  6. package/README.md +156 -52
  7. package/archive/benchmark.ts +688 -0
  8. package/archive/collection.ts +312 -0
  9. package/{src → archive}/computed.ts +33 -34
  10. package/archive/list.ts +551 -0
  11. package/archive/memo.ts +138 -0
  12. package/archive/state.ts +89 -0
  13. package/archive/store.ts +368 -0
  14. package/archive/task.ts +194 -0
  15. package/eslint.config.js +1 -0
  16. package/index.dev.js +902 -501
  17. package/index.js +1 -1
  18. package/index.ts +42 -22
  19. package/package.json +1 -1
  20. package/src/classes/collection.ts +272 -0
  21. package/src/classes/composite.ts +176 -0
  22. package/src/classes/computed.ts +333 -0
  23. package/src/classes/list.ts +304 -0
  24. package/src/classes/state.ts +98 -0
  25. package/src/classes/store.ts +210 -0
  26. package/src/diff.ts +28 -52
  27. package/src/effect.ts +9 -9
  28. package/src/errors.ts +50 -25
  29. package/src/signal.ts +58 -41
  30. package/src/system.ts +79 -42
  31. package/src/util.ts +16 -34
  32. package/test/batch.test.ts +15 -17
  33. package/test/benchmark.test.ts +4 -4
  34. package/test/collection.test.ts +796 -0
  35. package/test/computed.test.ts +138 -130
  36. package/test/diff.test.ts +2 -2
  37. package/test/effect.test.ts +36 -35
  38. package/test/list.test.ts +754 -0
  39. package/test/match.test.ts +25 -25
  40. package/test/resolve.test.ts +17 -19
  41. package/test/signal.test.ts +72 -121
  42. package/test/state.test.ts +44 -44
  43. package/test/store.test.ts +344 -1663
  44. package/types/index.d.ts +11 -9
  45. package/types/src/classes/collection.d.ts +32 -0
  46. package/types/src/classes/composite.d.ts +15 -0
  47. package/types/src/classes/computed.d.ts +97 -0
  48. package/types/src/classes/list.d.ts +41 -0
  49. package/types/src/classes/state.d.ts +52 -0
  50. package/types/src/classes/store.d.ts +51 -0
  51. package/types/src/diff.d.ts +8 -12
  52. package/types/src/errors.d.ts +12 -11
  53. package/types/src/signal.d.ts +27 -14
  54. package/types/src/system.d.ts +41 -20
  55. package/types/src/util.d.ts +6 -3
  56. package/src/state.ts +0 -98
  57. package/src/store.ts +0 -525
  58. package/types/src/collection.d.ts +0 -26
  59. package/types/src/computed.d.ts +0 -33
  60. package/types/src/scheduler.d.ts +0 -55
  61. package/types/src/state.d.ts +0 -24
  62. package/types/src/store.d.ts +0 -66
package/src/store.ts DELETED
@@ -1,525 +0,0 @@
1
- import { isComputed } from './computed'
2
- import {
3
- type ArrayToRecord,
4
- diff,
5
- type UnknownArray,
6
- type UnknownRecord,
7
- type UnknownRecordOrArray,
8
- } from './diff'
9
-
10
- import {
11
- InvalidSignalValueError,
12
- NullishSignalValueError,
13
- StoreKeyExistsError,
14
- StoreKeyRangeError,
15
- StoreKeyReadonlyError,
16
- } from './errors'
17
- import { isMutableSignal, type Signal } from './signal'
18
- import { createState, isState, type State } from './state'
19
- import {
20
- batch,
21
- type Cleanup,
22
- createWatcher,
23
- notify,
24
- observe,
25
- subscribe,
26
- type Watcher,
27
- } from './system'
28
- import {
29
- isFunction,
30
- isObjectOfType,
31
- isRecord,
32
- isSymbol,
33
- recordToArray,
34
- UNSET,
35
- valueString,
36
- } from './util'
37
-
38
- /* === Types === */
39
-
40
- type ArrayItem<T> = T extends readonly (infer U extends {})[] ? U : never
41
-
42
- type StoreChanges<T> = {
43
- add: Partial<T>
44
- change: Partial<T>
45
- remove: Partial<T>
46
- sort: string[]
47
- }
48
-
49
- type StoreListeners<T> = {
50
- [K in keyof StoreChanges<T>]: Set<(change: StoreChanges<T>[K]) => void>
51
- }
52
-
53
- interface BaseStore {
54
- readonly [Symbol.toStringTag]: 'Store'
55
- readonly size: State<number>
56
- }
57
-
58
- type RecordStore<T extends UnknownRecord> = BaseStore & {
59
- [K in keyof T]: T[K] extends readonly unknown[] | Record<string, unknown>
60
- ? Store<T[K]>
61
- : State<T[K]>
62
- } & {
63
- [Symbol.iterator](): IterableIterator<
64
- [
65
- Extract<keyof T, string>,
66
- T[Extract<keyof T, string>] extends
67
- | readonly unknown[]
68
- | Record<string, unknown>
69
- ? Store<T[Extract<keyof T, string>]>
70
- : State<T[Extract<keyof T, string>]>,
71
- ]
72
- >
73
- add<K extends Extract<keyof T, string>>(key: K, value: T[K]): void
74
- get(): T
75
- set(value: T): void
76
- update(fn: (value: T) => T): void
77
- sort<U = T[Extract<keyof T, string>]>(
78
- compareFn?: (a: U, b: U) => number,
79
- ): void
80
- on<K extends keyof StoreChanges<T>>(
81
- type: K,
82
- listener: (change: StoreChanges<T>[K]) => void,
83
- ): Cleanup
84
- remove<K extends Extract<keyof T, string>>(key: K): void
85
- }
86
-
87
- type ArrayStore<T extends UnknownArray> = BaseStore & {
88
- [Symbol.iterator](): IterableIterator<
89
- ArrayItem<T> extends readonly unknown[] | Record<string, unknown>
90
- ? Store<ArrayItem<T>>
91
- : State<ArrayItem<T>>
92
- >
93
- readonly [Symbol.isConcatSpreadable]: boolean
94
- [n: number]: ArrayItem<T> extends
95
- | readonly unknown[]
96
- | Record<string, unknown>
97
- ? Store<ArrayItem<T>>
98
- : State<ArrayItem<T>>
99
- add(value: ArrayItem<T>): void
100
- get(): T
101
- set(value: T): void
102
- update(fn: (value: T) => T): void
103
- sort<U = ArrayItem<T>>(compareFn?: (a: U, b: U) => number): void
104
- on<K extends keyof StoreChanges<T>>(
105
- type: K,
106
- listener: (change: StoreChanges<T>[K]) => void,
107
- ): Cleanup
108
- remove(index: number): void
109
- readonly length: number
110
- }
111
-
112
- type Store<T extends UnknownRecord | UnknownArray> = T extends UnknownRecord
113
- ? RecordStore<T>
114
- : T extends UnknownArray
115
- ? ArrayStore<T>
116
- : never
117
-
118
- /* === Constants === */
119
-
120
- const TYPE_STORE = 'Store'
121
-
122
- /* === Functions === */
123
-
124
- /**
125
- * Create a new store with deeply nested reactive properties
126
- *
127
- * Supports both objects and arrays as initial values. Arrays are converted
128
- * to records internally for storage but maintain their array type through
129
- * the .get() method, which automatically converts objects with consecutive
130
- * numeric keys back to arrays.
131
- *
132
- * @since 0.15.0
133
- * @param {T} initialValue - initial object or array value of the store
134
- * @returns {Store<T>} - new store with reactive properties that preserves the original type T
135
- */
136
- const createStore = <T extends UnknownRecord | UnknownArray>(
137
- initialValue: T,
138
- ): Store<T> => {
139
- if (initialValue == null) throw new NullishSignalValueError('store')
140
-
141
- const watchers = new Set<Watcher>()
142
- const listeners: StoreListeners<T> = {
143
- add: new Set<(change: Partial<T>) => void>(),
144
- change: new Set<(change: Partial<T>) => void>(),
145
- remove: new Set<(change: Partial<T>) => void>(),
146
- sort: new Set<(change: string[]) => void>(),
147
- }
148
- const signals = new Map<string, Signal<T[Extract<keyof T, string>] & {}>>()
149
- const signalWatchers = new Map<string, Watcher>()
150
-
151
- // Determine if this is an array-like store at creation time
152
- const isArrayLike = Array.isArray(initialValue)
153
-
154
- // Internal state
155
- const size = createState(0)
156
-
157
- // Get current record
158
- const current = () => {
159
- const record: Record<string, unknown> = {}
160
- for (const [key, signal] of signals) {
161
- record[key] = signal.get()
162
- }
163
- return record
164
- }
165
-
166
- // Emit change notifications
167
- const emit = <K extends keyof StoreChanges<T>>(
168
- key: K,
169
- changes: StoreChanges<T>[K],
170
- ) => {
171
- Object.freeze(changes)
172
- for (const listener of listeners[key]) {
173
- listener(changes)
174
- }
175
- }
176
-
177
- // Get sorted indexes
178
- const getSortedIndexes = () =>
179
- Array.from(signals.keys())
180
- .map(k => Number(k))
181
- .filter(n => Number.isInteger(n))
182
- .sort((a, b) => a - b)
183
-
184
- // Validate input
185
- const isValidValue = <T>(
186
- key: string,
187
- value: T,
188
- ): value is NonNullable<T> => {
189
- if (value == null)
190
- throw new NullishSignalValueError(`store for key "${key}"`)
191
- if (value === UNSET) return true
192
- if (isSymbol(value) || isFunction(value) || isComputed(value))
193
- throw new InvalidSignalValueError(
194
- `store for key "${key}"`,
195
- valueString(value),
196
- )
197
- return true
198
- }
199
-
200
- // Add nested signal and effect
201
- const addProperty = <K extends Extract<keyof T, string>>(
202
- key: K,
203
- value: T[K] | ArrayItem<T>,
204
- single = false,
205
- ): boolean => {
206
- if (!isValidValue(key, value)) return false
207
- const signal =
208
- isState(value) || isStore(value)
209
- ? value
210
- : isRecord(value) || Array.isArray(value)
211
- ? createStore(value)
212
- : createState(value)
213
- // @ts-expect-error non-matching signal types
214
- signals.set(key, signal)
215
- const watcher = createWatcher(() =>
216
- observe(() => {
217
- emit('change', {
218
- [key]: signal.get(),
219
- } as unknown as Partial<T>)
220
- }, watcher),
221
- )
222
- watcher()
223
- signalWatchers.set(key, watcher)
224
-
225
- if (single) {
226
- size.set(signals.size)
227
- notify(watchers)
228
- emit('add', {
229
- [key]: value,
230
- } as unknown as Partial<T>)
231
- }
232
- return true
233
- }
234
-
235
- // Remove nested signal and effect
236
- const removeProperty = <K extends Extract<keyof T, string>>(
237
- key: K,
238
- single = false,
239
- ) => {
240
- const ok = signals.delete(key)
241
- if (ok) {
242
- const watcher = signalWatchers.get(key)
243
- if (watcher) watcher.cleanup()
244
- signalWatchers.delete(key)
245
- }
246
-
247
- if (single) {
248
- size.set(signals.size)
249
- notify(watchers)
250
- emit('remove', {
251
- [key]: UNSET,
252
- } as unknown as Partial<T>)
253
- }
254
- return ok
255
- }
256
-
257
- // Reconcile data and dispatch events
258
- const reconcile = (
259
- oldValue: T,
260
- newValue: T,
261
- initialRun?: boolean,
262
- ): boolean => {
263
- const changes = diff(
264
- oldValue as T extends UnknownArray ? ArrayToRecord<T> : T,
265
- newValue as T extends UnknownArray ? ArrayToRecord<T> : T,
266
- )
267
-
268
- batch(() => {
269
- // Additions
270
- if (Object.keys(changes.add).length) {
271
- for (const key in changes.add) {
272
- const value = changes.add[key] ?? UNSET
273
- addProperty(
274
- key as Extract<keyof T, string>,
275
- value as T[Extract<keyof T, string>] & {},
276
- )
277
- }
278
-
279
- // Queue initial additions event to allow listeners to be added first
280
- if (initialRun) {
281
- setTimeout(() => {
282
- emit('add', changes.add as Partial<T>)
283
- }, 0)
284
- } else {
285
- emit('add', changes.add as Partial<T>)
286
- }
287
- }
288
-
289
- // Changes
290
- if (Object.keys(changes.change).length) {
291
- for (const key in changes.change) {
292
- const value = changes.change[key]
293
- if (!isValidValue(key, value)) continue
294
- const signal = signals.get(key as Extract<keyof T, string>)
295
- if (isMutableSignal(signal))
296
- signal.set(value as T[Extract<keyof T, string>] & {})
297
- else
298
- throw new StoreKeyReadonlyError(key, valueString(value))
299
- }
300
- emit('change', changes.change as Partial<T>)
301
- }
302
-
303
- // Removals
304
- if (Object.keys(changes.remove).length) {
305
- for (const key in changes.remove)
306
- removeProperty(key as Extract<keyof T, string>)
307
- emit('remove', changes.remove as Partial<T>)
308
- }
309
-
310
- size.set(signals.size)
311
- })
312
-
313
- return changes.changed
314
- }
315
-
316
- // Initialize data - convert arrays to records for internal storage
317
- reconcile({} as T, initialValue, true)
318
-
319
- // Methods and Properties
320
- const store: Record<string, unknown> = {
321
- add: isArrayLike
322
- ? (v: ArrayItem<T>): void => {
323
- const nextIndex = signals.size
324
- const key = String(nextIndex) as Extract<keyof T, string>
325
- addProperty(key, v, true)
326
- }
327
- : <K extends Extract<keyof T, string>>(k: K, v: T[K]): void => {
328
- if (!signals.has(k)) addProperty(k, v, true)
329
- else throw new StoreKeyExistsError(k, valueString(v))
330
- },
331
- get: (): T => {
332
- subscribe(watchers)
333
- return recordToArray(current()) as T
334
- },
335
- remove: isArrayLike
336
- ? (index: number): void => {
337
- const currentArray = recordToArray(current()) as T
338
- const currentLength = signals.size
339
- if (
340
- !Array.isArray(currentArray) ||
341
- index <= -currentLength ||
342
- index >= currentLength
343
- )
344
- throw new StoreKeyRangeError(index)
345
- const newArray = [...currentArray]
346
- newArray.splice(index, 1)
347
-
348
- if (reconcile(currentArray, newArray as unknown as T))
349
- notify(watchers)
350
- }
351
- : <K extends Extract<keyof T, string>>(k: K): void => {
352
- if (signals.has(k)) removeProperty(k, true)
353
- },
354
- set: (v: T): void => {
355
- if (reconcile(current() as T, v)) {
356
- notify(watchers)
357
- if (UNSET === v) watchers.clear()
358
- }
359
- },
360
- update: (fn: (v: T) => T): void => {
361
- const oldValue = current()
362
- const newValue = fn(recordToArray(oldValue) as T)
363
- if (reconcile(oldValue as T, newValue)) {
364
- notify(watchers)
365
- if (UNSET === newValue) watchers.clear()
366
- }
367
- },
368
- sort: (
369
- compareFn?: <
370
- U = T extends UnknownArray
371
- ? ArrayItem<T>
372
- : T[Extract<keyof T, string>],
373
- >(
374
- a: U,
375
- b: U,
376
- ) => number,
377
- ): void => {
378
- // Get all entries as [key, value] pairs
379
- const entries = Array.from(signals.entries())
380
- .map(
381
- ([key, signal]) =>
382
- [key, signal.get()] as [
383
- string,
384
- T[Extract<keyof T, string>],
385
- ],
386
- )
387
- .sort(
388
- compareFn
389
- ? (a, b) => compareFn(a[1], b[1])
390
- : (a, b) => String(a[1]).localeCompare(String(b[1])),
391
- )
392
-
393
- // Create array of original keys in their new sorted order
394
- const newOrder: string[] = entries.map(([key]) => String(key))
395
- const newSignals = new Map<
396
- string,
397
- Signal<T[Extract<keyof T, string>] & {}>
398
- >()
399
-
400
- entries.forEach(([key], newIndex) => {
401
- const oldKey = String(key)
402
- const newKey = isArrayLike ? String(newIndex) : String(key)
403
-
404
- const signal = signals.get(oldKey)
405
- if (signal) newSignals.set(newKey, signal)
406
- })
407
-
408
- // Replace signals map
409
- signals.clear()
410
- newSignals.forEach((signal, key) => signals.set(key, signal))
411
- notify(watchers)
412
- emit('sort', newOrder)
413
- },
414
- on: <K extends keyof StoreChanges<T>>(
415
- type: K,
416
- listener: (change: StoreChanges<T>[K]) => void,
417
- ): Cleanup => {
418
- listeners[type].add(listener)
419
- return () => listeners[type].delete(listener)
420
- },
421
- size,
422
- }
423
-
424
- // Return proxy directly with integrated signal methods
425
- return new Proxy({} as Store<T>, {
426
- get(_target, prop) {
427
- // Symbols
428
- if (prop === Symbol.toStringTag) return TYPE_STORE
429
- if (prop === Symbol.isConcatSpreadable) return isArrayLike
430
- if (prop === Symbol.iterator)
431
- return isArrayLike
432
- ? function* () {
433
- const indexes = getSortedIndexes()
434
- for (const index of indexes) {
435
- const signal = signals.get(
436
- String(index) as Extract<keyof T, string>,
437
- )
438
- if (signal) yield signal
439
- }
440
- }
441
- : function* () {
442
- for (const [key, signal] of signals)
443
- yield [key, signal]
444
- }
445
- if (isSymbol(prop)) return undefined
446
-
447
- // Methods and Properties
448
- if (prop in store) return store[prop]
449
- if (prop === 'length' && isArrayLike) {
450
- subscribe(watchers)
451
- return size.get()
452
- }
453
-
454
- // Signals
455
- return signals.get(prop as Extract<keyof T, string>)
456
- },
457
- has(_target, prop) {
458
- const stringProp = String(prop)
459
- return (
460
- (stringProp &&
461
- signals.has(stringProp as Extract<keyof T, string>)) ||
462
- Object.keys(store).includes(stringProp) ||
463
- prop === Symbol.toStringTag ||
464
- prop === Symbol.iterator ||
465
- prop === Symbol.isConcatSpreadable ||
466
- (prop === 'length' && isArrayLike)
467
- )
468
- },
469
- ownKeys() {
470
- return isArrayLike
471
- ? getSortedIndexes()
472
- .map(key => String(key))
473
- .concat(['length'])
474
- : Array.from(signals.keys()).map(key => String(key))
475
- },
476
- getOwnPropertyDescriptor(_target, prop) {
477
- const nonEnumerable = <T>(value: T) => ({
478
- enumerable: false,
479
- configurable: true,
480
- writable: false,
481
- value,
482
- })
483
-
484
- if (prop === 'length' && isArrayLike)
485
- return {
486
- enumerable: true,
487
- configurable: true,
488
- writable: false,
489
- value: size.get(),
490
- }
491
- if (prop === Symbol.isConcatSpreadable)
492
- return nonEnumerable(isArrayLike)
493
- if (prop === Symbol.toStringTag) return nonEnumerable(TYPE_STORE)
494
- if (isSymbol(prop)) return undefined
495
-
496
- if (Object.keys(store).includes(prop))
497
- return nonEnumerable(store[prop])
498
-
499
- const signal = signals.get(prop as Extract<keyof T, string>)
500
- return signal
501
- ? {
502
- enumerable: true,
503
- configurable: true,
504
- writable: true,
505
- value: signal,
506
- }
507
- : undefined
508
- },
509
- })
510
- }
511
-
512
- /**
513
- * Check if the provided value is a Store instance
514
- *
515
- * @since 0.15.0
516
- * @param {unknown} value - value to check
517
- * @returns {boolean} - true if the value is a Store instance, false otherwise
518
- */
519
- const isStore = <T extends UnknownRecordOrArray>(
520
- value: unknown,
521
- ): value is Store<T> => isObjectOfType(value, TYPE_STORE)
522
-
523
- /* === Exports === */
524
-
525
- export { TYPE_STORE, isStore, createStore, type Store, type StoreChanges }
@@ -1,26 +0,0 @@
1
- import type { UnknownArray } from './diff';
2
- import { type Store, type StoreChanges } from './store';
3
- import { type Cleanup } from './system';
4
- type Collection<T extends UnknownArray> = {
5
- readonly [Symbol.toStringTag]: 'Collection';
6
- get(): T;
7
- on<K extends keyof StoreChanges<T>>(type: K, listener: (change: StoreChanges<T>[K]) => void): Cleanup;
8
- };
9
- type CollectionCallback<T extends UnknownArray> = (store: Store<T>) => T;
10
- declare const TYPE_COLLECTION = "Collection";
11
- /**
12
- * Create a collection signal
13
- *
14
- * @param {CollectionCallback<T>} fn - callback function to create the collection
15
- * @returns {Collection<T>} - collection signal
16
- */
17
- declare const createCollection: <T extends UnknownArray>(fn: CollectionCallback<T>) => Collection<T>;
18
- /**
19
- * Check if a value is a collection signal
20
- *
21
- * @since 0.16.0
22
- * @param {unknown} value - value to check
23
- * @returns {boolean} - true if value is a computed state, false otherwise
24
- */
25
- declare const isCollection: <T extends UnknownArray>(value: unknown) => value is Collection<T>;
26
- export { TYPE_COLLECTION, createCollection, isCollection, type Collection };
@@ -1,33 +0,0 @@
1
- type Computed<T extends {}> = {
2
- readonly [Symbol.toStringTag]: 'Computed';
3
- get(): T;
4
- };
5
- type ComputedCallback<T extends {} & {
6
- then?: undefined;
7
- }> = ((oldValue: T, abort: AbortSignal) => Promise<T>) | ((oldValue: T) => T);
8
- declare const TYPE_COMPUTED = "Computed";
9
- /**
10
- * Create a derived signal from existing signals
11
- *
12
- * @since 0.9.0
13
- * @param {ComputedCallback<T>} callback - Computation callback function
14
- * @returns {Computed<T>} - Computed signal
15
- */
16
- declare const createComputed: <T extends {}>(callback: ComputedCallback<T>, initialValue?: T) => Computed<T>;
17
- /**
18
- * Check if a value is a computed signal
19
- *
20
- * @since 0.9.0
21
- * @param {unknown} value - Value to check
22
- * @returns {boolean} - true if value is a computed signal, false otherwise
23
- */
24
- declare const isComputed: <T extends {}>(value: unknown) => value is Computed<T>;
25
- /**
26
- * Check if the provided value is a callback that may be used as input for toSignal() to derive a computed state
27
- *
28
- * @since 0.12.0
29
- * @param {unknown} value - Value to check
30
- * @returns {boolean} - true if value is a callback or callbacks object, false otherwise
31
- */
32
- declare const isComputedCallback: <T extends {}>(value: unknown) => value is ComputedCallback<T>;
33
- export { TYPE_COMPUTED, createComputed, isComputed, isComputedCallback, type Computed, type ComputedCallback, };
@@ -1,55 +0,0 @@
1
- type Cleanup = () => void;
2
- type Watcher = {
3
- (): void;
4
- off(cleanup: Cleanup): void;
5
- cleanup(): void;
6
- };
7
- type Updater = <T>() => T | boolean | undefined;
8
- /**
9
- * Create a watcher that can be used to observe changes to a signal
10
- *
11
- * @since 0.14.1
12
- * @param {() => void} notice - function to be called when the state changes
13
- * @returns {Watcher} - watcher object with off and cleanup methods
14
- */
15
- declare const watch: (notice: () => void) => Watcher;
16
- /**
17
- * Add active watcher to the Set of watchers
18
- *
19
- * @param {Set<Watcher>} watchers - watchers of the signal
20
- */
21
- declare const subscribe: (watchers: Set<Watcher>) => void;
22
- /**
23
- * Add watchers to the pending set of change notifications
24
- *
25
- * @param {Set<Watcher>} watchers - watchers of the signal
26
- */
27
- declare const notify: (watchers: Set<Watcher>) => void;
28
- /**
29
- * Flush all pending changes to notify watchers
30
- */
31
- declare const flush: () => void;
32
- /**
33
- * Batch multiple changes in a single signal graph and DOM update cycle
34
- *
35
- * @param {() => void} fn - function with multiple signal writes to be batched
36
- */
37
- declare const batch: (fn: () => void) => void;
38
- /**
39
- * Run a function in a reactive context
40
- *
41
- * @param {() => void} run - function to run the computation or effect
42
- * @param {Watcher} watcher - function to be called when the state changes or undefined for temporary unwatching while inserting auto-hydrating DOM nodes that might read signals (e.g., web components)
43
- */
44
- declare const observe: (run: () => void, watcher?: Watcher) => void;
45
- /**
46
- * Enqueue a function to be executed on the next animation frame
47
- *
48
- * If the same Symbol is provided for multiple calls before the next animation frame,
49
- * only the latest call will be executed (deduplication).
50
- *
51
- * @param {Updater} fn - function to be executed on the next animation frame; can return updated value <T>, success <boolean> or void
52
- * @param {symbol} dedupe - Symbol for deduplication; if not provided, a unique Symbol is created ensuring the update is always executed
53
- */
54
- declare const enqueue: <T>(fn: Updater, dedupe?: symbol) => Promise<boolean | T | undefined>;
55
- export { type Cleanup, type Watcher, type Updater, subscribe, notify, flush, batch, watch, observe, enqueue, };
@@ -1,24 +0,0 @@
1
- type State<T extends {}> = {
2
- readonly [Symbol.toStringTag]: 'State';
3
- get(): T;
4
- set(newValue: T): void;
5
- update(updater: (oldValue: T) => T): void;
6
- };
7
- declare const TYPE_STATE = "State";
8
- /**
9
- * Create a new state signal
10
- *
11
- * @since 0.9.0
12
- * @param {T} initialValue - initial value of the state
13
- * @returns {State<T>} - new state signal
14
- */
15
- declare const createState: <T extends {}>(initialValue: T) => State<T>;
16
- /**
17
- * Check if the provided value is a State instance
18
- *
19
- * @since 0.9.0
20
- * @param {unknown} value - value to check
21
- * @returns {boolean} - true if the value is a State instance, false otherwise
22
- */
23
- declare const isState: <T extends {}>(value: unknown) => value is State<T>;
24
- export { TYPE_STATE, isState, createState, type State };