mutts 1.0.6 → 1.0.7

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 (110) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.d.ts +2 -0
  3. package/dist/browser.esm.js +70 -0
  4. package/dist/browser.esm.js.map +1 -0
  5. package/dist/browser.js +161 -0
  6. package/dist/browser.js.map +1 -0
  7. package/dist/chunks/{index-CDCOjzTy.js → index-BFYK02LG.js} +5760 -4338
  8. package/dist/chunks/index-BFYK02LG.js.map +1 -0
  9. package/dist/chunks/{index-DiP0RXoZ.esm.js → index-CNR6QRUl.esm.js} +5440 -4054
  10. package/dist/chunks/index-CNR6QRUl.esm.js.map +1 -0
  11. package/dist/devtools/panel.js.map +1 -1
  12. package/dist/mutts.umd.js +1 -1
  13. package/dist/mutts.umd.js.map +1 -1
  14. package/dist/mutts.umd.min.js +1 -1
  15. package/dist/mutts.umd.min.js.map +1 -1
  16. package/dist/node.d.ts +2 -0
  17. package/dist/node.esm.js +45 -0
  18. package/dist/node.esm.js.map +1 -0
  19. package/dist/node.js +136 -0
  20. package/dist/node.js.map +1 -0
  21. package/docs/ai/api-reference.md +0 -2
  22. package/docs/reactive/advanced.md +2 -5
  23. package/docs/reactive/collections.md +0 -125
  24. package/docs/reactive/core.md +27 -24
  25. package/docs/reactive/debugging.md +12 -2
  26. package/docs/reactive/project.md +1 -1
  27. package/docs/reactive/scan.md +78 -0
  28. package/docs/reactive.md +2 -1
  29. package/docs/std-decorators.md +1 -0
  30. package/docs/zone.md +88 -0
  31. package/package.json +42 -10
  32. package/src/async/browser.ts +87 -0
  33. package/src/async/index.ts +8 -0
  34. package/src/async/node.ts +46 -0
  35. package/src/decorator.ts +5 -1
  36. package/src/destroyable.ts +1 -1
  37. package/src/index.ts +22 -14
  38. package/src/indexable.ts +42 -0
  39. package/src/mixins.ts +2 -2
  40. package/src/reactive/array.ts +149 -141
  41. package/src/reactive/buffer.ts +168 -0
  42. package/src/reactive/change.ts +2 -2
  43. package/src/reactive/effect-context.ts +15 -91
  44. package/src/reactive/effects.ts +119 -179
  45. package/src/reactive/index.ts +10 -13
  46. package/src/reactive/interface.ts +19 -33
  47. package/src/reactive/map.ts +48 -61
  48. package/src/reactive/memoize.ts +19 -9
  49. package/src/reactive/project.ts +43 -22
  50. package/src/reactive/proxy.ts +16 -41
  51. package/src/reactive/record.ts +3 -3
  52. package/src/reactive/register.ts +5 -7
  53. package/src/reactive/registry.ts +9 -17
  54. package/src/reactive/set.ts +42 -56
  55. package/src/reactive/tracking.ts +1 -29
  56. package/src/reactive/types.ts +46 -23
  57. package/src/utils.ts +80 -37
  58. package/src/zone.ts +127 -0
  59. package/dist/chunks/_tslib-BgjropY9.js +0 -81
  60. package/dist/chunks/_tslib-BgjropY9.js.map +0 -1
  61. package/dist/chunks/_tslib-MCKDzsSq.esm.js +0 -75
  62. package/dist/chunks/_tslib-MCKDzsSq.esm.js.map +0 -1
  63. package/dist/chunks/decorator-BGILvPtN.esm.js +0 -627
  64. package/dist/chunks/decorator-BGILvPtN.esm.js.map +0 -1
  65. package/dist/chunks/decorator-BQ2eBTCj.js +0 -651
  66. package/dist/chunks/decorator-BQ2eBTCj.js.map +0 -1
  67. package/dist/chunks/index-CDCOjzTy.js.map +0 -1
  68. package/dist/chunks/index-DiP0RXoZ.esm.js.map +0 -1
  69. package/dist/decorator.d.ts +0 -107
  70. package/dist/decorator.esm.js +0 -2
  71. package/dist/decorator.esm.js.map +0 -1
  72. package/dist/decorator.js +0 -11
  73. package/dist/decorator.js.map +0 -1
  74. package/dist/destroyable.d.ts +0 -90
  75. package/dist/destroyable.esm.js +0 -109
  76. package/dist/destroyable.esm.js.map +0 -1
  77. package/dist/destroyable.js +0 -116
  78. package/dist/destroyable.js.map +0 -1
  79. package/dist/eventful.d.ts +0 -20
  80. package/dist/eventful.esm.js +0 -66
  81. package/dist/eventful.esm.js.map +0 -1
  82. package/dist/eventful.js +0 -68
  83. package/dist/eventful.js.map +0 -1
  84. package/dist/index.d.ts +0 -19
  85. package/dist/index.esm.js +0 -53
  86. package/dist/index.esm.js.map +0 -1
  87. package/dist/index.js +0 -139
  88. package/dist/index.js.map +0 -1
  89. package/dist/indexable.d.ts +0 -243
  90. package/dist/indexable.esm.js +0 -285
  91. package/dist/indexable.esm.js.map +0 -1
  92. package/dist/indexable.js +0 -291
  93. package/dist/indexable.js.map +0 -1
  94. package/dist/promiseChain.d.ts +0 -21
  95. package/dist/promiseChain.esm.js +0 -78
  96. package/dist/promiseChain.esm.js.map +0 -1
  97. package/dist/promiseChain.js +0 -80
  98. package/dist/promiseChain.js.map +0 -1
  99. package/dist/reactive.d.ts +0 -910
  100. package/dist/reactive.esm.js +0 -5
  101. package/dist/reactive.esm.js.map +0 -1
  102. package/dist/reactive.js +0 -59
  103. package/dist/reactive.js.map +0 -1
  104. package/dist/std-decorators.d.ts +0 -52
  105. package/dist/std-decorators.esm.js +0 -196
  106. package/dist/std-decorators.esm.js.map +0 -1
  107. package/dist/std-decorators.js +0 -204
  108. package/dist/std-decorators.js.map +0 -1
  109. package/src/reactive/mapped.ts +0 -129
  110. package/src/reactive/zone.ts +0 -208
@@ -1,910 +0,0 @@
1
- import { LegacyPropertyDecorator, ModernMethodDecorator, LegacyClassDecorator, ModernClassDecorator, GenericClassDecorator, ModernGetterDecorator, ModernAccessorDecorator } from './decorator.js';
2
- import { ArrayReadForward, forwardArray, getAt, setAt } from './indexable.js';
3
-
4
- /**
5
- * Function type for dependency tracking in effects
6
- * Restores the active effect context for dependency tracking
7
- */
8
- type DependencyFunction = <T>(cb: () => T) => T;
9
- /**
10
- * Dependency access passed to user callbacks within effects/watch
11
- * Provides functions to track dependencies and information about the effect execution
12
- */
13
- interface DependencyAccess {
14
- /**
15
- * Tracks dependencies in the current effect context
16
- * Use this for normal dependency tracking within the effect
17
- * @example
18
- * ```typescript
19
- * effect(({ tracked }) => {
20
- * // In async context, use tracked to restore dependency tracking
21
- * await someAsyncOperation()
22
- * const value = tracked(() => state.count) // Tracks state.count in this effect
23
- * })
24
- * ```
25
- */
26
- tracked: DependencyFunction;
27
- /**
28
- * Tracks dependencies in the parent effect context
29
- * Use this when child effects should track dependencies in the parent,
30
- * allowing parent cleanup to manage child effects while dependencies trigger the parent
31
- * @example
32
- * ```typescript
33
- * effect(({ ascend }) => {
34
- * const length = inputs.length
35
- * if (length > 0) {
36
- * ascend(() => {
37
- * // Dependencies here are tracked in the parent effect
38
- * inputs.forEach(item => console.log(item))
39
- * })
40
- * }
41
- * })
42
- * ```
43
- */
44
- ascend: DependencyFunction;
45
- /**
46
- * Indicates whether the effect is running as a reaction (i.e. not the first call)
47
- * - `false`: First execution when the effect is created
48
- * - `true`: Subsequent executions triggered by dependency changes
49
- * @example
50
- * ```typescript
51
- * effect(({ reaction }) => {
52
- * if (!reaction) {
53
- * console.log('Effect initialized')
54
- * // Setup code that should only run once
55
- * } else {
56
- * console.log('Effect re-ran due to dependency change')
57
- * // Code that runs on every update
58
- * }
59
- * })
60
- * ```
61
- */
62
- reaction: boolean;
63
- }
64
- /**
65
- * Type for effect cleanup functions
66
- */
67
- type ScopedCallback = () => void;
68
- /**
69
- * Async execution mode for effects
70
- * - `cancel`: Cancel previous async execution when dependencies change (default)
71
- * - `queue`: Queue next execution to run after current completes
72
- * - `ignore`: Ignore new executions while async work is running
73
- */
74
- type AsyncExecutionMode = 'cancel' | 'queue' | 'ignore';
75
- /**
76
- * Options for effect creation
77
- */
78
- interface EffectOptions {
79
- /**
80
- * How to handle async effect executions when dependencies change
81
- * @default 'cancel'
82
- */
83
- asyncMode?: AsyncExecutionMode;
84
- /**
85
- * If true, this effect is "opaque" to deep optimizations: it sees the object reference itself
86
- * and must be notified when it changes, regardless of deep content similarity.
87
- * Use this for effects that depend on object identity (like memoize).
88
- */
89
- opaque?: boolean;
90
- }
91
- /**
92
- * Type for property evolution events
93
- */
94
- type PropEvolution = {
95
- type: 'set' | 'del' | 'add' | 'invalidate';
96
- prop: any;
97
- };
98
- /**
99
- * Type for collection operation evolution events
100
- */
101
- type BunchEvolution = {
102
- type: 'bunch';
103
- method: string;
104
- };
105
- type Evolution = PropEvolution | BunchEvolution;
106
- type State = {
107
- evolution: Evolution;
108
- next: State;
109
- } | {};
110
- /**
111
- * Context for a running projection item effect
112
- */
113
- interface ProjectionContext {
114
- source: any;
115
- key?: any;
116
- target: any;
117
- depth: number;
118
- parent?: ProjectionContext;
119
- }
120
- /**
121
- * Structured error codes for machine-readable diagnosis
122
- */
123
- declare enum ReactiveErrorCode {
124
- CycleDetected = "CYCLE_DETECTED",
125
- MaxDepthExceeded = "MAX_DEPTH_EXCEEDED",
126
- MaxReactionExceeded = "MAX_REACTION_EXCEEDED",
127
- WriteInComputed = "WRITE_IN_COMPUTED",
128
- TrackingError = "TRACKING_ERROR"
129
- }
130
- type CycleDebugInfo = {
131
- code: ReactiveErrorCode.CycleDetected;
132
- cycle: string[];
133
- details?: string;
134
- };
135
- type MaxDepthDebugInfo = {
136
- code: ReactiveErrorCode.MaxDepthExceeded;
137
- depth: number;
138
- chain: string[];
139
- };
140
- type MaxReactionDebugInfo = {
141
- code: ReactiveErrorCode.MaxReactionExceeded;
142
- count: number;
143
- effect: string;
144
- };
145
- type GenericDebugInfo = {
146
- code: ReactiveErrorCode;
147
- causalChain?: string[];
148
- creationStack?: string;
149
- [key: string]: any;
150
- };
151
- type ReactiveDebugInfo = CycleDebugInfo | MaxDepthDebugInfo | MaxReactionDebugInfo | GenericDebugInfo;
152
- /**
153
- * Error class for reactive system errors
154
- */
155
- declare class ReactiveError extends Error {
156
- debugInfo?: ReactiveDebugInfo;
157
- constructor(message: string, debugInfo?: ReactiveDebugInfo);
158
- }
159
- /**
160
- * Global options for the reactive system
161
- */
162
- declare const options: {
163
- /**
164
- * Debug purpose: called when an effect is entered
165
- * @param effect - The effect that is entered
166
- */
167
- enter: (_effect: Function) => void;
168
- /**
169
- * Debug purpose: called when an effect is left
170
- * @param effect - The effect that is left
171
- */
172
- leave: (_effect: Function) => void;
173
- /**
174
- * Debug purpose: called when an effect is chained
175
- * @param target - The effect that is being triggered
176
- * @param caller - The effect that is calling the target
177
- */
178
- chain: (_targets: Function[], _caller?: Function) => void;
179
- /**
180
- * Debug purpose: called when an effect chain is started
181
- * @param target - The effect that is being triggered
182
- */
183
- beginChain: (_targets: Function[]) => void;
184
- /**
185
- * Debug purpose: called when an effect chain is ended
186
- */
187
- endChain: () => void;
188
- garbageCollected: (_fn: Function) => void;
189
- /**
190
- * Debug purpose: called when an object is touched
191
- * @param obj - The object that is touched
192
- * @param evolution - The type of change
193
- * @param props - The properties that changed
194
- * @param deps - The dependencies that changed
195
- */
196
- touched: (_obj: any, _evolution: Evolution, _props?: any[], _deps?: Set<ScopedCallback>) => void;
197
- /**
198
- * Debug purpose: called when an effect is skipped because it's already running
199
- * @param effect - The effect that is already running
200
- * @param runningChain - The array of effects from the detected one to the currently running one
201
- */
202
- skipRunningEffect: (_effect: ScopedCallback, _runningChain: ScopedCallback[]) => void;
203
- /**
204
- * Debug purpose: maximum effect chain (like call stack max depth)
205
- * Used to prevent infinite loops
206
- * @default 100
207
- */
208
- maxEffectChain: number;
209
- /**
210
- * Maximum number of times an effect can be triggered by the same cause in a single batch
211
- * Used to detect aggressive re-computation or infinite loops
212
- * @default 10
213
- */
214
- maxTriggerPerBatch: number;
215
- /**
216
- * Debug purpose: maximum effect reaction (like call stack max depth)
217
- * Used to prevent infinite loops
218
- * @default 'throw'
219
- */
220
- maxEffectReaction: "throw" | "debug" | "warn";
221
- /**
222
- * Callback called when a memoization discrepancy is detected (debug only)
223
- * When defined, memoized functions will run a second time (untracked) to verify consistency.
224
- * If the untracked run returns a different value than the cached one, this callback is triggered.
225
- *
226
- * This is the primary tool for detecting missing reactive dependencies in computed values.
227
- *
228
- * @param cached - The value currently in the memoization cache
229
- * @param fresh - The value obtained by re-running the function untracked
230
- * @param fn - The memoized function itself
231
- * @param args - Arguments passed to the function
232
- *
233
- * @example
234
- * ```typescript
235
- * reactiveOptions.onMemoizationDiscrepancy = (cached, fresh, fn, args) => {
236
- * throw new Error(`Memoization discrepancy in ${fn.name}!`);
237
- * };
238
- * ```
239
- */
240
- onMemoizationDiscrepancy: ((cached: any, fresh: any, fn: Function, args: any[], cause: "calculation" | "comparison") => void) | undefined;
241
- /**
242
- * How to handle cycles detected in effect batches
243
- * - 'throw': Throw an error with cycle information (default, recommended for development)
244
- * - 'warn': Log a warning and break the cycle by executing one effect
245
- * - 'break': Silently break the cycle by executing one effect (recommended for production)
246
- * - 'strict': Prevent cycle creation by checking graph before execution (throws error)
247
- * @default 'throw'
248
- */
249
- cycleHandling: "throw" | "warn" | "break" | "strict";
250
- /**
251
- * Internal flag used by memoization discrepancy detector to avoid counting calls in tests
252
- * @warning Do not modify this flag manually, this flag is given by the engine
253
- */
254
- isVerificationRun: boolean;
255
- /**
256
- * Maximum depth for deep watching traversal
257
- * Used to prevent infinite recursion in circular references
258
- * @default 100
259
- */
260
- maxDeepWatchDepth: number;
261
- /**
262
- * Only react on instance members modification (not inherited properties)
263
- * For instance, do not track class methods
264
- * @default true
265
- */
266
- instanceMembers: boolean;
267
- /**
268
- * Ignore accessors (getters and setters) and only track direct properties
269
- * @default true
270
- */
271
- ignoreAccessors: boolean;
272
- /**
273
- * Enable recursive touching when objects with the same prototype are replaced
274
- * When enabled, replacing an object with another of the same prototype triggers
275
- * recursive diffing instead of notifying parent effects
276
- * @default true
277
- */
278
- recursiveTouching: boolean;
279
- /**
280
- * Default async execution mode for effects that return Promises
281
- * - 'cancel': Cancel previous async execution when dependencies change (default, enables async zone)
282
- * - 'queue': Queue next execution to run after current completes (enables async zone)
283
- * - 'ignore': Ignore new executions while async work is running (enables async zone)
284
- * - false: Disable async zone and async mode handling (effects run concurrently)
285
- *
286
- * **When truthy:** Enables async zone (Promise.prototype wrapping) for automatic context
287
- * preservation in Promise callbacks. Warning: This modifies Promise.prototype globally.
288
- * Only enable if no other library modifies Promise.prototype.
289
- *
290
- * **When false:** Async zone is disabled. Use `tracked()` manually in Promise callbacks.
291
- *
292
- * Can be overridden per-effect via EffectOptions
293
- * @default 'cancel'
294
- */
295
- asyncMode: AsyncExecutionMode | false;
296
- warn: (...args: any[]) => void;
297
- /**
298
- * Configuration for the introspection system
299
- */
300
- introspection: {
301
- /**
302
- * Whether to keep a history of mutations for debugging
303
- * @default false
304
- */
305
- enableHistory: boolean;
306
- /**
307
- * Number of mutations to keep in history
308
- * @default 50
309
- */
310
- historySize: number;
311
- };
312
- /**
313
- * Configuration for zone hooks - control which async APIs are hooked
314
- * Each option controls whether the corresponding async API is wrapped to preserve effect context
315
- * Only applies when asyncMode is enabled (truthy)
316
- */
317
- zones: {
318
- /**
319
- * Hook setTimeout to preserve effect context
320
- * @default true
321
- */
322
- setTimeout: boolean;
323
- /**
324
- * Hook setInterval to preserve effect context
325
- * @default true
326
- */
327
- setInterval: boolean;
328
- /**
329
- * Hook requestAnimationFrame (runs in untracked context when hooked)
330
- * @default true
331
- */
332
- requestAnimationFrame: boolean;
333
- /**
334
- * Hook queueMicrotask to preserve effect context
335
- * @default true
336
- */
337
- queueMicrotask: boolean;
338
- };
339
- };
340
-
341
- /**
342
- * Gets the current state of a reactive object for evolution tracking
343
- * @param obj - The reactive object
344
- * @returns The current state object
345
- */
346
- declare function getState(obj: any): State;
347
- /**
348
- * Triggers effects for a single property change
349
- * @param obj - The object that changed
350
- * @param evolution - The type of change
351
- * @param prop - The property that changed
352
- */
353
- declare function touched1(obj: any, evolution: Evolution, prop: any): void;
354
- /**
355
- * Triggers effects for property changes
356
- * @param obj - The object that changed
357
- * @param evolution - The type of change
358
- * @param props - The properties that changed
359
- */
360
- declare function touched(obj: any, evolution: Evolution, props?: Iterable<any>): void;
361
-
362
- /**
363
- * Debug utilities for the reactivity system
364
- * - Captures effect metadata (names, parent relationships)
365
- * - Records cause → consequence edges with object/prop labels
366
- * - Provides graph data for tooling (DevTools panel, etc.)
367
- */
368
-
369
- type NodeKind = 'effect' | 'external' | 'state';
370
- type EdgeKind = 'cause' | 'dependency' | 'trigger';
371
- interface EffectNode {
372
- id: string;
373
- label: string;
374
- type: NodeKind;
375
- depth: number;
376
- parentId?: string;
377
- debugName?: string;
378
- }
379
- interface ObjectNode {
380
- id: string;
381
- label: string;
382
- type: NodeKind;
383
- debugName?: string;
384
- }
385
- interface GraphEdge {
386
- id: string;
387
- source: string;
388
- target: string;
389
- type: EdgeKind;
390
- label: string;
391
- count?: number;
392
- }
393
- interface ReactivityGraph {
394
- nodes: Array<EffectNode | ObjectNode>;
395
- edges: GraphEdge[];
396
- meta: {
397
- generatedAt: number;
398
- devtoolsEnabled: boolean;
399
- };
400
- }
401
- /**
402
- * Assign a debug-friendly name to an effect (shown in DevTools)
403
- */
404
- declare function setEffectName(effect: ScopedCallback, name: string): void;
405
- /**
406
- * Assign a debug-friendly name to a reactive object
407
- */
408
- declare function setObjectName(obj: object, name: string): void;
409
- /**
410
- * Register an effect so it appears in the DevTools graph
411
- */
412
- declare function registerEffectForDebug(effect: ScopedCallback): void;
413
- /**
414
- * Register a reactive object so it appears in the DevTools graph
415
- */
416
- declare function registerObjectForDebug(obj: object): void;
417
- /**
418
- * Builds a graph representing current reactive state (effects, objects, and trigger edges)
419
- */
420
- declare function buildReactivityGraph(): ReactivityGraph;
421
- /**
422
- * Enables the DevTools bridge and exposes the debug API on window.
423
- * Call as early as possible in development builds.
424
- */
425
- declare function enableDevTools(): void;
426
- declare function isDevtoolsEnabled(): boolean;
427
-
428
- /**
429
- * Deep watch an object and all its nested properties
430
- * @param target - The object to watch deeply
431
- * @param callback - The callback to call when any nested property changes
432
- * @param options - Options for the deep watch
433
- * @returns A cleanup function to stop watching
434
- */
435
- /**
436
- * Sets up deep watching for an object, tracking all nested property changes
437
- * @param target - The object to watch
438
- * @param callback - The callback to call when changes occur
439
- * @param options - Options for deep watching
440
- * @returns A cleanup function to stop deep watching
441
- */
442
- declare function deepWatch<T extends object>(target: T, callback: (value: T) => void, { immediate }?: {
443
- immediate?: boolean;
444
- }): (() => void) | undefined;
445
-
446
- declare function getActiveEffect(): ScopedCallback;
447
-
448
- type EffectTracking = (obj: any, evolution: Evolution, prop: any) => void;
449
-
450
- interface ActivationRecord {
451
- effect: ScopedCallback;
452
- obj: any;
453
- evolution: Evolution;
454
- prop: any;
455
- batchId: number;
456
- }
457
- declare function getActivationLog(): Omit<ActivationRecord, "batchId">[];
458
- /**
459
- * Registers a debug callback that is called when the current effect is triggered by a dependency change
460
- *
461
- * This function is useful for debugging purposes as it pin-points exactly which reactive property
462
- * change triggered the effect. The callback receives information about:
463
- * - The object that changed
464
- * - The type of change (evolution)
465
- * - The specific property that changed
466
- *
467
- * **Note:** The tracker callback is automatically removed after being called once. If you need
468
- * to track multiple triggers, call `trackEffect` again within the effect.
469
- *
470
- * @param onTouch - Callback function that receives (obj, evolution, prop) when the effect is triggered
471
- * @throws {Error} If called outside of an effect context
472
- *
473
- * @example
474
- * ```typescript
475
- * const state = reactive({ count: 0, name: 'John' })
476
- *
477
- * effect(() => {
478
- * // Register a tracker to see what triggers this effect
479
- * trackEffect((obj, evolution, prop) => {
480
- * console.log(`Effect triggered by:`, {
481
- * object: obj,
482
- * change: evolution.type,
483
- * property: prop
484
- * })
485
- * })
486
- *
487
- * // Access reactive properties
488
- * console.log(state.count, state.name)
489
- * })
490
- *
491
- * state.count = 5
492
- * // Logs: Effect triggered by: { object: state, change: 'set', property: 'count' }
493
- * ```
494
- */
495
- declare function trackEffect(onTouch: EffectTracking): void;
496
- /**
497
- * Adds a cleanup function to be called when the current batch of effects completes
498
- * @param cleanup - The cleanup function to add
499
- */
500
- declare function addBatchCleanup(cleanup: ScopedCallback): void;
501
- /**
502
- * Semantic alias for `addBatchCleanup` - defers work to the end of the current reactive batch.
503
- *
504
- * Use this when an effect needs to perform an action that would modify state the effect depends on,
505
- * which would create a reactive cycle. The deferred callback runs after all effects complete.
506
- *
507
- * @param callback - The callback to defer until after the current batch completes
508
- *
509
- * @example
510
- * ```typescript
511
- * effect(() => {
512
- * processData()
513
- *
514
- * // Defer to avoid cycle (createMovement modifies state this effect reads)
515
- * defer(() => {
516
- * createMovement(data)
517
- * })
518
- * })
519
- * ```
520
- */
521
- declare const defer: typeof addBatchCleanup;
522
- declare function batch(effect: ScopedCallback | ScopedCallback[], immediate?: 'immediate'): any;
523
- /**
524
- * Decorator that makes methods atomic - batches all effects triggered within the method
525
- */
526
- declare const atomic: LegacyPropertyDecorator<any> & ModernMethodDecorator<any> & (<Args extends any[], Return>(original: (...args: Args) => Return) => (...args: Args) => Return);
527
- /**
528
- * @param fn - The effect function to run - provides the cleaner
529
- * @returns The cleanup function
530
- */
531
- /**
532
- * Creates a reactive effect that automatically re-runs when dependencies change
533
- * @param fn - The effect function that provides dependencies and may return a cleanup function or Promise
534
- * @param options - Options for effect execution
535
- * @returns A cleanup function to stop the effect
536
- */
537
- declare function effect(fn: (access: DependencyAccess) => ScopedCallback | undefined | void | Promise<any>, effectOptions?: EffectOptions): ScopedCallback;
538
- /**
539
- * Executes a function without tracking dependencies but maintains parent cleanup relationship
540
- * Effects created inside will still be cleaned up when the parent effect is destroyed
541
- * @param fn - The function to execute
542
- */
543
- declare function untracked<T>(fn: () => T): T;
544
- /**
545
- * Executes a function from a virgin/root context - no parent effect, no tracking
546
- * Creates completely independent effects that won't be cleaned up by any parent
547
- * @param fn - The function to execute
548
- */
549
- declare function root<T>(fn: () => T): T;
550
-
551
- /**
552
- * Creates a bidirectional binding between a reactive value and a non-reactive external value
553
- * Prevents infinite loops by automatically suppressing circular notifications
554
- *
555
- * @param received - Function called when the reactive value changes (external setter)
556
- * @param get - Getter for the reactive value OR an object with `{ get, set }` properties
557
- * @param set - Setter for the reactive value (required if `get` is a function)
558
- * @returns A function to manually provide updates from the external side
559
- *
560
- * @example
561
- * ```typescript
562
- * const model = reactive({ value: '' })
563
- * const input = { value: '' }
564
- *
565
- * // Bidirectional binding
566
- * const provide = biDi(
567
- * (v) => input.value = v, // external setter
568
- * () => model.value, // reactive getter
569
- * (v) => model.value = v // reactive setter
570
- * )
571
- *
572
- * // External notification (e.g., from input event)
573
- * provide('new value') // Updates model.value, doesn't trigger circular loop
574
- * ```
575
- *
576
- * @example Using object syntax
577
- * ```typescript
578
- * const provide = biDi(
579
- * (v) => setHTMLValue(v),
580
- * { get: () => reactiveObj.value, set: (v) => reactiveObj.value = v }
581
- * )
582
- * ```
583
- */
584
- declare function biDi<T>(received: (value: T) => void, value: {
585
- get: () => T;
586
- set: (value: T) => void;
587
- }): (value: T) => void;
588
- declare function biDi<T>(received: (value: T) => void, get: () => T, set: (value: T) => void): (value: T) => void;
589
-
590
- /**
591
- * Symbol for accessing the cleanup function on cleaned objects
592
- */
593
- declare const cleanup: unique symbol;
594
- /**
595
- * Options for the watch function
596
- */
597
- interface WatchOptions {
598
- /** Whether to call the callback immediately */
599
- immediate?: boolean;
600
- /** Whether to watch nested properties */
601
- deep?: boolean;
602
- }
603
- /**
604
- * Watches a reactive value and calls a callback when it changes
605
- * @param value - Function that returns the value to watch
606
- * @param changed - Callback to call when the value changes
607
- * @param options - Watch options
608
- * @returns Cleanup function to stop watching
609
- */
610
- declare function watch<T>(value: (dep: DependencyAccess) => T, changed: (value: T, oldValue?: T) => void, options?: Omit<WatchOptions, 'deep'> & {
611
- deep?: false;
612
- }): ScopedCallback;
613
- /**
614
- * Watches a reactive value with deep watching enabled
615
- * @param value - Function that returns the value to watch
616
- * @param changed - Callback to call when the value changes
617
- * @param options - Watch options with deep watching enabled
618
- * @returns Cleanup function to stop watching
619
- */
620
- declare function watch<T extends object | any[]>(value: (dep: DependencyAccess) => T, changed: (value: T, oldValue?: T) => void, options?: Omit<WatchOptions, 'deep'> & {
621
- deep: true;
622
- }): ScopedCallback;
623
- /**
624
- * Watches a reactive object directly
625
- * @param value - The reactive object to watch
626
- * @param changed - Callback to call when the object changes
627
- * @param options - Watch options
628
- * @returns Cleanup function to stop watching
629
- */
630
- declare function watch<T extends object | any[]>(value: T, changed: (value: T) => void, options?: WatchOptions): ScopedCallback;
631
- declare function unreactiveApplication<T extends object>(...args: (keyof T)[]): GenericClassDecorator<T>;
632
- declare function unreactiveApplication<T extends object>(obj: T): T;
633
- /**
634
- * Decorator that marks classes or properties as non-reactive
635
- * Prevents objects from being made reactive
636
- */
637
- declare const unreactive: LegacyClassDecorator<new (...args: any[]) => any> & ModernClassDecorator<new (...args: any[]) => any> & typeof unreactiveApplication;
638
- declare function cleanedBy<T extends object>(obj: T, cleanupFn: ScopedCallback): T & {
639
- [cleanup]: ScopedCallback;
640
- };
641
- /**
642
- * Creates a derived value that automatically recomputes when dependencies change
643
- * @param compute - Function that computes the derived value
644
- * @returns Object with value and cleanup function
645
- */
646
- declare function derived<T>(compute: (dep: DependencyAccess) => T): {
647
- value: T;
648
- [cleanup]: ScopedCallback;
649
- };
650
-
651
- declare class ReadOnlyError extends Error {
652
- }
653
- declare function mapped<T, U>(inputs: readonly T[], compute: (input: T, index: number, output: U[]) => U, resize?: (newLength: number, oldLength: number) => void): readonly U[];
654
- declare function reduced<T, U, R extends object = any>(inputs: readonly T[], compute: (input: T, factor: R) => readonly U[]): readonly U[];
655
-
656
- type Memoizable = object | any[] | symbol | ((...args: any[]) => any);
657
- declare function memoizeFunction<Result, Args extends Memoizable[]>(fn: (...args: Args) => Result): (...args: Args) => Result;
658
- declare const memoize: LegacyPropertyDecorator<any> & ModernMethodDecorator<any> & ModernGetterDecorator<any> & ModernAccessorDecorator<any> & typeof memoizeFunction;
659
-
660
- declare const immutables: Set<(tested: any) => boolean>;
661
- declare function isNonReactive(obj: any): boolean;
662
- declare function registerNativeReactivity(originalClass: new (...args: any[]) => any, reactiveClass: new (...args: any[]) => any): void;
663
-
664
- type KeyFunction<T, K extends PropertyKey> = (item: T) => K;
665
- interface RegisterInstance<T> extends ArrayReadForward<T> {
666
- [index: number]: T;
667
- }
668
- declare const RegisterClass_base: new () => ArrayReadForward<any> & {
669
- [x: number]: any;
670
- toArray(): any[];
671
- };
672
- declare class RegisterClass<T, K extends PropertyKey = PropertyKey> extends RegisterClass_base implements RegisterInstance<T> {
673
- #private;
674
- protected get [forwardArray](): readonly T[];
675
- constructor(keyFn: KeyFunction<T, K>, initial?: Iterable<T>);
676
- private ensureKey;
677
- private assertValidKey;
678
- private setKeyValue;
679
- private cleanupValue;
680
- private disposeKeyEffects;
681
- private incrementUsage;
682
- private decrementUsage;
683
- private normalizeIndex;
684
- private assignAt;
685
- private insertKeyValue;
686
- private rebuildFrom;
687
- get length(): number;
688
- [getAt](index: number): T | undefined;
689
- [setAt](index: number, value: T): void;
690
- push(...items: T[]): number;
691
- pop(): T | undefined;
692
- shift(): T | undefined;
693
- unshift(...items: T[]): number;
694
- splice(start: number, deleteCount?: number, ...items: T[]): T[];
695
- clear(): void;
696
- get(key: K): T | undefined;
697
- set(key: K, value: T): void;
698
- remove(key: K): void;
699
- removeAt(index: number): T | undefined;
700
- /**
701
- * Keep only the items for which the predicate returns true.
702
- * Items for which the predicate returns false are removed.
703
- *
704
- * The predicate is evaluated once per distinct key; duplicate keys
705
- * will follow the same keep/remove decision.
706
- */
707
- keep(predicate: (value: T) => boolean): void;
708
- hasKey(key: K): boolean;
709
- indexOfKey(key: K): number;
710
- mapKeys(): IterableIterator<K>;
711
- update(...values: T[]): void;
712
- upsert(insert: (value: T) => void, ...values: T[]): void;
713
- entries(): IterableIterator<[number, T]>;
714
- [Symbol.iterator](): IterableIterator<T>;
715
- toString(): string;
716
- at(index: number): T | undefined;
717
- reverse(): this;
718
- sort(compareFn?: ((a: T, b: T) => number) | undefined): this;
719
- fill(value: T, start?: number, end?: number): this;
720
- copyWithin(target: number, start: number, end?: number): this;
721
- }
722
- type Register<T, K extends PropertyKey = PropertyKey> = RegisterClass<T, K> & T[];
723
- declare const Register: new <T, K extends PropertyKey = PropertyKey>(keyFn: KeyFunction<T, K>, initial?: Iterable<T>) => Register<T, K>;
724
- declare function register<T, K extends PropertyKey = PropertyKey>(keyFn: KeyFunction<T, K>, initial?: Iterable<T>): Register<T, K>;
725
-
726
- /**
727
- * Returns the projection context of the currently running effect, if any.
728
- */
729
- declare function getActiveProjection(): ProjectionContext | undefined;
730
- type ProjectOldValue<Target> = Target extends readonly (infer Item)[] ? Item : Target extends Map<any, infer Item> ? Item : Target extends Record<PropertyKey, infer Item> ? Item : unknown;
731
- type ProjectAccess<SourceValue, Key, SourceType, Target> = {
732
- readonly key: Key;
733
- get(): SourceValue;
734
- set(value: SourceValue): boolean;
735
- readonly source: SourceType;
736
- readonly old?: ProjectOldValue<Target>;
737
- value: SourceValue;
738
- };
739
- type BivariantProjectCallback<Args extends any[], Return> = {
740
- bivarianceHack(...args: Args): Return;
741
- }['bivarianceHack'];
742
- type ProjectCallback<SourceValue, Key, Target extends object, SourceType, Result> = BivariantProjectCallback<[ProjectAccess<SourceValue, Key, SourceType, Target>, Target], Result>;
743
- type ProjectResult<Target extends object> = Target & {
744
- [cleanup]: ScopedCallback;
745
- };
746
- declare function projectArray<SourceValue, ResultValue>(source: readonly SourceValue[], apply: ProjectCallback<SourceValue, number, ResultValue[], readonly SourceValue[], ResultValue>): ProjectResult<ResultValue[]>;
747
- declare function projectRegister<Key extends PropertyKey, SourceValue, ResultValue>(source: Register<SourceValue, Key>, apply: ProjectCallback<SourceValue, Key, Map<Key, ResultValue>, Register<SourceValue, Key>, ResultValue>): ProjectResult<Map<Key, ResultValue>>;
748
- declare function projectRecord<Source extends Record<PropertyKey, any>, ResultValue>(source: Source, apply: ProjectCallback<Source[keyof Source], keyof Source, Record<keyof Source, ResultValue>, Source, ResultValue>): ProjectResult<Record<keyof Source, ResultValue>>;
749
- declare function projectMap<Key, Value, ResultValue>(source: Map<Key, Value>, apply: ProjectCallback<Value, Key, Map<Key, ResultValue>, Map<Key, Value>, ResultValue>): ProjectResult<Map<Key, ResultValue>>;
750
- type ProjectOverload = {
751
- <SourceValue, ResultValue>(source: readonly SourceValue[], apply: ProjectCallback<SourceValue, number, ResultValue[], readonly SourceValue[], ResultValue>): ProjectResult<ResultValue[]>;
752
- <Key extends PropertyKey, SourceValue, ResultValue>(source: Register<SourceValue, Key>, apply: ProjectCallback<SourceValue, Key, Map<Key, ResultValue>, Register<SourceValue, Key>, ResultValue>): ProjectResult<Map<Key, ResultValue>>;
753
- <Source extends Record<PropertyKey, any>, ResultValue>(source: Source, apply: ProjectCallback<Source[keyof Source], keyof Source, Record<keyof Source, ResultValue>, Source, ResultValue>): ProjectResult<Record<keyof Source, ResultValue>>;
754
- <Key, Value, ResultValue>(source: Map<Key, Value>, apply: ProjectCallback<Value, Key, Map<Key, ResultValue>, Map<Key, Value>, ResultValue>): ProjectResult<Map<Key, ResultValue>>;
755
- array: typeof projectArray;
756
- register: typeof projectRegister;
757
- record: typeof projectRecord;
758
- map: typeof projectMap;
759
- };
760
- declare const project: ProjectOverload;
761
-
762
- declare function unwrap<T>(obj: T): T;
763
- declare function isReactive(obj: any): boolean;
764
-
765
- /**
766
- * Base mixin for reactive classes that provides proper constructor reactivity
767
- * Solves constructor reactivity issues in complex inheritance trees
768
- */
769
- declare const ReactiveBase: (new (...args: any[]) => {
770
- [x: string]: any;
771
- }) & (<Base>(base: abstract new (...args: any[]) => Base) => new (...args: any[]) => {
772
- [x: string]: any;
773
- } & Base);
774
- declare function reactiveObject<T>(anyTarget: T): T;
775
- /**
776
- * Main decorator for making classes reactive
777
- * Automatically makes class instances reactive when created
778
- */
779
- declare const reactive: LegacyClassDecorator<new (...args: any[]) => any> & ModernClassDecorator<new (...args: any[]) => any> & typeof reactiveObject;
780
-
781
- /**
782
- * Provides type-safe access to a source object's property within the organized callback.
783
- * @template Source - The type of the source object
784
- * @template Key - The type of the property key in the source object
785
- */
786
- type OrganizedAccess<Source extends Record<PropertyKey, any>, Key extends keyof Source> = {
787
- /** The property key being accessed */
788
- readonly key: Key;
789
- /**
790
- * Gets the current value of the property from the source object
791
- * @returns The current value of the property
792
- */
793
- get(): Source[Key];
794
- /**
795
- * Updates the property value in the source object
796
- * @param value - The new value to set
797
- * @returns {boolean} True if the update was successful
798
- */
799
- set(value: Source[Key]): boolean;
800
- /**
801
- * The current value of the property (equivalent to using get()/set() directly)
802
- */
803
- value: Source[Key];
804
- };
805
- /**
806
- * Callback function type for the organized function that processes each source property.
807
- * @template Source - The type of the source object
808
- * @template Target - The type of the target object
809
- */
810
- type OrganizedCallback<Source extends Record<PropertyKey, any>, Target extends object> = <Key extends keyof Source>(
811
- /**
812
- * Accessor object for the current source property
813
- */
814
- access: OrganizedAccess<Source, Key>,
815
- /**
816
- * The target object where organized data will be stored
817
- */
818
- target: Target) => ScopedCallback | undefined;
819
- /**
820
- * The result type of the organized function, combining the target object with cleanup capability.
821
- * @template Target - The type of the target object
822
- */
823
- type OrganizedResult<Target extends object> = Target & {
824
- /**
825
- * Cleanup function to dispose of all reactive bindings created by organized().
826
- * This is automatically called when the effect that created the organized binding is disposed.
827
- */
828
- [cleanup]: ScopedCallback;
829
- };
830
- /**
831
- * Organizes a source object's properties into a target object using a callback function.
832
- * This creates a reactive mapping between source properties and a target object,
833
- * automatically handling property additions, updates, and removals.
834
- *
835
- * @template Source - The type of the source object
836
- * @template Target - The type of the target object (defaults to Record<PropertyKey, any>)
837
- *
838
- * @param {Source} source - The source object to organize
839
- * @param {OrganizedCallback<Source, Target>} apply - Callback function that defines how each source property is mapped to the target
840
- * @param {Target} [baseTarget={}] - Optional base target object to use (will be made reactive if not already)
841
- *
842
- * @returns {OrganizedResult<Target>} The target object with cleanup capability
843
- *
844
- * @example
845
- * // Organize user permissions into role-based access
846
- * const user = reactive({ isAdmin: true, canEdit: false });
847
- * const permissions = organized(
848
- * user,
849
- * (access, target) => {
850
- * if (access.key === 'isAdmin') {
851
- * target.hasFullAccess = access.value;
852
- * }
853
- * target[`can${access.key.charAt(0).toUpperCase() + access.key.slice(1)}`] = access.value;
854
- * }
855
- * );
856
- *
857
- * @example
858
- * // Transform object structure with cleanup
859
- * const source = reactive({ firstName: 'John', lastName: 'Doe' });
860
- * const formatted = organized(
861
- * source,
862
- * (access, target) => {
863
- * if (access.key === 'firstName' || access.key === 'lastName') {
864
- * target.fullName = `${source.firstName} ${source.lastName}`.trim();
865
- * }
866
- * }
867
- * );
868
- *
869
- * @example
870
- * // Using with cleanup in a component
871
- * effect(() => {
872
- * const data = fetchData();
873
- * const organizedData = organized(data, (access, target) => {
874
- * // Transform data
875
- * });
876
- *
877
- * // The cleanup will be called automatically when the effect is disposed
878
- * return () => organizedData[cleanup]();
879
- * });
880
- */
881
- declare function organized<Source extends Record<PropertyKey, any>, Target extends object = Record<PropertyKey, any>>(source: Source, apply: OrganizedCallback<Source, Target>, baseTarget?: Target): OrganizedResult<Target>;
882
- /**
883
- * Organizes a property on a target object
884
- * Shortcut for defineProperty/delete with touched signal
885
- * @param target - The target object
886
- * @param property - The property to organize
887
- * @param access - The access object
888
- * @returns The property descriptor
889
- */
890
- declare function organize<T>(target: object, property: PropertyKey, access: {
891
- get?(): T;
892
- set?(value: T): boolean;
893
- }): () => boolean;
894
-
895
- /**
896
- * Manually enable/disable the zone (for testing)
897
- */
898
- declare function setZoneEnabled(enabled: boolean): void;
899
- /**
900
- * Check if zone is currently hooked
901
- */
902
- declare function isZoneEnabled(): boolean;
903
-
904
- /**
905
- * Object containing internal reactive system state for debugging and profiling
906
- */
907
- declare const profileInfo: any;
908
-
909
- export { ReactiveBase, ReactiveError, ReadOnlyError, Register, addBatchCleanup, atomic, batch, biDi, buildReactivityGraph, cleanedBy, cleanup, deepWatch, defer, derived, effect, enableDevTools, getActivationLog, getActiveEffect, getActiveProjection, getState, immutables, isDevtoolsEnabled, isNonReactive, isReactive, isZoneEnabled, mapped, memoize, organize, organized, profileInfo, project, reactive, options as reactiveOptions, reduced, register, registerEffectForDebug, registerNativeReactivity, registerObjectForDebug, root, setEffectName, setObjectName, setZoneEnabled, touched, touched1, trackEffect, unreactive, untracked, unwrap, watch };
910
- export type { DependencyAccess, DependencyFunction, Evolution, Memoizable, ReactivityGraph, ScopedCallback };