@sigx/reactivity 0.1.8 → 0.1.9

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.
@@ -0,0 +1,79 @@
1
+ let activeEffect = null;
2
+ var batchDepth = 0;
3
+ var pendingEffects = /* @__PURE__ */ new Set();
4
+ function setActiveEffect(effect) {
5
+ activeEffect = effect;
6
+ }
7
+ function getActiveEffect() {
8
+ return activeEffect;
9
+ }
10
+ function batch(fn) {
11
+ batchDepth++;
12
+ try {
13
+ fn();
14
+ } finally {
15
+ batchDepth--;
16
+ if (batchDepth === 0) {
17
+ const effects = Array.from(pendingEffects);
18
+ pendingEffects.clear();
19
+ for (const effect of effects) effect();
20
+ }
21
+ }
22
+ }
23
+ function cleanup(effect) {
24
+ if (!effect.deps) return;
25
+ for (const dep of effect.deps) dep.delete(effect);
26
+ effect.deps.length = 0;
27
+ }
28
+ function track(depSet) {
29
+ if (!activeEffect) return;
30
+ depSet.add(activeEffect);
31
+ activeEffect.deps.push(depSet);
32
+ }
33
+ function trigger(depSet) {
34
+ const effects = Array.from(depSet);
35
+ for (const effect of effects) if (batchDepth > 0) pendingEffects.add(effect);
36
+ else effect();
37
+ }
38
+ function runEffect(fn) {
39
+ const effectFn = function() {
40
+ cleanup(effectFn);
41
+ activeEffect = effectFn;
42
+ fn();
43
+ activeEffect = null;
44
+ };
45
+ effectFn.deps = [];
46
+ effectFn();
47
+ const runner = (() => effectFn());
48
+ runner.stop = () => cleanup(effectFn);
49
+ return runner;
50
+ }
51
+ function effect(fn) {
52
+ return runEffect(fn);
53
+ }
54
+ function untrack(fn) {
55
+ const prev = activeEffect;
56
+ activeEffect = null;
57
+ try {
58
+ return fn();
59
+ } finally {
60
+ activeEffect = prev;
61
+ }
62
+ }
63
+ function effectScope(_detached) {
64
+ const effects = [];
65
+ let active = true;
66
+ return {
67
+ run(fn) {
68
+ if (!active) return void 0;
69
+ return fn();
70
+ },
71
+ stop() {
72
+ active = false;
73
+ effects.forEach((e) => e());
74
+ }
75
+ };
76
+ }
77
+ export { getActiveEffect as a, trigger as c, effectScope as i, untrack as l, cleanup as n, setActiveEffect as o, effect as r, track as s, batch as t };
78
+
79
+ //# sourceMappingURL=effect-DeSl7uNB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-DeSl7uNB.js","names":[],"sources":["../src/effect.ts"],"sourcesContent":["// ============================================================================\r\n// Effect System - Core reactivity primitives\r\n// ============================================================================\r\n\r\nimport type { EffectFn, EffectRunner, ReactiveEffect } from './types';\r\n\r\nexport let activeEffect: ReactiveEffect | null = null;\r\nlet batchDepth = 0;\r\nconst pendingEffects = new Set<ReactiveEffect>();\r\n\r\nexport function setActiveEffect(effect: ReactiveEffect | null): void {\r\n activeEffect = effect;\r\n}\r\n\r\nexport function getActiveEffect(): ReactiveEffect | null {\r\n return activeEffect;\r\n}\r\n\r\n/**\r\n * Batch multiple reactive updates into a single flush.\r\n * Effects are deferred until the batch completes, avoiding redundant re-renders.\r\n *\r\n * @example\r\n * ```ts\r\n * batch(() => {\r\n * count.value++;\r\n * name.value = 'Alice';\r\n * }); // effects run once after both updates\r\n * ```\r\n */\r\nexport function batch(fn: () => void) {\r\n batchDepth++;\r\n try {\r\n fn();\r\n } finally {\r\n batchDepth--;\r\n if (batchDepth === 0) {\r\n const effects = Array.from(pendingEffects);\r\n pendingEffects.clear();\r\n for (const effect of effects) {\r\n effect();\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function cleanup(effect: ReactiveEffect): void {\r\n if (!effect.deps) return;\r\n for (const dep of effect.deps) {\r\n dep.delete(effect);\r\n }\r\n effect.deps.length = 0;\r\n}\r\n\r\nexport function track(depSet: Set<ReactiveEffect>): void {\r\n if (!activeEffect) return;\r\n depSet.add(activeEffect);\r\n activeEffect.deps.push(depSet);\r\n}\r\n\r\nexport function trigger(depSet: Set<ReactiveEffect>): void {\r\n const effects = Array.from(depSet);\r\n for (const effect of effects) {\r\n if (batchDepth > 0) {\r\n pendingEffects.add(effect);\r\n } else {\r\n effect();\r\n }\r\n }\r\n}\r\n\r\nfunction runEffect(fn: EffectFn): EffectRunner {\r\n const effectFn: ReactiveEffect = function () {\r\n cleanup(effectFn);\r\n activeEffect = effectFn;\r\n fn();\r\n activeEffect = null;\r\n } as ReactiveEffect;\r\n\r\n effectFn.deps = [];\r\n effectFn();\r\n\r\n // Return the effect as a runner with a stop method\r\n const runner = (() => effectFn()) as EffectRunner;\r\n runner.stop = () => cleanup(effectFn);\r\n return runner;\r\n}\r\n\r\n/**\r\n * Create a reactive effect that re-runs whenever its tracked dependencies change.\r\n * Returns a runner with a `.stop()` method to dispose the effect.\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const runner = effect(() => console.log(count.value));\r\n * count.value++; // logs: 1\r\n * runner.stop();\r\n * ```\r\n */\r\nexport function effect(fn: EffectFn): EffectRunner {\r\n return runEffect(fn);\r\n}\r\n\r\n/**\r\n * Execute a function without tracking any reactive dependencies.\r\n * Useful for reading signals inside an effect without creating a subscription.\r\n *\r\n * @example\r\n * ```ts\r\n * effect(() => {\r\n * const val = untrack(() => someSignal.value); // not tracked\r\n * });\r\n * ```\r\n */\r\nexport function untrack<T>(fn: () => T): T {\r\n const prev = activeEffect;\r\n activeEffect = null;\r\n try {\r\n return fn();\r\n } finally {\r\n activeEffect = prev;\r\n }\r\n}\r\n\r\n/**\r\n * Create an effect scope that collects reactive effects for bulk disposal.\r\n *\r\n * @example\r\n * ```ts\r\n * const scope = effectScope();\r\n * scope.run(() => {\r\n * effect(() => console.log(count.value));\r\n * effect(() => console.log(name.value));\r\n * });\r\n * scope.stop(); // disposes both effects\r\n * ```\r\n */\r\nexport function effectScope(_detached?: boolean): {\r\n run<T>(fn: () => T): T | undefined;\r\n stop(fromParent?: boolean): void;\r\n} {\r\n const effects: (() => void)[] = [];\r\n let active = true;\r\n\r\n return {\r\n run<T>(fn: () => T): T | undefined {\r\n if (!active) return undefined;\r\n return fn();\r\n },\r\n stop() {\r\n active = false;\r\n effects.forEach(e => e());\r\n }\r\n };\r\n}\r\n"],"mappings":"AAMA,IAAW,eAAsC;AACjD,IAAI,aAAa;AACjB,IAAM,iCAAiB,IAAI,KAAqB;AAEhD,SAAgB,gBAAgB,QAAqC;AACjE,gBAAe;;AAGnB,SAAgB,kBAAyC;AACrD,QAAO;;AAeX,SAAgB,MAAM,IAAgB;AAClC;AACA,KAAI;AACA,MAAI;WACE;AACN;AACA,MAAI,eAAe,GAAG;GAClB,MAAM,UAAU,MAAM,KAAK,eAAe;AAC1C,kBAAe,OAAO;AACtB,QAAK,MAAM,UAAU,QACjB,SAAQ;;;;AAMxB,SAAgB,QAAQ,QAA8B;AAClD,KAAI,CAAC,OAAO,KAAM;AAClB,MAAK,MAAM,OAAO,OAAO,KACrB,KAAI,OAAO,OAAO;AAEtB,QAAO,KAAK,SAAS;;AAGzB,SAAgB,MAAM,QAAmC;AACrD,KAAI,CAAC,aAAc;AACnB,QAAO,IAAI,aAAa;AACxB,cAAa,KAAK,KAAK,OAAO;;AAGlC,SAAgB,QAAQ,QAAmC;CACvD,MAAM,UAAU,MAAM,KAAK,OAAO;AAClC,MAAK,MAAM,UAAU,QACjB,KAAI,aAAa,EACb,gBAAe,IAAI,OAAO;KAE1B,SAAQ;;AAKpB,SAAS,UAAU,IAA4B;CAC3C,MAAM,WAA2B,WAAY;AACzC,UAAQ,SAAS;AACjB,iBAAe;AACf,MAAI;AACJ,iBAAe;;AAGnB,UAAS,OAAO,EAAE;AAClB,WAAU;CAGV,MAAM,gBAAgB,UAAU;AAChC,QAAO,aAAa,QAAQ,SAAS;AACrC,QAAO;;AAeX,SAAgB,OAAO,IAA4B;AAC/C,QAAO,UAAU,GAAG;;AAcxB,SAAgB,QAAW,IAAgB;CACvC,MAAM,OAAO;AACb,gBAAe;AACf,KAAI;AACA,SAAO,IAAI;WACL;AACN,iBAAe;;;AAiBvB,SAAgB,YAAY,WAG1B;CACE,MAAM,UAA0B,EAAE;CAClC,IAAI,SAAS;AAEb,QAAO;EACH,IAAO,IAA4B;AAC/B,OAAI,CAAC,OAAQ,QAAO,KAAA;AACpB,UAAO,IAAI;;EAEf,OAAO;AACH,YAAS;AACT,WAAQ,SAAQ,MAAK,GAAG,CAAC;;EAEhC"}
package/dist/effect.d.ts CHANGED
@@ -2,13 +2,61 @@ import type { EffectFn, EffectRunner, ReactiveEffect } from './types';
2
2
  export declare let activeEffect: ReactiveEffect | null;
3
3
  export declare function setActiveEffect(effect: ReactiveEffect | null): void;
4
4
  export declare function getActiveEffect(): ReactiveEffect | null;
5
+ /**
6
+ * Batch multiple reactive updates into a single flush.
7
+ * Effects are deferred until the batch completes, avoiding redundant re-renders.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * batch(() => {
12
+ * count.value++;
13
+ * name.value = 'Alice';
14
+ * }); // effects run once after both updates
15
+ * ```
16
+ */
5
17
  export declare function batch(fn: () => void): void;
6
18
  export declare function cleanup(effect: ReactiveEffect): void;
7
19
  export declare function track(depSet: Set<ReactiveEffect>): void;
8
20
  export declare function trigger(depSet: Set<ReactiveEffect>): void;
21
+ /**
22
+ * Create a reactive effect that re-runs whenever its tracked dependencies change.
23
+ * Returns a runner with a `.stop()` method to dispose the effect.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const count = signal(0);
28
+ * const runner = effect(() => console.log(count.value));
29
+ * count.value++; // logs: 1
30
+ * runner.stop();
31
+ * ```
32
+ */
9
33
  export declare function effect(fn: EffectFn): EffectRunner;
34
+ /**
35
+ * Execute a function without tracking any reactive dependencies.
36
+ * Useful for reading signals inside an effect without creating a subscription.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * effect(() => {
41
+ * const val = untrack(() => someSignal.value); // not tracked
42
+ * });
43
+ * ```
44
+ */
10
45
  export declare function untrack<T>(fn: () => T): T;
11
- export declare function effectScope(detached?: boolean): {
46
+ /**
47
+ * Create an effect scope that collects reactive effects for bulk disposal.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const scope = effectScope();
52
+ * scope.run(() => {
53
+ * effect(() => console.log(count.value));
54
+ * effect(() => console.log(name.value));
55
+ * });
56
+ * scope.stop(); // disposes both effects
57
+ * ```
58
+ */
59
+ export declare function effectScope(_detached?: boolean): {
12
60
  run<T>(fn: () => T): T | undefined;
13
61
  stop(fromParent?: boolean): void;
14
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEtE,eAAO,IAAI,YAAY,EAAE,cAAc,GAAG,IAAW,CAAC;AAItD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAEnE;AAED,wBAAgB,eAAe,IAAI,cAAc,GAAG,IAAI,CAEvD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,QAcnC;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAMpD;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI,CAIvD;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI,CASzD;AAmBD,wBAAgB,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAEjD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAQzC;AAED,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG;IAC7C,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACpC,CAcA"}
1
+ {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEtE,eAAO,IAAI,YAAY,EAAE,cAAc,GAAG,IAAW,CAAC;AAItD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAEnE;AAED,wBAAgB,eAAe,IAAI,cAAc,GAAG,IAAI,CAEvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,QAcnC;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAMpD;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI,CAIvD;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI,CASzD;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAQzC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;IAC9C,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACpC,CAcA"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export type { EffectFn, EffectRunner, ReactiveEffect, Widen, Signal, PrimitiveSignal, Primitive, WatchSource, WatchCallback, WatchOptions, WatchHandle, Computed, WritableComputed, ComputedGetter, ComputedSetter, WritableComputedOptions, EffectScope } from './types';
2
2
  export { ComputedSymbol } from './types';
3
- export { effect, batch, untrack, effectScope, track, trigger, cleanup } from './effect';
3
+ export { effect, batch, untrack, effectScope } from './effect';
4
4
  export { toRaw, isReactive } from './collections';
5
5
  export { signal, detectAccess } from './signal';
6
6
  export { watch } from './watch';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,YAAY,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,KAAK,EACL,MAAM,EACN,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,WAAW,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EACH,MAAM,EACN,KAAK,EACL,OAAO,EACP,WAAW,EACX,KAAK,EACL,OAAO,EACP,OAAO,EACV,MAAM,UAAU,CAAC;AAGlB,OAAO,EACH,KAAK,EACL,UAAU,EACb,MAAM,eAAe,CAAC;AAGvB,OAAO,EACH,MAAM,EACN,YAAY,EACf,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,YAAY,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,KAAK,EACL,MAAM,EACN,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,WAAW,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EACH,MAAM,EACN,KAAK,EACL,OAAO,EACP,WAAW,EACd,MAAM,UAAU,CAAC;AAGlB,OAAO,EACH,KAAK,EACL,UAAU,EACb,MAAM,eAAe,CAAC;AAGvB,OAAO,EACH,MAAM,EACN,YAAY,EACf,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,80 +1,5 @@
1
+ import { a as getActiveEffect, c as trigger, i as effectScope, l as untrack, n as cleanup, o as setActiveEffect, r as effect, s as track, t as batch } from "./effect-DeSl7uNB.js";
1
2
  const ComputedSymbol = Symbol("computed");
2
- let activeEffect = null;
3
- var batchDepth = 0;
4
- var pendingEffects = /* @__PURE__ */ new Set();
5
- function setActiveEffect(effect) {
6
- activeEffect = effect;
7
- }
8
- function getActiveEffect() {
9
- return activeEffect;
10
- }
11
- function batch(fn) {
12
- batchDepth++;
13
- try {
14
- fn();
15
- } finally {
16
- batchDepth--;
17
- if (batchDepth === 0) {
18
- const effects = Array.from(pendingEffects);
19
- pendingEffects.clear();
20
- for (const effect of effects) effect();
21
- }
22
- }
23
- }
24
- function cleanup(effect) {
25
- if (!effect.deps) return;
26
- for (const dep of effect.deps) dep.delete(effect);
27
- effect.deps.length = 0;
28
- }
29
- function track(depSet) {
30
- if (!activeEffect) return;
31
- depSet.add(activeEffect);
32
- activeEffect.deps.push(depSet);
33
- }
34
- function trigger(depSet) {
35
- const effects = Array.from(depSet);
36
- for (const effect of effects) if (batchDepth > 0) pendingEffects.add(effect);
37
- else effect();
38
- }
39
- function runEffect(fn) {
40
- const effectFn = function() {
41
- cleanup(effectFn);
42
- activeEffect = effectFn;
43
- fn();
44
- activeEffect = null;
45
- };
46
- effectFn.deps = [];
47
- effectFn();
48
- const runner = (() => effectFn());
49
- runner.stop = () => cleanup(effectFn);
50
- return runner;
51
- }
52
- function effect(fn) {
53
- return runEffect(fn);
54
- }
55
- function untrack(fn) {
56
- const prev = activeEffect;
57
- activeEffect = null;
58
- try {
59
- return fn();
60
- } finally {
61
- activeEffect = prev;
62
- }
63
- }
64
- function effectScope(detached) {
65
- const effects = [];
66
- let active = true;
67
- return {
68
- run(fn) {
69
- if (!active) return void 0;
70
- return fn();
71
- },
72
- stop() {
73
- active = false;
74
- effects.forEach((e) => e());
75
- }
76
- };
77
- }
78
3
  const ITERATE_KEY = Symbol("iterate");
79
4
  const reactiveToRaw = /* @__PURE__ */ new WeakMap();
80
5
  const rawToReactive = /* @__PURE__ */ new WeakMap();
@@ -543,6 +468,6 @@ function computed(getterOrOptions) {
543
468
  function isComputed(value) {
544
469
  return value !== null && typeof value === "object" && ComputedSymbol in value;
545
470
  }
546
- export { ComputedSymbol, batch, cleanup, computed, detectAccess, effect, effectScope, isComputed, isReactive, signal, toRaw, track, trigger, untrack, watch };
471
+ export { ComputedSymbol, batch, computed, detectAccess, effect, effectScope, isComputed, isReactive, signal, toRaw, untrack, watch };
547
472
 
548
473
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/types.ts","../src/effect.ts","../src/collections.ts","../src/signal.ts","../src/watch.ts","../src/computed.ts"],"sourcesContent":["// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\n/** Symbol to identify computed values */\r\nexport const ComputedSymbol: unique symbol = Symbol('computed');\r\n\r\nexport type EffectFn = () => void;\r\n\r\nexport interface EffectRunner<T = void> {\r\n (): T;\r\n stop: () => void;\r\n}\r\n\r\nexport interface ReactiveEffect extends EffectFn {\r\n deps: Set<ReactiveEffect>[];\r\n}\r\n\r\n/** \r\n * Widens literal types to their base primitive types.\r\n * e.g., `false` → `boolean`, `\"hello\"` → `string`, `123` → `number`\r\n */\r\nexport type Widen<T> = \r\n T extends boolean ? boolean :\r\n T extends number ? number :\r\n T extends string ? string :\r\n T extends bigint ? bigint :\r\n T extends symbol ? symbol :\r\n T;\r\n\r\n/** Type for object/array signals - includes $set for replacing the whole object */\r\nexport type Signal<T> = T & {\r\n $set: (newValue: T) => void;\r\n};\r\n\r\n/** Type for primitive values that get wrapped in { value: T } - no $set, use .value instead */\r\nexport type PrimitiveSignal<T> = { value: Widen<T> };\r\n\r\n/** Primitive types that will be wrapped in { value: T } */\r\nexport type Primitive = string | number | boolean | symbol | bigint | null | undefined;\r\n\r\n// Watch types\r\nexport type WatchSource<T = any> = T | (() => T);\r\nexport type WatchCallback<V = any, OV = any> = (value: V, oldValue: OV, onCleanup: (fn: () => void) => void) => any;\r\n\r\nexport interface WatchOptions<Immediate = boolean> {\r\n immediate?: Immediate;\r\n deep?: boolean | number;\r\n once?: boolean;\r\n}\r\n\r\nexport interface WatchHandle {\r\n (): void; // callable to stop\r\n stop: () => void;\r\n pause: () => void;\r\n resume: () => void;\r\n}\r\n\r\n// Computed types\r\n/** A read-only computed signal - access via .value */\r\nexport interface Computed<T> {\r\n readonly value: T;\r\n readonly [ComputedSymbol]: true;\r\n}\r\n\r\n/** A writable computed signal - access and set via .value */\r\nexport interface WritableComputed<T> {\r\n value: T;\r\n readonly [ComputedSymbol]: true;\r\n}\r\n\r\nexport interface ComputedGetter<T> {\r\n (): T;\r\n}\r\n\r\nexport interface ComputedSetter<T> {\r\n (value: T): void;\r\n}\r\n\r\nexport interface WritableComputedOptions<T> {\r\n get: ComputedGetter<T>;\r\n set: ComputedSetter<T>;\r\n}\r\n\r\n// Effect scope types\r\nexport type EffectScope = {\r\n run<T>(fn: () => T): T | undefined;\r\n stop(fromParent?: boolean): void;\r\n}\r\n","// ============================================================================\r\n// Effect System - Core reactivity primitives\r\n// ============================================================================\r\n\r\nimport type { EffectFn, EffectRunner, ReactiveEffect } from './types';\r\n\r\nexport let activeEffect: ReactiveEffect | null = null;\r\nlet batchDepth = 0;\r\nconst pendingEffects = new Set<ReactiveEffect>();\r\n\r\nexport function setActiveEffect(effect: ReactiveEffect | null): void {\r\n activeEffect = effect;\r\n}\r\n\r\nexport function getActiveEffect(): ReactiveEffect | null {\r\n return activeEffect;\r\n}\r\n\r\nexport function batch(fn: () => void) {\r\n batchDepth++;\r\n try {\r\n fn();\r\n } finally {\r\n batchDepth--;\r\n if (batchDepth === 0) {\r\n const effects = Array.from(pendingEffects);\r\n pendingEffects.clear();\r\n for (const effect of effects) {\r\n effect();\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function cleanup(effect: ReactiveEffect): void {\r\n if (!effect.deps) return;\r\n for (const dep of effect.deps) {\r\n dep.delete(effect);\r\n }\r\n effect.deps.length = 0;\r\n}\r\n\r\nexport function track(depSet: Set<ReactiveEffect>): void {\r\n if (!activeEffect) return;\r\n depSet.add(activeEffect);\r\n activeEffect.deps.push(depSet);\r\n}\r\n\r\nexport function trigger(depSet: Set<ReactiveEffect>): void {\r\n const effects = Array.from(depSet);\r\n for (const effect of effects) {\r\n if (batchDepth > 0) {\r\n pendingEffects.add(effect);\r\n } else {\r\n effect();\r\n }\r\n }\r\n}\r\n\r\nfunction runEffect(fn: EffectFn): EffectRunner {\r\n const effectFn: ReactiveEffect = function () {\r\n cleanup(effectFn);\r\n activeEffect = effectFn;\r\n fn();\r\n activeEffect = null;\r\n } as ReactiveEffect;\r\n\r\n effectFn.deps = [];\r\n effectFn();\r\n\r\n // Return the effect as a runner with a stop method\r\n const runner = (() => effectFn()) as EffectRunner;\r\n runner.stop = () => cleanup(effectFn);\r\n return runner;\r\n}\r\n\r\nexport function effect(fn: EffectFn): EffectRunner {\r\n return runEffect(fn);\r\n}\r\n\r\nexport function untrack<T>(fn: () => T): T {\r\n const prev = activeEffect;\r\n activeEffect = null;\r\n try {\r\n return fn();\r\n } finally {\r\n activeEffect = prev;\r\n }\r\n}\r\n\r\nexport function effectScope(detached?: boolean): {\r\n run<T>(fn: () => T): T | undefined;\r\n stop(fromParent?: boolean): void;\r\n} {\r\n const effects: (() => void)[] = [];\r\n let active = true;\r\n\r\n return {\r\n run<T>(fn: () => T): T | undefined {\r\n if (!active) return undefined;\r\n return fn();\r\n },\r\n stop() {\r\n active = false;\r\n effects.forEach(e => e());\r\n }\r\n };\r\n}\r\n","// ============================================================================\r\n// Collection Reactivity Support (Set, Map, WeakSet, WeakMap)\r\n// ============================================================================\r\n\r\nimport type { ReactiveEffect } from './types';\r\nimport { track, trigger } from './effect';\r\n\r\n/** Symbol for tracking iteration dependencies (forEach, keys, values, entries, size) */\r\nexport const ITERATE_KEY = Symbol('iterate');\r\n\r\n/** WeakMap to get raw object from reactive proxy */\r\nexport const reactiveToRaw = new WeakMap<object, object>();\r\n\r\n/** WeakMap to get reactive proxy from raw object */\r\nexport const rawToReactive = new WeakMap<object, object>();\r\n\r\n/**\r\n * Returns the raw, original object from a reactive proxy.\r\n * If the value is not a proxy, returns it as-is.\r\n */\r\nexport function toRaw<T>(observed: T): T {\r\n const raw = reactiveToRaw.get(observed as object);\r\n return raw ? toRaw(raw as T) : observed;\r\n}\r\n\r\n/**\r\n * Checks if a value is a reactive proxy created by signal().\r\n */\r\nexport function isReactive(value: unknown): boolean {\r\n return reactiveToRaw.has(value as object);\r\n}\r\n\r\n/**\r\n * Checks if a value is a collection type (Set, Map, WeakSet, WeakMap).\r\n */\r\nexport function isCollection(value: unknown): value is Map<any, any> | Set<any> | WeakMap<any, any> | WeakSet<any> {\r\n if (!value || typeof value !== 'object') return false;\r\n const ctor = value.constructor;\r\n return ctor === Set || ctor === Map || ctor === WeakSet || ctor === WeakMap;\r\n}\r\n\r\n/**\r\n * Checks if a value is an iterable collection (Set or Map, not Weak variants).\r\n */\r\nexport function isIterableCollection(value: unknown): value is Map<any, any> | Set<any> {\r\n if (!value || typeof value !== 'object') return false;\r\n const ctor = value.constructor;\r\n return ctor === Set || ctor === Map;\r\n}\r\n\r\n/**\r\n * Checks if a value is an \"exotic\" built-in object that should NOT be proxied.\r\n * These objects have internal slots that cannot be accessed through Proxy.\r\n * Proxying them causes errors like \"Method X called on incompatible receiver\".\r\n */\r\nexport function shouldNotProxy(value: unknown): boolean {\r\n if (!value || typeof value !== 'object') return false;\r\n \r\n // Check against constructors of built-ins with internal slots\r\n const proto = Object.prototype.toString.call(value);\r\n \r\n // Built-ins that should not be proxied\r\n const nonProxyable = [\r\n '[object Date]',\r\n '[object RegExp]',\r\n '[object Error]',\r\n '[object Promise]',\r\n '[object ArrayBuffer]',\r\n '[object DataView]',\r\n '[object Int8Array]',\r\n '[object Uint8Array]',\r\n '[object Uint8ClampedArray]',\r\n '[object Int16Array]',\r\n '[object Uint16Array]',\r\n '[object Int32Array]',\r\n '[object Uint32Array]',\r\n '[object Float32Array]',\r\n '[object Float64Array]',\r\n '[object BigInt64Array]',\r\n '[object BigUint64Array]'\r\n ];\r\n \r\n return nonProxyable.includes(proto);\r\n}\r\n\r\n/**\r\n * Creates instrumented collection methods that properly handle reactivity.\r\n * These methods call the real collection methods on the raw object while\r\n * tracking dependencies and triggering updates.\r\n */\r\nexport function createCollectionInstrumentations(\r\n depsMap: Map<string | symbol, Set<ReactiveEffect>>,\r\n getOrCreateDep: (key: string | symbol) => Set<ReactiveEffect>\r\n) {\r\n const instrumentations: Record<string | symbol, any> = {};\r\n\r\n // ---- READ METHODS (track dependencies) ----\r\n\r\n // has() - works on Set, Map, WeakSet, WeakMap\r\n instrumentations.has = function (this: any, key: unknown): boolean {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n track(getOrCreateDep(rawKey as string | symbol));\r\n return target.has(rawKey);\r\n };\r\n\r\n // get() - works on Map, WeakMap\r\n instrumentations.get = function (this: any, key: unknown): any {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n track(getOrCreateDep(rawKey as string | symbol));\r\n const value = target.get(rawKey);\r\n // Make the returned value reactive if it's an object\r\n if (value && typeof value === 'object') {\r\n return rawToReactive.get(value) || value;\r\n }\r\n return value;\r\n };\r\n\r\n // size - works on Set, Map (not WeakSet, WeakMap)\r\n Object.defineProperty(instrumentations, 'size', {\r\n get(this: any) {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n return target.size;\r\n }\r\n });\r\n\r\n // forEach() - works on Set, Map\r\n instrumentations.forEach = function (this: any, callback: Function, thisArg?: unknown): void {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n target.forEach((value: any, key: any) => {\r\n // Make values reactive when iterating\r\n const reactiveValue = (value && typeof value === 'object') \r\n ? (rawToReactive.get(value) || value) \r\n : value;\r\n const reactiveKey = (key && typeof key === 'object') \r\n ? (rawToReactive.get(key) || key) \r\n : key;\r\n callback.call(thisArg, reactiveValue, reactiveKey, this);\r\n });\r\n };\r\n\r\n // keys() - works on Set, Map\r\n instrumentations.keys = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.keys();\r\n return createReactiveIterator(innerIterator, false);\r\n };\r\n\r\n // values() - works on Set, Map\r\n instrumentations.values = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.values();\r\n return createReactiveIterator(innerIterator, true);\r\n };\r\n\r\n // entries() - works on Set, Map\r\n instrumentations.entries = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.entries();\r\n return createReactiveEntriesIterator(innerIterator);\r\n };\r\n\r\n // [Symbol.iterator] - works on Set, Map\r\n instrumentations[Symbol.iterator] = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n // Set uses values(), Map uses entries() for default iterator\r\n if (target instanceof Set) {\r\n return createReactiveIterator(target.values(), true);\r\n } else {\r\n return createReactiveEntriesIterator(target.entries());\r\n }\r\n };\r\n\r\n // ---- WRITE METHODS (trigger updates) ----\r\n\r\n // add() - works on Set, WeakSet\r\n instrumentations.add = function (this: any, value: unknown): any {\r\n const target = toRaw(this);\r\n const rawValue = toRaw(value);\r\n const hadKey = target.has(rawValue);\r\n target.add(rawValue);\r\n if (!hadKey) {\r\n // Trigger both the specific key and iteration\r\n const dep = depsMap.get(rawValue as string | symbol);\r\n if (dep) trigger(dep);\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n return this; // Return the proxy, not raw\r\n };\r\n\r\n // set() - works on Map, WeakMap\r\n instrumentations.set = function (this: any, key: unknown, value: unknown): any {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n const rawValue = toRaw(value);\r\n const hadKey = target.has(rawKey);\r\n const oldValue = target.get(rawKey);\r\n target.set(rawKey, rawValue);\r\n if (!hadKey) {\r\n // New key - trigger iteration\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n if (!hadKey || !Object.is(oldValue, rawValue)) {\r\n // Value changed - trigger key dependency\r\n const dep = depsMap.get(rawKey as string | symbol);\r\n if (dep) trigger(dep);\r\n }\r\n return this; // Return the proxy, not raw\r\n };\r\n\r\n // delete() - works on Set, Map, WeakSet, WeakMap\r\n instrumentations.delete = function (this: any, key: unknown): boolean {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n const hadKey = target.has(rawKey);\r\n const result = target.delete(rawKey);\r\n if (hadKey) {\r\n // Trigger both the specific key and iteration\r\n const dep = depsMap.get(rawKey as string | symbol);\r\n if (dep) trigger(dep);\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n return result;\r\n };\r\n\r\n // clear() - works on Set, Map\r\n instrumentations.clear = function (this: any): void {\r\n const target = toRaw(this);\r\n const hadItems = target.size > 0;\r\n target.clear();\r\n if (hadItems) {\r\n // Trigger all dependencies\r\n for (const dep of depsMap.values()) {\r\n trigger(dep);\r\n }\r\n }\r\n };\r\n\r\n return instrumentations;\r\n}\r\n\r\n/**\r\n * Creates a reactive iterator that wraps values in reactive proxies.\r\n */\r\nfunction createReactiveIterator(innerIterator: IterableIterator<any>, wrapValues: boolean): IterableIterator<any> {\r\n return {\r\n next() {\r\n const { value, done } = innerIterator.next();\r\n if (done) {\r\n return { value: undefined, done: true };\r\n }\r\n const wrappedValue = wrapValues && value && typeof value === 'object'\r\n ? (rawToReactive.get(value) || value)\r\n : value;\r\n return { value: wrappedValue, done: false };\r\n },\r\n [Symbol.iterator]() {\r\n return this;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a reactive entries iterator that wraps both keys and values.\r\n */\r\nfunction createReactiveEntriesIterator(innerIterator: IterableIterator<[any, any]>): IterableIterator<[any, any]> {\r\n return {\r\n next() {\r\n const { value, done } = innerIterator.next();\r\n if (done) {\r\n return { value: undefined, done: true };\r\n }\r\n const [key, val] = value;\r\n const wrappedKey = key && typeof key === 'object' ? (rawToReactive.get(key) || key) : key;\r\n const wrappedVal = val && typeof val === 'object' ? (rawToReactive.get(val) || val) : val;\r\n return { value: [wrappedKey, wrappedVal] as [any, any], done: false };\r\n },\r\n [Symbol.iterator]() {\r\n return this;\r\n }\r\n };\r\n}\r\n","// ============================================================================\r\n// Signal - Reactive state primitives\r\n// ============================================================================\r\n\r\nimport type { ReactiveEffect, Signal, PrimitiveSignal, Primitive } from './types';\r\nimport { batch, track, trigger } from './effect';\r\nimport { \r\n isReactive, \r\n isCollection, \r\n isIterableCollection, \r\n shouldNotProxy,\r\n reactiveToRaw,\r\n rawToReactive,\r\n createCollectionInstrumentations,\r\n ITERATE_KEY\r\n} from './collections';\r\n\r\n/** Check if a value is a primitive type */\r\nfunction isPrimitive(value: unknown): value is Primitive {\r\n if (value === null || value === undefined) return true;\r\n const type = typeof value;\r\n return type === 'string' || type === 'number' || type === 'boolean' || type === 'symbol' || type === 'bigint';\r\n}\r\n\r\nlet accessObserver: ((target: any, key: string | symbol) => void) | null = null;\r\n\r\n/** @internal Get the current access observer for computed/model integration */\r\nexport function getAccessObserver(): ((target: any, key: string | symbol) => void) | null {\r\n return accessObserver;\r\n}\r\n\r\n/** @internal Temporarily suspend the access observer (used by computed to prevent leakage) */\r\nexport function setAccessObserver(observer: ((target: any, key: string | symbol) => void) | null): void {\r\n accessObserver = observer;\r\n}\r\n\r\nexport function detectAccess(selector: () => any): [any, string | symbol] | null {\r\n let result: [any, string | symbol] | null = null;\r\n const prev = accessObserver;\r\n\r\n // Capture the LAST access in the property chain\r\n // For nested paths like state.form.displayName, this gives [state.form, \"displayName\"]\r\n // Computed getters suspend the observer before evaluating, preventing leakage\r\n accessObserver = (target, key) => {\r\n result = [target, key];\r\n };\r\n\r\n try {\r\n selector();\r\n } finally {\r\n accessObserver = prev;\r\n }\r\n\r\n return result;\r\n}\r\n\r\nconst arrayInstrumentations: Record<string, Function> = {};\r\n['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {\r\n arrayInstrumentations[method] = function (this: any, ...args: any[]) {\r\n let res;\r\n batch(() => {\r\n res = (Array.prototype as any)[method].apply(this, args);\r\n });\r\n return res;\r\n };\r\n});\r\n\r\n// Overload for primitive types - wraps in { value: T }, no $set (use .value instead)\r\nexport function signal<T extends Primitive>(target: T): PrimitiveSignal<T>;\r\n// Overload for object types - includes $set for replacing the whole object\r\nexport function signal<T extends object>(target: T): Signal<T>;\r\n// Implementation\r\nexport function signal<T>(target: T): PrimitiveSignal<T> | Signal<T & object> {\r\n // Handle primitive types by wrapping in { value: T }\r\n if (isPrimitive(target)) {\r\n return signal({ value: target }) as unknown as PrimitiveSignal<T>;\r\n }\r\n\r\n const objectTarget = target as T & object;\r\n\r\n // Skip exotic built-ins that can't be proxied (Date, RegExp, etc.)\r\n // These have internal slots and will throw errors if proxied\r\n if (shouldNotProxy(objectTarget)) {\r\n return objectTarget as Signal<T & object>;\r\n }\r\n\r\n // Check if already reactive\r\n if (isReactive(objectTarget)) {\r\n return objectTarget as Signal<T & object>;\r\n }\r\n\r\n // Check if we already have a reactive version of this raw object\r\n const existingProxy = rawToReactive.get(objectTarget);\r\n if (existingProxy) {\r\n return existingProxy as Signal<T & object>;\r\n }\r\n\r\n const depsMap = new Map<string | symbol, Set<ReactiveEffect>>();\r\n const reactiveCache = new WeakMap<object, any>();\r\n\r\n // Helper to get or create a dependency set for a key\r\n const getOrCreateDep = (key: string | symbol): Set<ReactiveEffect> => {\r\n let dep = depsMap.get(key);\r\n if (!dep) {\r\n dep = new Set<ReactiveEffect>();\r\n depsMap.set(key, dep);\r\n }\r\n return dep;\r\n };\r\n\r\n // Create collection instrumentations if this is a collection\r\n const collectionInstrumentations = isCollection(objectTarget) \r\n ? createCollectionInstrumentations(depsMap, getOrCreateDep)\r\n : null;\r\n\r\n const proxy = new Proxy(objectTarget, {\r\n get(obj, prop, receiver) {\r\n if (prop === '$set') {\r\n return (newValue: T & object) => {\r\n batch(() => {\r\n if (Array.isArray(obj) && Array.isArray(newValue)) {\r\n const len = newValue.length;\r\n for (let i = 0; i < len; i++) {\r\n Reflect.set(receiver, String(i), newValue[i]);\r\n }\r\n Reflect.set(receiver, 'length', len);\r\n } else {\r\n const newKeys = Object.keys(newValue);\r\n const oldKeys = Object.keys(obj);\r\n for (const key of newKeys) {\r\n Reflect.set(receiver, key, (newValue as any)[key]);\r\n }\r\n for (const key of oldKeys) {\r\n if (!(key in newValue)) {\r\n Reflect.deleteProperty(receiver, key);\r\n }\r\n }\r\n }\r\n });\r\n };\r\n }\r\n\r\n // Handle collection instrumentations (Set, Map, WeakSet, WeakMap)\r\n if (collectionInstrumentations) {\r\n // Special handling for 'size' getter\r\n if (prop === 'size' && isIterableCollection(obj)) {\r\n track(getOrCreateDep(ITERATE_KEY));\r\n return (obj as Set<any> | Map<any, any>).size;\r\n }\r\n \r\n // Check if this is an instrumented method\r\n if (prop in collectionInstrumentations) {\r\n const instrumented = collectionInstrumentations[prop];\r\n if (typeof instrumented === 'function') {\r\n return instrumented.bind(receiver);\r\n }\r\n return instrumented;\r\n }\r\n }\r\n\r\n if (Array.isArray(obj) && typeof prop === 'string' && arrayInstrumentations.hasOwnProperty(prop)) {\r\n return arrayInstrumentations[prop];\r\n }\r\n\r\n const value = Reflect.get(obj, prop);\r\n\r\n if (accessObserver) {\r\n accessObserver(receiver, prop);\r\n }\r\n\r\n // Track this property access (skip for collections - they use instrumentations)\r\n if (!collectionInstrumentations) {\r\n const dep = getOrCreateDep(prop);\r\n track(dep);\r\n }\r\n\r\n // If the value is an object, make it reactive too (with caching)\r\n // Skip exotic built-ins like Date, RegExp, etc. that have internal slots\r\n if (value && typeof value === 'object' && !shouldNotProxy(value)) {\r\n let cached = reactiveCache.get(value);\r\n if (!cached) {\r\n cached = signal(value);\r\n reactiveCache.set(value, cached);\r\n }\r\n return cached;\r\n }\r\n\r\n return value;\r\n },\r\n set(obj, prop, newValue) {\r\n const oldLength = Array.isArray(obj) ? obj.length : 0;\r\n const oldValue = Reflect.get(obj, prop);\r\n const result = Reflect.set(obj, prop, newValue);\r\n\r\n // Only trigger if value actually changed\r\n if (!Object.is(oldValue, newValue)) {\r\n const dep = depsMap.get(prop);\r\n if (dep) {\r\n trigger(dep);\r\n }\r\n\r\n // Special handling for Arrays\r\n if (Array.isArray(obj)) {\r\n // If we set an index and length changed, trigger length dependency\r\n if (prop !== 'length' && obj.length !== oldLength) {\r\n const lengthDep = depsMap.get('length');\r\n if (lengthDep) {\r\n trigger(lengthDep);\r\n }\r\n }\r\n // If we set length, trigger indices that are now out of bounds\r\n if (prop === 'length' && typeof newValue === 'number' && newValue < oldLength) {\r\n for (let i = newValue; i < oldLength; i++) {\r\n const idxDep = depsMap.get(String(i));\r\n if (idxDep) trigger(idxDep);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n },\r\n deleteProperty(obj, prop) {\r\n const hasKey = Object.prototype.hasOwnProperty.call(obj, prop);\r\n const result = Reflect.deleteProperty(obj, prop);\r\n\r\n if (result && hasKey) {\r\n const dep = depsMap.get(prop);\r\n if (dep) {\r\n trigger(dep);\r\n }\r\n }\r\n return result;\r\n }\r\n }) as Signal<T & object>;\r\n\r\n // Store the raw ↔ reactive mappings\r\n reactiveToRaw.set(proxy, objectTarget);\r\n rawToReactive.set(objectTarget, proxy);\r\n\r\n return proxy;\r\n}\r\n","// ============================================================================\r\n// Watch - Reactive watchers with cleanup and options\r\n// ============================================================================\r\n\r\nimport type { WatchSource, WatchCallback, WatchOptions, WatchHandle } from './types';\r\nimport { effect } from './effect';\r\n\r\n/**\r\n * Deeply traverses an object to trigger reactive tracking on all nested properties.\r\n * @param value The value to traverse\r\n * @param depth Maximum depth to traverse (Infinity for unlimited, number for limited)\r\n * @param seen Set of already visited objects to prevent circular references\r\n */\r\nfunction traverse(value: unknown, depth: number = Infinity, seen: Set<unknown> = new Set()): unknown {\r\n // Don't traverse primitives, null, or if we've exceeded depth\r\n if (depth <= 0) return value;\r\n if (value === null || typeof value !== 'object') return value;\r\n \r\n // Prevent circular references\r\n if (seen.has(value)) return value;\r\n seen.add(value);\r\n \r\n if (Array.isArray(value)) {\r\n // Traverse array elements\r\n for (let i = 0; i < value.length; i++) {\r\n traverse(value[i], depth - 1, seen);\r\n }\r\n } else if (value instanceof Map) {\r\n // Traverse Map entries\r\n value.forEach((v, k) => {\r\n traverse(k, depth - 1, seen);\r\n traverse(v, depth - 1, seen);\r\n });\r\n } else if (value instanceof Set) {\r\n // Traverse Set values\r\n value.forEach(v => {\r\n traverse(v, depth - 1, seen);\r\n });\r\n } else {\r\n // Traverse object properties\r\n for (const key of Object.keys(value)) {\r\n traverse((value as Record<string, unknown>)[key], depth - 1, seen);\r\n }\r\n }\r\n \r\n return value;\r\n}\r\n\r\nexport function watch<T>(source: WatchSource<T>, cb: WatchCallback<T>, options?: WatchOptions): WatchHandle {\r\n let oldValue: T | undefined;\r\n let isFirst = true;\r\n let cleanupFn: (() => void) | null = null;\r\n let paused = false;\r\n let pendingValue: T | undefined;\r\n let hasPending = false;\r\n let stopped = false;\r\n\r\n // Determine traverse depth from deep option\r\n const deep = options?.deep;\r\n const traverseDepth = deep === true ? Infinity : (typeof deep === 'number' ? deep : 0);\r\n\r\n const runner = effect(() => {\r\n if (stopped) return;\r\n \r\n let newValue = typeof source === 'function' ? (source as () => T)() : source;\r\n \r\n // If deep watching, traverse the value to track nested properties\r\n if (traverseDepth > 0) {\r\n traverse(newValue, traverseDepth);\r\n }\r\n\r\n if (paused) {\r\n // Store pending value to process on resume\r\n pendingValue = newValue;\r\n hasPending = true;\r\n return;\r\n }\r\n\r\n if (isFirst) {\r\n if (options?.immediate) {\r\n if (cleanupFn) cleanupFn();\r\n cb(newValue, oldValue, (fn) => cleanupFn = fn);\r\n // If once option, stop after immediate callback\r\n if (options?.once) {\r\n stopped = true;\r\n // Schedule stop for next tick to allow effect to complete\r\n queueMicrotask(() => stop());\r\n }\r\n }\r\n isFirst = false;\r\n } else {\r\n if (cleanupFn) cleanupFn();\r\n cb(newValue, oldValue, (fn) => cleanupFn = fn);\r\n // If once option, stop after first callback\r\n if (options?.once) {\r\n stopped = true;\r\n // Schedule stop for next tick to allow effect to complete\r\n queueMicrotask(() => stop());\r\n }\r\n }\r\n oldValue = newValue;\r\n });\r\n\r\n const stop = () => {\r\n stopped = true;\r\n runner.stop();\r\n if (cleanupFn) cleanupFn();\r\n };\r\n\r\n const pause = () => {\r\n paused = true;\r\n };\r\n\r\n const resume = () => {\r\n if (!paused) return;\r\n paused = false;\r\n // If value changed while paused, trigger callback now\r\n if (hasPending && !Object.is(pendingValue, oldValue)) {\r\n if (cleanupFn) cleanupFn();\r\n cb(pendingValue as T, oldValue, (fn) => cleanupFn = fn);\r\n oldValue = pendingValue;\r\n }\r\n hasPending = false;\r\n pendingValue = undefined;\r\n };\r\n\r\n return Object.assign(stop, { stop, pause, resume });\r\n}\r\n","// ============================================================================\r\n// Computed Signals - Lazy, cached, reactive derived values\r\n// ============================================================================\r\n\r\nimport type { \r\n ReactiveEffect, \r\n Computed, \r\n WritableComputed, \r\n ComputedGetter, \r\n ComputedSetter, \r\n WritableComputedOptions \r\n} from './types';\r\nimport { ComputedSymbol } from './types';\r\nimport { cleanup, track, trigger, setActiveEffect, getActiveEffect } from './effect';\r\nimport { getAccessObserver, setAccessObserver } from './signal';\r\n\r\n/**\r\n * Creates a computed signal that lazily derives a value from other reactive sources.\r\n * \r\n * Performance characteristics:\r\n * - Lazy: Only computes when accessed\r\n * - Cached: Returns cached value if dependencies haven't changed\r\n * - Minimal overhead: Uses dirty flag instead of always running getter\r\n * \r\n * @example\r\n * ```ts\r\n * const count = signal({ n: 0 });\r\n * const doubled = computed(() => count.n * 2);\r\n * \r\n * console.log(doubled.value); // 0\r\n * count.n = 5;\r\n * console.log(doubled.value); // 10\r\n * ```\r\n */\r\nexport function computed<T>(getter: ComputedGetter<T>): Computed<T>;\r\nexport function computed<T>(options: WritableComputedOptions<T>): WritableComputed<T>;\r\nexport function computed<T>(\r\n getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>\r\n): Computed<T> | WritableComputed<T> {\r\n let getter: ComputedGetter<T>;\r\n let setter: ComputedSetter<T> | undefined;\r\n\r\n if (typeof getterOrOptions === 'function') {\r\n getter = getterOrOptions;\r\n } else {\r\n getter = getterOrOptions.get;\r\n setter = getterOrOptions.set;\r\n }\r\n\r\n const subscribers = new Set<ReactiveEffect>();\r\n let cachedValue: T;\r\n let dirty = true;\r\n\r\n // Internal effect for dependency tracking\r\n const computedEffect: ReactiveEffect = function () {\r\n if (!dirty) {\r\n dirty = true;\r\n trigger(subscribers);\r\n }\r\n } as ReactiveEffect;\r\n computedEffect.deps = [];\r\n\r\n const computeValue = (): T => {\r\n cleanup(computedEffect);\r\n const prevEffect = getActiveEffect();\r\n setActiveEffect(computedEffect);\r\n try {\r\n cachedValue = getter();\r\n dirty = false;\r\n return cachedValue;\r\n } finally {\r\n setActiveEffect(prevEffect);\r\n }\r\n };\r\n\r\n // The computed object with .value accessor\r\n const computedObj = {\r\n [ComputedSymbol]: true as const,\r\n get value(): T {\r\n // Notify access observer for model binding integration (detectAccess)\r\n const observer = getAccessObserver();\r\n if (observer) {\r\n observer(computedObj, 'value');\r\n // Suspend observer so computeValue's internal signal reads don't leak\r\n setAccessObserver(null);\r\n }\r\n track(subscribers);\r\n const result = dirty ? computeValue() : cachedValue;\r\n // Restore observer after compute\r\n if (observer) setAccessObserver(observer);\r\n return result;\r\n },\r\n };\r\n\r\n // Add setter if provided (writable computed)\r\n if (setter) {\r\n Object.defineProperty(computedObj, 'value', {\r\n get(): T {\r\n // Notify access observer for model binding integration (detectAccess)\r\n const observer = getAccessObserver();\r\n if (observer) {\r\n observer(computedObj, 'value');\r\n // Suspend observer so computeValue's internal signal reads don't leak\r\n setAccessObserver(null);\r\n }\r\n track(subscribers);\r\n const result = dirty ? computeValue() : cachedValue;\r\n // Restore observer after compute\r\n if (observer) setAccessObserver(observer);\r\n return result;\r\n },\r\n set(newValue: T) {\r\n setter!(newValue);\r\n },\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n return computedObj as WritableComputed<T>;\r\n }\r\n\r\n return computedObj as Computed<T>;\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is a computed signal.\r\n * \r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * console.log(isComputed(doubled)); // true\r\n * console.log(isComputed({ value: 1 })); // false\r\n * ```\r\n */\r\nexport function isComputed(value: unknown): value is Computed<unknown> {\r\n return value !== null && typeof value === 'object' && ComputedSymbol in value;\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/types.ts","../src/collections.ts","../src/signal.ts","../src/watch.ts","../src/computed.ts"],"sourcesContent":["// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\n/** Symbol to identify computed values */\r\nexport const ComputedSymbol: unique symbol = Symbol('computed');\r\n\r\nexport type EffectFn = () => void;\r\n\r\nexport interface EffectRunner<T = void> {\r\n (): T;\r\n stop: () => void;\r\n}\r\n\r\nexport interface ReactiveEffect extends EffectFn {\r\n deps: Set<ReactiveEffect>[];\r\n}\r\n\r\n/** \r\n * Widens literal types to their base primitive types.\r\n * e.g., `false` → `boolean`, `\"hello\"` → `string`, `123` → `number`\r\n */\r\nexport type Widen<T> = \r\n T extends boolean ? boolean :\r\n T extends number ? number :\r\n T extends string ? string :\r\n T extends bigint ? bigint :\r\n T extends symbol ? symbol :\r\n T;\r\n\r\n/** Type for object/array signals - includes $set for replacing the whole object */\r\nexport type Signal<T> = T & {\r\n $set: (newValue: T) => void;\r\n};\r\n\r\n/** Type for primitive values that get wrapped in { value: T } - no $set, use .value instead */\r\nexport type PrimitiveSignal<T> = { value: Widen<T> };\r\n\r\n/** Primitive types that will be wrapped in { value: T } */\r\nexport type Primitive = string | number | boolean | symbol | bigint | null | undefined;\r\n\r\n// Watch types\r\nexport type WatchSource<T = any> = T | (() => T);\r\nexport type WatchCallback<V = any, OV = any> = (value: V, oldValue: OV, onCleanup: (fn: () => void) => void) => any;\r\n\r\nexport interface WatchOptions<Immediate = boolean> {\r\n immediate?: Immediate;\r\n deep?: boolean | number;\r\n once?: boolean;\r\n}\r\n\r\nexport interface WatchHandle {\r\n (): void; // callable to stop\r\n stop: () => void;\r\n pause: () => void;\r\n resume: () => void;\r\n}\r\n\r\n// Computed types\r\n/** A read-only computed signal - access via .value */\r\nexport interface Computed<T> {\r\n readonly value: T;\r\n readonly [ComputedSymbol]: true;\r\n}\r\n\r\n/** A writable computed signal - access and set via .value */\r\nexport interface WritableComputed<T> {\r\n value: T;\r\n readonly [ComputedSymbol]: true;\r\n}\r\n\r\nexport interface ComputedGetter<T> {\r\n (): T;\r\n}\r\n\r\nexport interface ComputedSetter<T> {\r\n (value: T): void;\r\n}\r\n\r\nexport interface WritableComputedOptions<T> {\r\n get: ComputedGetter<T>;\r\n set: ComputedSetter<T>;\r\n}\r\n\r\n// Effect scope types\r\nexport type EffectScope = {\r\n run<T>(fn: () => T): T | undefined;\r\n stop(fromParent?: boolean): void;\r\n}\r\n","// ============================================================================\r\n// Collection Reactivity Support (Set, Map, WeakSet, WeakMap)\r\n// ============================================================================\r\n\r\nimport type { ReactiveEffect } from './types';\r\nimport { track, trigger } from './effect';\r\n\r\n/** Symbol for tracking iteration dependencies (forEach, keys, values, entries, size) */\r\nexport const ITERATE_KEY = Symbol('iterate');\r\n\r\n/** WeakMap to get raw object from reactive proxy */\r\nexport const reactiveToRaw = new WeakMap<object, object>();\r\n\r\n/** WeakMap to get reactive proxy from raw object */\r\nexport const rawToReactive = new WeakMap<object, object>();\r\n\r\n/**\r\n * Returns the raw, original object from a reactive proxy.\r\n * If the value is not a proxy, returns it as-is.\r\n */\r\nexport function toRaw<T>(observed: T): T {\r\n const raw = reactiveToRaw.get(observed as object);\r\n return raw ? toRaw(raw as T) : observed;\r\n}\r\n\r\n/**\r\n * Checks if a value is a reactive proxy created by signal().\r\n */\r\nexport function isReactive(value: unknown): boolean {\r\n return reactiveToRaw.has(value as object);\r\n}\r\n\r\n/**\r\n * Checks if a value is a collection type (Set, Map, WeakSet, WeakMap).\r\n */\r\nexport function isCollection(value: unknown): value is Map<any, any> | Set<any> | WeakMap<any, any> | WeakSet<any> {\r\n if (!value || typeof value !== 'object') return false;\r\n const ctor = value.constructor;\r\n return ctor === Set || ctor === Map || ctor === WeakSet || ctor === WeakMap;\r\n}\r\n\r\n/**\r\n * Checks if a value is an iterable collection (Set or Map, not Weak variants).\r\n */\r\nexport function isIterableCollection(value: unknown): value is Map<any, any> | Set<any> {\r\n if (!value || typeof value !== 'object') return false;\r\n const ctor = value.constructor;\r\n return ctor === Set || ctor === Map;\r\n}\r\n\r\n/**\r\n * Checks if a value is an \"exotic\" built-in object that should NOT be proxied.\r\n * These objects have internal slots that cannot be accessed through Proxy.\r\n * Proxying them causes errors like \"Method X called on incompatible receiver\".\r\n */\r\nexport function shouldNotProxy(value: unknown): boolean {\r\n if (!value || typeof value !== 'object') return false;\r\n \r\n // Check against constructors of built-ins with internal slots\r\n const proto = Object.prototype.toString.call(value);\r\n \r\n // Built-ins that should not be proxied\r\n const nonProxyable = [\r\n '[object Date]',\r\n '[object RegExp]',\r\n '[object Error]',\r\n '[object Promise]',\r\n '[object ArrayBuffer]',\r\n '[object DataView]',\r\n '[object Int8Array]',\r\n '[object Uint8Array]',\r\n '[object Uint8ClampedArray]',\r\n '[object Int16Array]',\r\n '[object Uint16Array]',\r\n '[object Int32Array]',\r\n '[object Uint32Array]',\r\n '[object Float32Array]',\r\n '[object Float64Array]',\r\n '[object BigInt64Array]',\r\n '[object BigUint64Array]'\r\n ];\r\n \r\n return nonProxyable.includes(proto);\r\n}\r\n\r\n/**\r\n * Creates instrumented collection methods that properly handle reactivity.\r\n * These methods call the real collection methods on the raw object while\r\n * tracking dependencies and triggering updates.\r\n */\r\nexport function createCollectionInstrumentations(\r\n depsMap: Map<string | symbol, Set<ReactiveEffect>>,\r\n getOrCreateDep: (key: string | symbol) => Set<ReactiveEffect>\r\n) {\r\n const instrumentations: Record<string | symbol, any> = {};\r\n\r\n // ---- READ METHODS (track dependencies) ----\r\n\r\n // has() - works on Set, Map, WeakSet, WeakMap\r\n instrumentations.has = function (this: any, key: unknown): boolean {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n track(getOrCreateDep(rawKey as string | symbol));\r\n return target.has(rawKey);\r\n };\r\n\r\n // get() - works on Map, WeakMap\r\n instrumentations.get = function (this: any, key: unknown): any {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n track(getOrCreateDep(rawKey as string | symbol));\r\n const value = target.get(rawKey);\r\n // Make the returned value reactive if it's an object\r\n if (value && typeof value === 'object') {\r\n return rawToReactive.get(value) || value;\r\n }\r\n return value;\r\n };\r\n\r\n // size - works on Set, Map (not WeakSet, WeakMap)\r\n Object.defineProperty(instrumentations, 'size', {\r\n get(this: any) {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n return target.size;\r\n }\r\n });\r\n\r\n // forEach() - works on Set, Map\r\n instrumentations.forEach = function (this: any, callback: Function, thisArg?: unknown): void {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n target.forEach((value: any, key: any) => {\r\n // Make values reactive when iterating\r\n const reactiveValue = (value && typeof value === 'object') \r\n ? (rawToReactive.get(value) || value) \r\n : value;\r\n const reactiveKey = (key && typeof key === 'object') \r\n ? (rawToReactive.get(key) || key) \r\n : key;\r\n callback.call(thisArg, reactiveValue, reactiveKey, this);\r\n });\r\n };\r\n\r\n // keys() - works on Set, Map\r\n instrumentations.keys = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.keys();\r\n return createReactiveIterator(innerIterator, false);\r\n };\r\n\r\n // values() - works on Set, Map\r\n instrumentations.values = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.values();\r\n return createReactiveIterator(innerIterator, true);\r\n };\r\n\r\n // entries() - works on Set, Map\r\n instrumentations.entries = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n const innerIterator = target.entries();\r\n return createReactiveEntriesIterator(innerIterator);\r\n };\r\n\r\n // [Symbol.iterator] - works on Set, Map\r\n instrumentations[Symbol.iterator] = function (this: any): IterableIterator<any> {\r\n const target = toRaw(this);\r\n track(getOrCreateDep(ITERATE_KEY));\r\n // Set uses values(), Map uses entries() for default iterator\r\n if (target instanceof Set) {\r\n return createReactiveIterator(target.values(), true);\r\n } else {\r\n return createReactiveEntriesIterator(target.entries());\r\n }\r\n };\r\n\r\n // ---- WRITE METHODS (trigger updates) ----\r\n\r\n // add() - works on Set, WeakSet\r\n instrumentations.add = function (this: any, value: unknown): any {\r\n const target = toRaw(this);\r\n const rawValue = toRaw(value);\r\n const hadKey = target.has(rawValue);\r\n target.add(rawValue);\r\n if (!hadKey) {\r\n // Trigger both the specific key and iteration\r\n const dep = depsMap.get(rawValue as string | symbol);\r\n if (dep) trigger(dep);\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n return this; // Return the proxy, not raw\r\n };\r\n\r\n // set() - works on Map, WeakMap\r\n instrumentations.set = function (this: any, key: unknown, value: unknown): any {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n const rawValue = toRaw(value);\r\n const hadKey = target.has(rawKey);\r\n const oldValue = target.get(rawKey);\r\n target.set(rawKey, rawValue);\r\n if (!hadKey) {\r\n // New key - trigger iteration\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n if (!hadKey || !Object.is(oldValue, rawValue)) {\r\n // Value changed - trigger key dependency\r\n const dep = depsMap.get(rawKey as string | symbol);\r\n if (dep) trigger(dep);\r\n }\r\n return this; // Return the proxy, not raw\r\n };\r\n\r\n // delete() - works on Set, Map, WeakSet, WeakMap\r\n instrumentations.delete = function (this: any, key: unknown): boolean {\r\n const target = toRaw(this);\r\n const rawKey = toRaw(key);\r\n const hadKey = target.has(rawKey);\r\n const result = target.delete(rawKey);\r\n if (hadKey) {\r\n // Trigger both the specific key and iteration\r\n const dep = depsMap.get(rawKey as string | symbol);\r\n if (dep) trigger(dep);\r\n const iterDep = depsMap.get(ITERATE_KEY);\r\n if (iterDep) trigger(iterDep);\r\n }\r\n return result;\r\n };\r\n\r\n // clear() - works on Set, Map\r\n instrumentations.clear = function (this: any): void {\r\n const target = toRaw(this);\r\n const hadItems = target.size > 0;\r\n target.clear();\r\n if (hadItems) {\r\n // Trigger all dependencies\r\n for (const dep of depsMap.values()) {\r\n trigger(dep);\r\n }\r\n }\r\n };\r\n\r\n return instrumentations;\r\n}\r\n\r\n/**\r\n * Creates a reactive iterator that wraps values in reactive proxies.\r\n */\r\nfunction createReactiveIterator(innerIterator: IterableIterator<any>, wrapValues: boolean): IterableIterator<any> {\r\n return {\r\n next() {\r\n const { value, done } = innerIterator.next();\r\n if (done) {\r\n return { value: undefined, done: true };\r\n }\r\n const wrappedValue = wrapValues && value && typeof value === 'object'\r\n ? (rawToReactive.get(value) || value)\r\n : value;\r\n return { value: wrappedValue, done: false };\r\n },\r\n [Symbol.iterator]() {\r\n return this;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a reactive entries iterator that wraps both keys and values.\r\n */\r\nfunction createReactiveEntriesIterator(innerIterator: IterableIterator<[any, any]>): IterableIterator<[any, any]> {\r\n return {\r\n next() {\r\n const { value, done } = innerIterator.next();\r\n if (done) {\r\n return { value: undefined, done: true };\r\n }\r\n const [key, val] = value;\r\n const wrappedKey = key && typeof key === 'object' ? (rawToReactive.get(key) || key) : key;\r\n const wrappedVal = val && typeof val === 'object' ? (rawToReactive.get(val) || val) : val;\r\n return { value: [wrappedKey, wrappedVal] as [any, any], done: false };\r\n },\r\n [Symbol.iterator]() {\r\n return this;\r\n }\r\n };\r\n}\r\n","// ============================================================================\r\n// Signal - Reactive state primitives\r\n// ============================================================================\r\n\r\nimport type { ReactiveEffect, Signal, PrimitiveSignal, Primitive } from './types';\r\nimport { batch, track, trigger } from './effect';\r\nimport { \r\n isReactive, \r\n isCollection, \r\n isIterableCollection, \r\n shouldNotProxy,\r\n reactiveToRaw,\r\n rawToReactive,\r\n createCollectionInstrumentations,\r\n ITERATE_KEY\r\n} from './collections';\r\n\r\n/** Check if a value is a primitive type */\r\nfunction isPrimitive(value: unknown): value is Primitive {\r\n if (value === null || value === undefined) return true;\r\n const type = typeof value;\r\n return type === 'string' || type === 'number' || type === 'boolean' || type === 'symbol' || type === 'bigint';\r\n}\r\n\r\nlet accessObserver: ((target: any, key: string | symbol) => void) | null = null;\r\n\r\n/** @internal Get the current access observer for computed/model integration */\r\nexport function getAccessObserver(): ((target: any, key: string | symbol) => void) | null {\r\n return accessObserver;\r\n}\r\n\r\n/** @internal Temporarily suspend the access observer (used by computed to prevent leakage) */\r\nexport function setAccessObserver(observer: ((target: any, key: string | symbol) => void) | null): void {\r\n accessObserver = observer;\r\n}\r\n\r\nexport function detectAccess(selector: () => any): [any, string | symbol] | null {\r\n let result: [any, string | symbol] | null = null;\r\n const prev = accessObserver;\r\n\r\n // Capture the LAST access in the property chain\r\n // For nested paths like state.form.displayName, this gives [state.form, \"displayName\"]\r\n // Computed getters suspend the observer before evaluating, preventing leakage\r\n accessObserver = (target, key) => {\r\n result = [target, key];\r\n };\r\n\r\n try {\r\n selector();\r\n } finally {\r\n accessObserver = prev;\r\n }\r\n\r\n return result;\r\n}\r\n\r\nconst arrayInstrumentations: Record<string, Function> = {};\r\n['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {\r\n arrayInstrumentations[method] = function (this: any, ...args: any[]) {\r\n let res;\r\n batch(() => {\r\n res = (Array.prototype as any)[method].apply(this, args);\r\n });\r\n return res;\r\n };\r\n});\r\n\r\n// Overload for primitive types - wraps in { value: T }, no $set (use .value instead)\r\n/**\r\n * Create a reactive signal from a value.\r\n *\r\n * For primitives, wraps the value as `{ value: T }` — access and mutate via `.value`.\r\n * For objects, returns a deeply reactive proxy with `.$set()` for full replacement.\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * count.value++;\r\n *\r\n * const user = signal({ name: 'Alice' });\r\n * user.name = 'Bob'; // reactive\r\n * user.$set({ name: 'Carol' }); // replace entire object\r\n * ```\r\n */\r\nexport function signal<T extends Primitive>(target: T): PrimitiveSignal<T>;\r\n// Overload for object types - includes $set for replacing the whole object\r\nexport function signal<T extends object>(target: T): Signal<T>;\r\n// Implementation\r\nexport function signal<T>(target: T): PrimitiveSignal<T> | Signal<T & object> {\r\n // Handle primitive types by wrapping in { value: T }\r\n if (isPrimitive(target)) {\r\n return signal({ value: target }) as unknown as PrimitiveSignal<T>;\r\n }\r\n\r\n const objectTarget = target as T & object;\r\n\r\n // Skip exotic built-ins that can't be proxied (Date, RegExp, etc.)\r\n // These have internal slots and will throw errors if proxied\r\n if (shouldNotProxy(objectTarget)) {\r\n return objectTarget as Signal<T & object>;\r\n }\r\n\r\n // Check if already reactive\r\n if (isReactive(objectTarget)) {\r\n return objectTarget as Signal<T & object>;\r\n }\r\n\r\n // Check if we already have a reactive version of this raw object\r\n const existingProxy = rawToReactive.get(objectTarget);\r\n if (existingProxy) {\r\n return existingProxy as Signal<T & object>;\r\n }\r\n\r\n const depsMap = new Map<string | symbol, Set<ReactiveEffect>>();\r\n const reactiveCache = new WeakMap<object, any>();\r\n\r\n // Helper to get or create a dependency set for a key\r\n const getOrCreateDep = (key: string | symbol): Set<ReactiveEffect> => {\r\n let dep = depsMap.get(key);\r\n if (!dep) {\r\n dep = new Set<ReactiveEffect>();\r\n depsMap.set(key, dep);\r\n }\r\n return dep;\r\n };\r\n\r\n // Create collection instrumentations if this is a collection\r\n const collectionInstrumentations = isCollection(objectTarget) \r\n ? createCollectionInstrumentations(depsMap, getOrCreateDep)\r\n : null;\r\n\r\n const proxy = new Proxy(objectTarget, {\r\n get(obj, prop, receiver) {\r\n if (prop === '$set') {\r\n return (newValue: T & object) => {\r\n batch(() => {\r\n if (Array.isArray(obj) && Array.isArray(newValue)) {\r\n const len = newValue.length;\r\n for (let i = 0; i < len; i++) {\r\n Reflect.set(receiver, String(i), newValue[i]);\r\n }\r\n Reflect.set(receiver, 'length', len);\r\n } else {\r\n const newKeys = Object.keys(newValue);\r\n const oldKeys = Object.keys(obj);\r\n for (const key of newKeys) {\r\n Reflect.set(receiver, key, (newValue as any)[key]);\r\n }\r\n for (const key of oldKeys) {\r\n if (!(key in newValue)) {\r\n Reflect.deleteProperty(receiver, key);\r\n }\r\n }\r\n }\r\n });\r\n };\r\n }\r\n\r\n // Handle collection instrumentations (Set, Map, WeakSet, WeakMap)\r\n if (collectionInstrumentations) {\r\n // Special handling for 'size' getter\r\n if (prop === 'size' && isIterableCollection(obj)) {\r\n track(getOrCreateDep(ITERATE_KEY));\r\n return (obj as Set<any> | Map<any, any>).size;\r\n }\r\n \r\n // Check if this is an instrumented method\r\n if (prop in collectionInstrumentations) {\r\n const instrumented = collectionInstrumentations[prop];\r\n if (typeof instrumented === 'function') {\r\n return instrumented.bind(receiver);\r\n }\r\n return instrumented;\r\n }\r\n }\r\n\r\n if (Array.isArray(obj) && typeof prop === 'string' && arrayInstrumentations.hasOwnProperty(prop)) {\r\n return arrayInstrumentations[prop];\r\n }\r\n\r\n const value = Reflect.get(obj, prop);\r\n\r\n if (accessObserver) {\r\n accessObserver(receiver, prop);\r\n }\r\n\r\n // Track this property access (skip for collections - they use instrumentations)\r\n if (!collectionInstrumentations) {\r\n const dep = getOrCreateDep(prop);\r\n track(dep);\r\n }\r\n\r\n // If the value is an object, make it reactive too (with caching)\r\n // Skip exotic built-ins like Date, RegExp, etc. that have internal slots\r\n if (value && typeof value === 'object' && !shouldNotProxy(value)) {\r\n let cached = reactiveCache.get(value);\r\n if (!cached) {\r\n cached = signal(value);\r\n reactiveCache.set(value, cached);\r\n }\r\n return cached;\r\n }\r\n\r\n return value;\r\n },\r\n set(obj, prop, newValue) {\r\n const oldLength = Array.isArray(obj) ? obj.length : 0;\r\n const oldValue = Reflect.get(obj, prop);\r\n const result = Reflect.set(obj, prop, newValue);\r\n\r\n // Only trigger if value actually changed\r\n if (!Object.is(oldValue, newValue)) {\r\n const dep = depsMap.get(prop);\r\n if (dep) {\r\n trigger(dep);\r\n }\r\n\r\n // Special handling for Arrays\r\n if (Array.isArray(obj)) {\r\n // If we set an index and length changed, trigger length dependency\r\n if (prop !== 'length' && obj.length !== oldLength) {\r\n const lengthDep = depsMap.get('length');\r\n if (lengthDep) {\r\n trigger(lengthDep);\r\n }\r\n }\r\n // If we set length, trigger indices that are now out of bounds\r\n if (prop === 'length' && typeof newValue === 'number' && newValue < oldLength) {\r\n for (let i = newValue; i < oldLength; i++) {\r\n const idxDep = depsMap.get(String(i));\r\n if (idxDep) trigger(idxDep);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n },\r\n deleteProperty(obj, prop) {\r\n const hasKey = Object.prototype.hasOwnProperty.call(obj, prop);\r\n const result = Reflect.deleteProperty(obj, prop);\r\n\r\n if (result && hasKey) {\r\n const dep = depsMap.get(prop);\r\n if (dep) {\r\n trigger(dep);\r\n }\r\n }\r\n return result;\r\n }\r\n }) as Signal<T & object>;\r\n\r\n // Store the raw ↔ reactive mappings\r\n reactiveToRaw.set(proxy, objectTarget);\r\n rawToReactive.set(objectTarget, proxy);\r\n\r\n return proxy;\r\n}\r\n","// ============================================================================\r\n// Watch - Reactive watchers with cleanup and options\r\n// ============================================================================\r\n\r\nimport type { WatchSource, WatchCallback, WatchOptions, WatchHandle } from './types';\r\nimport { effect } from './effect';\r\n\r\n/**\r\n * Deeply traverses an object to trigger reactive tracking on all nested properties.\r\n * @param value The value to traverse\r\n * @param depth Maximum depth to traverse (Infinity for unlimited, number for limited)\r\n * @param seen Set of already visited objects to prevent circular references\r\n */\r\nfunction traverse(value: unknown, depth: number = Infinity, seen: Set<unknown> = new Set()): unknown {\r\n // Don't traverse primitives, null, or if we've exceeded depth\r\n if (depth <= 0) return value;\r\n if (value === null || typeof value !== 'object') return value;\r\n \r\n // Prevent circular references\r\n if (seen.has(value)) return value;\r\n seen.add(value);\r\n \r\n if (Array.isArray(value)) {\r\n // Traverse array elements\r\n for (let i = 0; i < value.length; i++) {\r\n traverse(value[i], depth - 1, seen);\r\n }\r\n } else if (value instanceof Map) {\r\n // Traverse Map entries\r\n value.forEach((v, k) => {\r\n traverse(k, depth - 1, seen);\r\n traverse(v, depth - 1, seen);\r\n });\r\n } else if (value instanceof Set) {\r\n // Traverse Set values\r\n value.forEach(v => {\r\n traverse(v, depth - 1, seen);\r\n });\r\n } else {\r\n // Traverse object properties\r\n for (const key of Object.keys(value)) {\r\n traverse((value as Record<string, unknown>)[key], depth - 1, seen);\r\n }\r\n }\r\n \r\n return value;\r\n}\r\n\r\n/**\r\n * Watch a reactive source and run a callback when it changes.\r\n * Supports deep watching, immediate invocation, and pause/resume.\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const handle = watch(() => count.value, (newVal, oldVal) => {\r\n * console.log(`${oldVal} → ${newVal}`);\r\n * });\r\n * handle.stop(); // stop watching\r\n * ```\r\n */\r\nexport function watch<T>(source: WatchSource<T>, cb: WatchCallback<T>, options?: WatchOptions): WatchHandle {\r\n let oldValue: T | undefined;\r\n let isFirst = true;\r\n let cleanupFn: (() => void) | null = null;\r\n let paused = false;\r\n let pendingValue: T | undefined;\r\n let hasPending = false;\r\n let stopped = false;\r\n\r\n // Determine traverse depth from deep option\r\n const deep = options?.deep;\r\n const traverseDepth = deep === true ? Infinity : (typeof deep === 'number' ? deep : 0);\r\n\r\n const runner = effect(() => {\r\n if (stopped) return;\r\n \r\n let newValue = typeof source === 'function' ? (source as () => T)() : source;\r\n \r\n // If deep watching, traverse the value to track nested properties\r\n if (traverseDepth > 0) {\r\n traverse(newValue, traverseDepth);\r\n }\r\n\r\n if (paused) {\r\n // Store pending value to process on resume\r\n pendingValue = newValue;\r\n hasPending = true;\r\n return;\r\n }\r\n\r\n if (isFirst) {\r\n if (options?.immediate) {\r\n if (cleanupFn) cleanupFn();\r\n cb(newValue, oldValue, (fn) => cleanupFn = fn);\r\n // If once option, stop after immediate callback\r\n if (options?.once) {\r\n stopped = true;\r\n // Schedule stop for next tick to allow effect to complete\r\n queueMicrotask(() => stop());\r\n }\r\n }\r\n isFirst = false;\r\n } else {\r\n if (cleanupFn) cleanupFn();\r\n cb(newValue, oldValue, (fn) => cleanupFn = fn);\r\n // If once option, stop after first callback\r\n if (options?.once) {\r\n stopped = true;\r\n // Schedule stop for next tick to allow effect to complete\r\n queueMicrotask(() => stop());\r\n }\r\n }\r\n oldValue = newValue;\r\n });\r\n\r\n const stop = () => {\r\n stopped = true;\r\n runner.stop();\r\n if (cleanupFn) cleanupFn();\r\n };\r\n\r\n const pause = () => {\r\n paused = true;\r\n };\r\n\r\n const resume = () => {\r\n if (!paused) return;\r\n paused = false;\r\n // If value changed while paused, trigger callback now\r\n if (hasPending && !Object.is(pendingValue, oldValue)) {\r\n if (cleanupFn) cleanupFn();\r\n cb(pendingValue as T, oldValue, (fn) => cleanupFn = fn);\r\n oldValue = pendingValue;\r\n }\r\n hasPending = false;\r\n pendingValue = undefined;\r\n };\r\n\r\n return Object.assign(stop, { stop, pause, resume });\r\n}\r\n","// ============================================================================\r\n// Computed Signals - Lazy, cached, reactive derived values\r\n// ============================================================================\r\n\r\nimport type { \r\n ReactiveEffect, \r\n Computed, \r\n WritableComputed, \r\n ComputedGetter, \r\n ComputedSetter, \r\n WritableComputedOptions \r\n} from './types';\r\nimport { ComputedSymbol } from './types';\r\nimport { cleanup, track, trigger, setActiveEffect, getActiveEffect } from './effect';\r\nimport { getAccessObserver, setAccessObserver } from './signal';\r\n\r\n/**\r\n * Creates a computed signal that lazily derives a value from other reactive sources.\r\n * \r\n * Performance characteristics:\r\n * - Lazy: Only computes when accessed\r\n * - Cached: Returns cached value if dependencies haven't changed\r\n * - Minimal overhead: Uses dirty flag instead of always running getter\r\n * \r\n * @example\r\n * ```ts\r\n * const count = signal({ n: 0 });\r\n * const doubled = computed(() => count.n * 2);\r\n * \r\n * console.log(doubled.value); // 0\r\n * count.n = 5;\r\n * console.log(doubled.value); // 10\r\n * ```\r\n */\r\nexport function computed<T>(getter: ComputedGetter<T>): Computed<T>;\r\nexport function computed<T>(options: WritableComputedOptions<T>): WritableComputed<T>;\r\nexport function computed<T>(\r\n getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>\r\n): Computed<T> | WritableComputed<T> {\r\n let getter: ComputedGetter<T>;\r\n let setter: ComputedSetter<T> | undefined;\r\n\r\n if (typeof getterOrOptions === 'function') {\r\n getter = getterOrOptions;\r\n } else {\r\n getter = getterOrOptions.get;\r\n setter = getterOrOptions.set;\r\n }\r\n\r\n const subscribers = new Set<ReactiveEffect>();\r\n let cachedValue: T;\r\n let dirty = true;\r\n\r\n // Internal effect for dependency tracking\r\n const computedEffect: ReactiveEffect = function () {\r\n if (!dirty) {\r\n dirty = true;\r\n trigger(subscribers);\r\n }\r\n } as ReactiveEffect;\r\n computedEffect.deps = [];\r\n\r\n const computeValue = (): T => {\r\n cleanup(computedEffect);\r\n const prevEffect = getActiveEffect();\r\n setActiveEffect(computedEffect);\r\n try {\r\n cachedValue = getter();\r\n dirty = false;\r\n return cachedValue;\r\n } finally {\r\n setActiveEffect(prevEffect);\r\n }\r\n };\r\n\r\n // The computed object with .value accessor\r\n const computedObj = {\r\n [ComputedSymbol]: true as const,\r\n get value(): T {\r\n // Notify access observer for model binding integration (detectAccess)\r\n const observer = getAccessObserver();\r\n if (observer) {\r\n observer(computedObj, 'value');\r\n // Suspend observer so computeValue's internal signal reads don't leak\r\n setAccessObserver(null);\r\n }\r\n track(subscribers);\r\n const result = dirty ? computeValue() : cachedValue;\r\n // Restore observer after compute\r\n if (observer) setAccessObserver(observer);\r\n return result;\r\n },\r\n };\r\n\r\n // Add setter if provided (writable computed)\r\n if (setter) {\r\n Object.defineProperty(computedObj, 'value', {\r\n get(): T {\r\n // Notify access observer for model binding integration (detectAccess)\r\n const observer = getAccessObserver();\r\n if (observer) {\r\n observer(computedObj, 'value');\r\n // Suspend observer so computeValue's internal signal reads don't leak\r\n setAccessObserver(null);\r\n }\r\n track(subscribers);\r\n const result = dirty ? computeValue() : cachedValue;\r\n // Restore observer after compute\r\n if (observer) setAccessObserver(observer);\r\n return result;\r\n },\r\n set(newValue: T) {\r\n setter!(newValue);\r\n },\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n return computedObj as WritableComputed<T>;\r\n }\r\n\r\n return computedObj as Computed<T>;\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is a computed signal.\r\n * \r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * console.log(isComputed(doubled)); // true\r\n * console.log(isComputed({ value: 1 })); // false\r\n * ```\r\n */\r\nexport function isComputed(value: unknown): value is Computed<unknown> {\r\n return value !== null && typeof value === 'object' && ComputedSymbol in value;\r\n}\r\n"],"mappings":";AAKA,MAAa,iBAAgC,OAAO,WAAW;ACG/D,MAAa,cAAc,OAAO,UAAU;AAG5C,MAAa,gCAAgB,IAAI,SAAyB;AAG1D,MAAa,gCAAgB,IAAI,SAAyB;AAM1D,SAAgB,MAAS,UAAgB;CACrC,MAAM,MAAM,cAAc,IAAI,SAAmB;AACjD,QAAO,MAAM,MAAM,IAAS,GAAG;;AAMnC,SAAgB,WAAW,OAAyB;AAChD,QAAO,cAAc,IAAI,MAAgB;;AAM7C,SAAgB,aAAa,OAAsF;AAC/G,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;CAChD,MAAM,OAAO,MAAM;AACnB,QAAO,SAAS,OAAO,SAAS,OAAO,SAAS,WAAW,SAAS;;AAMxE,SAAgB,qBAAqB,OAAmD;AACpF,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;CAChD,MAAM,OAAO,MAAM;AACnB,QAAO,SAAS,OAAO,SAAS;;AAQpC,SAAgB,eAAe,OAAyB;AACpD,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;CAGhD,MAAM,QAAQ,OAAO,UAAU,SAAS,KAAK,MAAM;AAuBnD,QApBqB;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH,CAEmB,SAAS,MAAM;;AAQvC,SAAgB,iCACZ,SACA,gBACF;CACE,MAAM,mBAAiD,EAAE;AAKzD,kBAAiB,MAAM,SAAqB,KAAuB;EAC/D,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,SAAS,MAAM,IAAI;AACzB,QAAM,eAAe,OAA0B,CAAC;AAChD,SAAO,OAAO,IAAI,OAAO;;AAI7B,kBAAiB,MAAM,SAAqB,KAAmB;EAC3D,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,SAAS,MAAM,IAAI;AACzB,QAAM,eAAe,OAA0B,CAAC;EAChD,MAAM,QAAQ,OAAO,IAAI,OAAO;AAEhC,MAAI,SAAS,OAAO,UAAU,SAC1B,QAAO,cAAc,IAAI,MAAM,IAAI;AAEvC,SAAO;;AAIX,QAAO,eAAe,kBAAkB,QAAQ,EAC5C,MAAe;EACX,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAClC,SAAO,OAAO;IAErB,CAAC;AAGF,kBAAiB,UAAU,SAAqB,UAAoB,SAAyB;EACzF,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAClC,SAAO,SAAS,OAAY,QAAa;GAErC,MAAM,gBAAiB,SAAS,OAAO,UAAU,WAC1C,cAAc,IAAI,MAAM,IAAI,QAC7B;GACN,MAAM,cAAe,OAAO,OAAO,QAAQ,WACpC,cAAc,IAAI,IAAI,IAAI,MAC3B;AACN,YAAS,KAAK,SAAS,eAAe,aAAa,KAAK;IAC1D;;AAIN,kBAAiB,OAAO,WAA4C;EAChE,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAElC,SAAO,uBADe,OAAO,MAAM,EACU,MAAM;;AAIvD,kBAAiB,SAAS,WAA4C;EAClE,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAElC,SAAO,uBADe,OAAO,QAAQ,EACQ,KAAK;;AAItD,kBAAiB,UAAU,WAA4C;EACnE,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAElC,SAAO,8BADe,OAAO,SAAS,CACa;;AAIvD,kBAAiB,OAAO,YAAY,WAA4C;EAC5E,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,eAAe,YAAY,CAAC;AAElC,MAAI,kBAAkB,IAClB,QAAO,uBAAuB,OAAO,QAAQ,EAAE,KAAK;MAEpD,QAAO,8BAA8B,OAAO,SAAS,CAAC;;AAO9D,kBAAiB,MAAM,SAAqB,OAAqB;EAC7D,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,WAAW,MAAM,MAAM;EAC7B,MAAM,SAAS,OAAO,IAAI,SAAS;AACnC,SAAO,IAAI,SAAS;AACpB,MAAI,CAAC,QAAQ;GAET,MAAM,MAAM,QAAQ,IAAI,SAA4B;AACpD,OAAI,IAAK,SAAQ,IAAI;GACrB,MAAM,UAAU,QAAQ,IAAI,YAAY;AACxC,OAAI,QAAS,SAAQ,QAAQ;;AAEjC,SAAO;;AAIX,kBAAiB,MAAM,SAAqB,KAAc,OAAqB;EAC3E,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,SAAS,MAAM,IAAI;EACzB,MAAM,WAAW,MAAM,MAAM;EAC7B,MAAM,SAAS,OAAO,IAAI,OAAO;EACjC,MAAM,WAAW,OAAO,IAAI,OAAO;AACnC,SAAO,IAAI,QAAQ,SAAS;AAC5B,MAAI,CAAC,QAAQ;GAET,MAAM,UAAU,QAAQ,IAAI,YAAY;AACxC,OAAI,QAAS,SAAQ,QAAQ;;AAEjC,MAAI,CAAC,UAAU,CAAC,OAAO,GAAG,UAAU,SAAS,EAAE;GAE3C,MAAM,MAAM,QAAQ,IAAI,OAA0B;AAClD,OAAI,IAAK,SAAQ,IAAI;;AAEzB,SAAO;;AAIX,kBAAiB,SAAS,SAAqB,KAAuB;EAClE,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,SAAS,MAAM,IAAI;EACzB,MAAM,SAAS,OAAO,IAAI,OAAO;EACjC,MAAM,SAAS,OAAO,OAAO,OAAO;AACpC,MAAI,QAAQ;GAER,MAAM,MAAM,QAAQ,IAAI,OAA0B;AAClD,OAAI,IAAK,SAAQ,IAAI;GACrB,MAAM,UAAU,QAAQ,IAAI,YAAY;AACxC,OAAI,QAAS,SAAQ,QAAQ;;AAEjC,SAAO;;AAIX,kBAAiB,QAAQ,WAA2B;EAChD,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,WAAW,OAAO,OAAO;AAC/B,SAAO,OAAO;AACd,MAAI,SAEA,MAAK,MAAM,OAAO,QAAQ,QAAQ,CAC9B,SAAQ,IAAI;;AAKxB,QAAO;;AAMX,SAAS,uBAAuB,eAAsC,YAA4C;AAC9G,QAAO;EACH,OAAO;GACH,MAAM,EAAE,OAAO,SAAS,cAAc,MAAM;AAC5C,OAAI,KACA,QAAO;IAAE,OAAO,KAAA;IAAW,MAAM;IAAM;AAK3C,UAAO;IAAE,OAHY,cAAc,SAAS,OAAO,UAAU,WACtD,cAAc,IAAI,MAAM,IAAI,QAC7B;IACwB,MAAM;IAAO;;EAE/C,CAAC,OAAO,YAAY;AAChB,UAAO;;EAEd;;AAML,SAAS,8BAA8B,eAA2E;AAC9G,QAAO;EACH,OAAO;GACH,MAAM,EAAE,OAAO,SAAS,cAAc,MAAM;AAC5C,OAAI,KACA,QAAO;IAAE,OAAO,KAAA;IAAW,MAAM;IAAM;GAE3C,MAAM,CAAC,KAAK,OAAO;AAGnB,UAAO;IAAE,OAAO,CAFG,OAAO,OAAO,QAAQ,WAAY,cAAc,IAAI,IAAI,IAAI,MAAO,KACnE,OAAO,OAAO,QAAQ,WAAY,cAAc,IAAI,IAAI,IAAI,MAAO,IAC9C;IAAgB,MAAM;IAAO;;EAEzE,CAAC,OAAO,YAAY;AAChB,UAAO;;EAEd;;AChRL,SAAS,YAAY,OAAoC;AACrD,KAAI,UAAU,QAAQ,UAAU,KAAA,EAAW,QAAO;CAClD,MAAM,OAAO,OAAO;AACpB,QAAO,SAAS,YAAY,SAAS,YAAY,SAAS,aAAa,SAAS,YAAY,SAAS;;AAGzG,IAAI,iBAAuE;AAG3E,SAAgB,oBAA0E;AACtF,QAAO;;AAIX,SAAgB,kBAAkB,UAAsE;AACpG,kBAAiB;;AAGrB,SAAgB,aAAa,UAAoD;CAC7E,IAAI,SAAwC;CAC5C,MAAM,OAAO;AAKb,mBAAkB,QAAQ,QAAQ;AAC9B,WAAS,CAAC,QAAQ,IAAI;;AAG1B,KAAI;AACA,YAAU;WACJ;AACN,mBAAiB;;AAGrB,QAAO;;AAGX,IAAM,wBAAkD,EAAE;AAC1D;CAAC;CAAQ;CAAO;CAAS;CAAW;CAAU;CAAQ;CAAU,CAAC,SAAQ,WAAU;AAC/E,uBAAsB,UAAU,SAAqB,GAAG,MAAa;EACjE,IAAI;AACJ,cAAY;AACR,SAAO,MAAM,UAAkB,QAAQ,MAAM,MAAM,KAAK;IAC1D;AACF,SAAO;;EAEb;AAuBF,SAAgB,OAAU,QAAoD;AAE1E,KAAI,YAAY,OAAO,CACnB,QAAO,OAAO,EAAE,OAAO,QAAQ,CAAC;CAGpC,MAAM,eAAe;AAIrB,KAAI,eAAe,aAAa,CAC5B,QAAO;AAIX,KAAI,WAAW,aAAa,CACxB,QAAO;CAIX,MAAM,gBAAgB,cAAc,IAAI,aAAa;AACrD,KAAI,cACA,QAAO;CAGX,MAAM,0BAAU,IAAI,KAA2C;CAC/D,MAAM,gCAAgB,IAAI,SAAsB;CAGhD,MAAM,kBAAkB,QAA8C;EAClE,IAAI,MAAM,QAAQ,IAAI,IAAI;AAC1B,MAAI,CAAC,KAAK;AACN,yBAAM,IAAI,KAAqB;AAC/B,WAAQ,IAAI,KAAK,IAAI;;AAEzB,SAAO;;CAIX,MAAM,6BAA6B,aAAa,aAAa,GACvD,iCAAiC,SAAS,eAAe,GACzD;CAEN,MAAM,QAAQ,IAAI,MAAM,cAAc;EAClC,IAAI,KAAK,MAAM,UAAU;AACrB,OAAI,SAAS,OACT,SAAQ,aAAyB;AAC7B,gBAAY;AACR,SAAI,MAAM,QAAQ,IAAI,IAAI,MAAM,QAAQ,SAAS,EAAE;MAC/C,MAAM,MAAM,SAAS;AACrB,WAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IACrB,SAAQ,IAAI,UAAU,OAAO,EAAE,EAAE,SAAS,GAAG;AAEjD,cAAQ,IAAI,UAAU,UAAU,IAAI;YACjC;MACH,MAAM,UAAU,OAAO,KAAK,SAAS;MACrC,MAAM,UAAU,OAAO,KAAK,IAAI;AAChC,WAAK,MAAM,OAAO,QACd,SAAQ,IAAI,UAAU,KAAM,SAAiB,KAAK;AAEtD,WAAK,MAAM,OAAO,QACd,KAAI,EAAE,OAAO,UACT,SAAQ,eAAe,UAAU,IAAI;;MAInD;;AAKV,OAAI,4BAA4B;AAE5B,QAAI,SAAS,UAAU,qBAAqB,IAAI,EAAE;AAC9C,WAAM,eAAe,YAAY,CAAC;AAClC,YAAQ,IAAiC;;AAI7C,QAAI,QAAQ,4BAA4B;KACpC,MAAM,eAAe,2BAA2B;AAChD,SAAI,OAAO,iBAAiB,WACxB,QAAO,aAAa,KAAK,SAAS;AAEtC,YAAO;;;AAIf,OAAI,MAAM,QAAQ,IAAI,IAAI,OAAO,SAAS,YAAY,sBAAsB,eAAe,KAAK,CAC5F,QAAO,sBAAsB;GAGjC,MAAM,QAAQ,QAAQ,IAAI,KAAK,KAAK;AAEpC,OAAI,eACA,gBAAe,UAAU,KAAK;AAIlC,OAAI,CAAC,2BAED,OADY,eAAe,KAAK,CACtB;AAKd,OAAI,SAAS,OAAO,UAAU,YAAY,CAAC,eAAe,MAAM,EAAE;IAC9D,IAAI,SAAS,cAAc,IAAI,MAAM;AACrC,QAAI,CAAC,QAAQ;AACT,cAAS,OAAO,MAAM;AACtB,mBAAc,IAAI,OAAO,OAAO;;AAEpC,WAAO;;AAGX,UAAO;;EAEX,IAAI,KAAK,MAAM,UAAU;GACrB,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,IAAI,SAAS;GACpD,MAAM,WAAW,QAAQ,IAAI,KAAK,KAAK;GACvC,MAAM,SAAS,QAAQ,IAAI,KAAK,MAAM,SAAS;AAG/C,OAAI,CAAC,OAAO,GAAG,UAAU,SAAS,EAAE;IAChC,MAAM,MAAM,QAAQ,IAAI,KAAK;AAC7B,QAAI,IACA,SAAQ,IAAI;AAIhB,QAAI,MAAM,QAAQ,IAAI,EAAE;AAEpB,SAAI,SAAS,YAAY,IAAI,WAAW,WAAW;MAC/C,MAAM,YAAY,QAAQ,IAAI,SAAS;AACvC,UAAI,UACA,SAAQ,UAAU;;AAI1B,SAAI,SAAS,YAAY,OAAO,aAAa,YAAY,WAAW,UAChE,MAAK,IAAI,IAAI,UAAU,IAAI,WAAW,KAAK;MACvC,MAAM,SAAS,QAAQ,IAAI,OAAO,EAAE,CAAC;AACrC,UAAI,OAAQ,SAAQ,OAAO;;;;AAM3C,UAAO;;EAEX,eAAe,KAAK,MAAM;GACtB,MAAM,SAAS,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK;GAC9D,MAAM,SAAS,QAAQ,eAAe,KAAK,KAAK;AAEhD,OAAI,UAAU,QAAQ;IAClB,MAAM,MAAM,QAAQ,IAAI,KAAK;AAC7B,QAAI,IACA,SAAQ,IAAI;;AAGpB,UAAO;;EAEd,CAAC;AAGF,eAAc,IAAI,OAAO,aAAa;AACtC,eAAc,IAAI,cAAc,MAAM;AAEtC,QAAO;;ACnPX,SAAS,SAAS,OAAgB,QAAgB,UAAU,uBAAqB,IAAI,KAAK,EAAW;AAEjG,KAAI,SAAS,EAAG,QAAO;AACvB,KAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AAGxD,KAAI,KAAK,IAAI,MAAM,CAAE,QAAO;AAC5B,MAAK,IAAI,MAAM;AAEf,KAAI,MAAM,QAAQ,MAAM,CAEpB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAC9B,UAAS,MAAM,IAAI,QAAQ,GAAG,KAAK;UAEhC,iBAAiB,IAExB,OAAM,SAAS,GAAG,MAAM;AACpB,WAAS,GAAG,QAAQ,GAAG,KAAK;AAC5B,WAAS,GAAG,QAAQ,GAAG,KAAK;GAC9B;UACK,iBAAiB,IAExB,OAAM,SAAQ,MAAK;AACf,WAAS,GAAG,QAAQ,GAAG,KAAK;GAC9B;KAGF,MAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CAChC,UAAU,MAAkC,MAAM,QAAQ,GAAG,KAAK;AAI1E,QAAO;;AAgBX,SAAgB,MAAS,QAAwB,IAAsB,SAAqC;CACxG,IAAI;CACJ,IAAI,UAAU;CACd,IAAI,YAAiC;CACrC,IAAI,SAAS;CACb,IAAI;CACJ,IAAI,aAAa;CACjB,IAAI,UAAU;CAGd,MAAM,OAAO,SAAS;CACtB,MAAM,gBAAgB,SAAS,OAAO,WAAY,OAAO,SAAS,WAAW,OAAO;CAEpF,MAAM,SAAS,aAAa;AACxB,MAAI,QAAS;EAEb,IAAI,WAAW,OAAO,WAAW,aAAc,QAAoB,GAAG;AAGtE,MAAI,gBAAgB,EAChB,UAAS,UAAU,cAAc;AAGrC,MAAI,QAAQ;AAER,kBAAe;AACf,gBAAa;AACb;;AAGJ,MAAI,SAAS;AACT,OAAI,SAAS,WAAW;AACpB,QAAI,UAAW,YAAW;AAC1B,OAAG,UAAU,WAAW,OAAO,YAAY,GAAG;AAE9C,QAAI,SAAS,MAAM;AACf,eAAU;AAEV,0BAAqB,MAAM,CAAC;;;AAGpC,aAAU;SACP;AACH,OAAI,UAAW,YAAW;AAC1B,MAAG,UAAU,WAAW,OAAO,YAAY,GAAG;AAE9C,OAAI,SAAS,MAAM;AACf,cAAU;AAEV,yBAAqB,MAAM,CAAC;;;AAGpC,aAAW;GACb;CAEF,MAAM,aAAa;AACf,YAAU;AACV,SAAO,MAAM;AACb,MAAI,UAAW,YAAW;;CAG9B,MAAM,cAAc;AAChB,WAAS;;CAGb,MAAM,eAAe;AACjB,MAAI,CAAC,OAAQ;AACb,WAAS;AAET,MAAI,cAAc,CAAC,OAAO,GAAG,cAAc,SAAS,EAAE;AAClD,OAAI,UAAW,YAAW;AAC1B,MAAG,cAAmB,WAAW,OAAO,YAAY,GAAG;AACvD,cAAW;;AAEf,eAAa;AACb,iBAAe,KAAA;;AAGnB,QAAO,OAAO,OAAO,MAAM;EAAE;EAAM;EAAO;EAAQ,CAAC;;ACvGvD,SAAgB,SACZ,iBACiC;CACjC,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,oBAAoB,WAC3B,UAAS;MACN;AACH,WAAS,gBAAgB;AACzB,WAAS,gBAAgB;;CAG7B,MAAM,8BAAc,IAAI,KAAqB;CAC7C,IAAI;CACJ,IAAI,QAAQ;CAGZ,MAAM,iBAAiC,WAAY;AAC/C,MAAI,CAAC,OAAO;AACR,WAAQ;AACR,WAAQ,YAAY;;;AAG5B,gBAAe,OAAO,EAAE;CAExB,MAAM,qBAAwB;AAC1B,UAAQ,eAAe;EACvB,MAAM,aAAa,iBAAiB;AACpC,kBAAgB,eAAe;AAC/B,MAAI;AACA,iBAAc,QAAQ;AACtB,WAAQ;AACR,UAAO;YACD;AACN,mBAAgB,WAAW;;;CAKnC,MAAM,cAAc;GACf,iBAAiB;EAClB,IAAI,QAAW;GAEX,MAAM,WAAW,mBAAmB;AACpC,OAAI,UAAU;AACV,aAAS,aAAa,QAAQ;AAE9B,sBAAkB,KAAK;;AAE3B,SAAM,YAAY;GAClB,MAAM,SAAS,QAAQ,cAAc,GAAG;AAExC,OAAI,SAAU,mBAAkB,SAAS;AACzC,UAAO;;EAEd;AAGD,KAAI,QAAQ;AACR,SAAO,eAAe,aAAa,SAAS;GACxC,MAAS;IAEL,MAAM,WAAW,mBAAmB;AACpC,QAAI,UAAU;AACV,cAAS,aAAa,QAAQ;AAE9B,uBAAkB,KAAK;;AAE3B,UAAM,YAAY;IAClB,MAAM,SAAS,QAAQ,cAAc,GAAG;AAExC,QAAI,SAAU,mBAAkB,SAAS;AACzC,WAAO;;GAEX,IAAI,UAAa;AACb,WAAQ,SAAS;;GAErB,YAAY;GACZ,cAAc;GACjB,CAAC;AACF,SAAO;;AAGX,QAAO;;AAaX,SAAgB,WAAW,OAA4C;AACnE,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,kBAAkB"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @sigx/reactivity internal APIs
3
+ *
4
+ * ⚠️ These are low-level primitives for building custom renderers and plugins.
5
+ * They are NOT part of the public API and may change without notice.
6
+ *
7
+ * @internal
8
+ */
9
+ export { track, trigger, cleanup } from './effect';
10
+ //# sourceMappingURL=internals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../src/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { c as trigger, n as cleanup, s as track } from "./effect-DeSl7uNB.js";
2
+ export { cleanup, track, trigger };
package/dist/signal.d.ts CHANGED
@@ -4,6 +4,22 @@ export declare function getAccessObserver(): ((target: any, key: string | symbol
4
4
  /** @internal Temporarily suspend the access observer (used by computed to prevent leakage) */
5
5
  export declare function setAccessObserver(observer: ((target: any, key: string | symbol) => void) | null): void;
6
6
  export declare function detectAccess(selector: () => any): [any, string | symbol] | null;
7
+ /**
8
+ * Create a reactive signal from a value.
9
+ *
10
+ * For primitives, wraps the value as `{ value: T }` — access and mutate via `.value`.
11
+ * For objects, returns a deeply reactive proxy with `.$set()` for full replacement.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const count = signal(0);
16
+ * count.value++;
17
+ *
18
+ * const user = signal({ name: 'Alice' });
19
+ * user.name = 'Bob'; // reactive
20
+ * user.$set({ name: 'Carol' }); // replace entire object
21
+ * ```
22
+ */
7
23
  export declare function signal<T extends Primitive>(target: T): PrimitiveSignal<T>;
8
24
  export declare function signal<T extends object>(target: T): Signal<T>;
9
25
  //# sourceMappingURL=signal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAsBlF,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAExF;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAEtG;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAkB/E;AAcD,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;AAE3E,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAsBlF,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAExF;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAEtG;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAkB/E;AAcD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;AAE3E,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC"}
package/dist/watch.d.ts CHANGED
@@ -1,3 +1,16 @@
1
1
  import type { WatchSource, WatchCallback, WatchOptions, WatchHandle } from './types';
2
+ /**
3
+ * Watch a reactive source and run a callback when it changes.
4
+ * Supports deep watching, immediate invocation, and pause/resume.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const count = signal(0);
9
+ * const handle = watch(() => count.value, (newVal, oldVal) => {
10
+ * console.log(`${oldVal} → ${newVal}`);
11
+ * });
12
+ * handle.stop(); // stop watching
13
+ * ```
14
+ */
2
15
  export declare function watch<T>(source: WatchSource<T>, cb: WatchCallback<T>, options?: WatchOptions): WatchHandle;
3
16
  //# sourceMappingURL=watch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA4CrF,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CA+E1G"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA4CrF;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CA+E1G"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/reactivity",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Reactivity system for SignalX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,6 +9,10 @@
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts"
12
+ },
13
+ "./internals": {
14
+ "import": "./dist/internals.js",
15
+ "types": "./dist/internals.d.ts"
12
16
  }
13
17
  },
14
18
  "files": [
@@ -35,7 +39,7 @@
35
39
  "devDependencies": {
36
40
  "typescript": "^5.9.3",
37
41
  "vite": "^8.0.0-beta.9",
38
- "@sigx/vite": "^0.1.8"
42
+ "@sigx/vite": "^0.1.9"
39
43
  },
40
44
  "scripts": {
41
45
  "build": "vite build && tsc --emitDeclarationOnly",