@pyreon/reactivity 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/batch.ts","../src/cell.ts","../src/scope.ts","../src/tracking.ts","../src/computed.ts","../src/effect.ts","../src/createSelector.ts","../src/debug.ts","../src/signal.ts","../src/store.ts","../src/reconcile.ts","../src/resource.ts","../src/watch.ts"],"sourcesContent":["// Batch multiple signal updates into a single notification pass.\n// Uses a Set so the same subscriber is never flushed more than once per batch,\n// even if multiple signals it depends on change within the same batch.\n\nlet batchDepth = 0\nlet pendingNotifications = new Set<() => void>()\n\nexport function batch(fn: () => void): void {\n batchDepth++\n try {\n fn()\n } finally {\n batchDepth--\n if (batchDepth === 0) {\n // Swap to a fresh Set before flushing so new enqueues during notification\n // (e.g. from nested batch() calls) land in the new Set and are handled in\n // the next flush pass, not mixed into the current iteration.\n const flush = pendingNotifications\n pendingNotifications = new Set()\n for (const notify of flush) notify()\n }\n }\n}\n\nexport function isBatching(): boolean {\n return batchDepth > 0\n}\n\nexport function enqueuePendingNotification(notify: () => void): void {\n pendingNotifications.add(notify)\n}\n\n/**\n * Returns a Promise that resolves after all currently-pending microtasks have flushed.\n * Useful when you need to read the DOM after a batch of signal updates has settled.\n *\n * @example\n * count.set(1); count.set(2)\n * await nextTick()\n * // DOM is now up-to-date\n */\nexport function nextTick(): Promise<void> {\n return new Promise((resolve) => queueMicrotask(resolve))\n}\n","/**\n * Lightweight reactive cell — class-based alternative to signal().\n *\n * - 1 object allocation vs signal()'s 6 closures\n * - Same API surface: peek(), set(), update(), subscribe(), listen()\n * - NOT callable as a getter (no effect tracking) — use for fixed subscriptions\n * - Methods on prototype, shared across all instances\n * - Single-listener fast path: no Set allocated when ≤1 subscriber\n *\n * Use when you need reactive state but don't need automatic effect dependency tracking.\n * Ideal for list item labels in keyed reconcilers where subscribe() is used directly.\n */\nexport class Cell<T> {\n /** @internal */ _v: T\n /** @internal */ _l: (() => void) | null = null // single-listener fast path\n /** @internal */ _s: Set<() => void> | null = null // multi-listener fallback\n\n constructor(value: T) {\n this._v = value\n }\n\n peek(): T {\n return this._v\n }\n\n set(value: T): void {\n if (Object.is(this._v, value)) return\n this._v = value\n if (this._l) this._l()\n else if (this._s) for (const fn of this._s) fn()\n }\n\n update(fn: (current: T) => T): void {\n this.set(fn(this._v))\n }\n\n /**\n * Fire-and-forget subscription — no unsubscribe returned.\n * Use when the listener's lifetime matches the cell's (e.g., list rows).\n * Saves 1 closure allocation per call vs subscribe().\n */\n listen(listener: () => void): void {\n if (!this._l && !this._s) {\n this._l = listener\n } else {\n // Promote to Set\n if (!this._s) {\n this._s = new Set()\n if (this._l) {\n this._s.add(this._l)\n this._l = null\n }\n }\n this._s.add(listener)\n }\n }\n\n subscribe(listener: () => void): () => void {\n this.listen(listener)\n if (this._l === listener) {\n return () => {\n if (this._l === listener) this._l = null\n }\n }\n return () => this._s?.delete(listener)\n }\n}\n\nexport function cell<T>(value: T): Cell<T> {\n return new Cell(value)\n}\n","// EffectScope — auto-tracks effects created during a component's setup\n// and disposes them all at once when the component unmounts.\n\nexport class EffectScope {\n private _effects: { dispose(): void }[] = []\n private _active = true\n private _updateHooks: (() => void)[] = []\n private _updatePending = false\n\n /** Register an effect/computed to be disposed when this scope stops. */\n add(e: { dispose(): void }): void {\n if (this._active) this._effects.push(e)\n }\n\n /**\n * Temporarily re-activate this scope so effects created inside `fn` are\n * auto-tracked and will be disposed when the scope stops.\n * Used to ensure effects created in `onMount` callbacks belong to their\n * component's scope rather than leaking as global effects.\n */\n runInScope<T>(fn: () => T): T {\n const prev = _currentScope\n _currentScope = this\n try {\n return fn()\n } finally {\n _currentScope = prev\n }\n }\n\n /** Register a callback to run after any reactive update in this scope. */\n addUpdateHook(fn: () => void): void {\n this._updateHooks.push(fn)\n }\n\n /**\n * Called by effects after each non-initial re-run.\n * Schedules onUpdate hooks via microtask so all synchronous effects settle first.\n */\n notifyEffectRan(): void {\n if (!this._active || this._updateHooks.length === 0 || this._updatePending) return\n this._updatePending = true\n queueMicrotask(() => {\n this._updatePending = false\n if (!this._active) return\n for (const fn of this._updateHooks) {\n try {\n fn()\n } catch (err) {\n console.error(\"[pyreon] onUpdate hook error:\", err)\n }\n }\n })\n }\n\n /** Dispose all tracked effects. */\n stop(): void {\n if (!this._active) return\n for (const e of this._effects) e.dispose()\n this._effects = []\n this._updateHooks = []\n this._updatePending = false\n this._active = false\n }\n}\n\nlet _currentScope: EffectScope | null = null\n\nexport function getCurrentScope(): EffectScope | null {\n return _currentScope\n}\n\nexport function setCurrentScope(scope: EffectScope | null): void {\n _currentScope = scope\n}\n\n/** Create a new EffectScope. */\nexport function effectScope(): EffectScope {\n return new EffectScope()\n}\n","// Global subscriber tracking context\n\nimport { enqueuePendingNotification, isBatching } from \"./batch\"\n\nlet activeEffect: (() => void) | null = null\n\n// Tracks which subscriber sets each effect is registered in, so we can\n// clean them up before a re-run (dynamic dependency tracking).\nconst effectDeps = new WeakMap<() => void, Set<Set<() => void>>>()\n\n// Fast deps collector for renderEffect — avoids WeakMap overhead entirely.\n// When set, trackSubscriber pushes subscriber sets here instead of effectDeps.\nlet _depsCollector: Set<() => void>[] | null = null\n\nexport function setDepsCollector(collector: Set<() => void>[] | null): void {\n _depsCollector = collector\n}\n\n/**\n * Subscriber host — any reactive source that can have downstream subscribers.\n * Signals, computeds, and createSelector buckets all implement this interface.\n * The Set is created lazily — only allocated when an effect actually tracks this source.\n */\nexport interface SubscriberHost {\n /** @internal subscriber set — null until first tracked by an effect */\n _s: Set<() => void> | null\n}\n\n/**\n * Register the active effect as a subscriber of the given reactive source.\n * The subscriber Set is created lazily on the host — sources read only outside\n * effects never allocate a Set.\n */\nexport function trackSubscriber(host: SubscriberHost) {\n if (activeEffect) {\n if (!host._s) host._s = new Set()\n const subscribers = host._s\n subscribers.add(activeEffect)\n if (_depsCollector) {\n // Fast path: renderEffect stores deps inline, no WeakMap\n _depsCollector.push(subscribers)\n } else {\n // Record this dep so we can remove it on cleanup\n let deps = effectDeps.get(activeEffect)\n if (!deps) {\n deps = new Set()\n effectDeps.set(activeEffect, deps)\n }\n deps.add(subscribers)\n }\n }\n}\n\n/**\n * Remove an effect from every subscriber set it was registered in,\n * then clear its dep record. Call this before each re-run and on dispose.\n */\nexport function cleanupEffect(fn: () => void): void {\n const deps = effectDeps.get(fn)\n if (deps) {\n for (const sub of deps) sub.delete(fn)\n deps.clear()\n }\n}\n\nexport function notifySubscribers(subscribers: Set<() => void>) {\n if (subscribers.size === 0) return\n // Single-subscriber fast path: avoid any iteration overhead.\n if (subscribers.size === 1) {\n const sub = subscribers.values().next().value as () => void\n if (isBatching()) enqueuePendingNotification(sub)\n else sub()\n return\n }\n if (isBatching()) {\n // Effects are queued not run inline — no re-entrancy risk, iterate the live Set directly.\n for (const sub of subscribers) enqueuePendingNotification(sub)\n } else {\n // Effects run inline and may call cleanupEffect (removes) + trackSubscriber (re-adds).\n // Snapshot first to prevent the iterator from visiting re-inserted entries → infinite loop.\n for (const sub of [...subscribers]) sub()\n }\n}\n\nexport function withTracking<T>(fn: () => void, compute: () => T): T {\n const prev = activeEffect\n activeEffect = fn\n try {\n return compute()\n } finally {\n activeEffect = prev\n }\n}\n\nexport function runUntracked<T>(fn: () => T): T {\n const prev = activeEffect\n activeEffect = null\n try {\n return fn()\n } finally {\n activeEffect = prev\n }\n}\n","import { getCurrentScope } from \"./scope\"\nimport { cleanupEffect, notifySubscribers, trackSubscriber, withTracking } from \"./tracking\"\n\nexport interface Computed<T> {\n (): T\n /** Remove this computed from all its reactive dependencies. */\n dispose(): void\n}\n\nexport interface ComputedOptions<T> {\n /**\n * Custom equality function. When provided, the computed eagerly re-evaluates\n * on dependency change and only notifies downstream if `equals(prev, next)`\n * returns false. Useful for derived objects/arrays to skip spurious updates.\n *\n * @example\n * const sorted = computed(() => items().slice().sort(), {\n * equals: (a, b) => a.length === b.length && a.every((v, i) => v === b[i])\n * })\n */\n equals?: (prev: T, next: T) => boolean\n}\n\nexport function computed<T>(fn: () => T, options?: ComputedOptions<T>): Computed<T> {\n let value: T\n let dirty = true\n let initialized = false\n let disposed = false\n const customEquals = options?.equals\n\n // SubscriberHost — _s is lazily allocated by trackSubscriber\n const host: { _s: Set<() => void> | null } = { _s: null }\n\n const recompute = () => {\n if (disposed) return\n // Remove from all current deps before re-evaluating (dynamic deps support)\n cleanupEffect(recompute)\n if (customEquals) {\n // Eager evaluation: only notify downstream if the value actually changed\n const next = withTracking(recompute, fn)\n if (initialized && customEquals(value as T, next)) return\n value = next\n dirty = false\n initialized = true\n if (host._s) notifySubscribers(host._s)\n } else {\n dirty = true\n if (host._s) notifySubscribers(host._s)\n }\n }\n\n const read = (): T => {\n trackSubscriber(host)\n if (dirty) {\n value = withTracking(recompute, fn)\n dirty = false\n initialized = true\n }\n return value as T\n }\n\n read.dispose = () => {\n disposed = true\n cleanupEffect(recompute)\n }\n\n // Auto-register with the active EffectScope (if any)\n getCurrentScope()?.add({ dispose: read.dispose })\n\n return read\n}\n","import { getCurrentScope } from \"./scope\"\nimport { cleanupEffect, setDepsCollector, withTracking } from \"./tracking\"\n\nexport interface Effect {\n dispose(): void\n}\n\n// Global error handler — called for unhandled errors thrown inside effects.\n// Defaults to console.error so silent failures are never swallowed.\nlet _errorHandler: (err: unknown) => void = (err) => {\n console.error(\"[pyreon] Unhandled effect error:\", err)\n}\n\nexport function setErrorHandler(fn: (err: unknown) => void): void {\n _errorHandler = fn\n}\n\n// biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callbacks that return nothing must be assignable\nexport function effect(fn: () => (() => void) | void): Effect {\n // Capture the scope at creation time — remains correct during future re-runs\n // even after setCurrentScope(null) has been called post-setup.\n const scope = getCurrentScope()\n let disposed = false\n let isFirstRun = true\n let cleanup: (() => void) | undefined\n\n const runCleanup = () => {\n if (typeof cleanup === \"function\") {\n try {\n cleanup()\n } catch (err) {\n _errorHandler(err)\n }\n cleanup = undefined\n }\n }\n\n const run = () => {\n if (disposed) return\n // Run previous cleanup before re-running\n runCleanup()\n // Clean up previous subscriptions before re-running (dynamic dep tracking)\n cleanupEffect(run)\n try {\n cleanup = withTracking(run, fn) || undefined\n } catch (err) {\n _errorHandler(err)\n }\n // Notify scope after each reactive re-run (not the initial synchronous run)\n // so onUpdate hooks fire after the DOM has settled.\n if (!isFirstRun) scope?.notifyEffectRan()\n isFirstRun = false\n }\n\n run()\n\n const e: Effect = {\n dispose() {\n runCleanup()\n disposed = true\n cleanupEffect(run)\n },\n }\n\n // Auto-register with the active EffectScope (if any)\n getCurrentScope()?.add(e)\n\n return e\n}\n\n/**\n * Lightweight effect for DOM render bindings.\n *\n * Differences from `effect()`:\n * - No EffectScope registration (caller owns the dispose lifecycle)\n * - No error handler (errors propagate naturally)\n * - No onUpdate notification\n * - Deps stored in a local array instead of the global WeakMap — faster\n * creation and disposal (~200ns saved per effect vs WeakMap path)\n *\n * Returns a dispose function (not an Effect object — saves 1 allocation).\n */\n/**\n * Static-dep binding — compiler helper for template expressions.\n *\n * Like renderEffect but assumes dependencies never change (true for all\n * compiler-emitted template bindings like `_tpl()` text/attribute updates).\n *\n * Tracks dependencies only on the first run. Re-runs skip cleanup, re-tracking,\n * and tracking context save/restore entirely — just calls `fn()` directly.\n *\n * Per re-run savings vs renderEffect:\n * - No deps iteration + Set.delete (cleanup)\n * - No setDepsCollector + withTracking (re-registration)\n * - Signal reads hit `if (activeEffect)` null check → instant return\n */\nexport function _bind(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n fn()\n }\n\n // First run: track deps so we know what to unsubscribe on dispose\n setDepsCollector(deps)\n withTracking(run, fn)\n setDepsCollector(null)\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n\n // Auto-register with scope so template bindings are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n\nexport function renderEffect(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n // Clean up old subscriptions\n for (const s of deps) s.delete(run)\n deps.length = 0\n // Track with fast collector — pushes to our local deps array\n setDepsCollector(deps)\n withTracking(run, fn)\n setDepsCollector(null)\n }\n\n run()\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n\n // Auto-register with scope so render effects are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n","import { effect } from \"./effect\"\nimport { trackSubscriber } from \"./tracking\"\n\n/**\n * Create an equality selector — returns a reactive predicate that is true\n * only for the currently selected value.\n *\n * Unlike a plain `() => source() === value`, this only triggers the TWO\n * affected subscribers (deselected + newly selected) instead of ALL\n * subscribers, making selection O(1) regardless of list size.\n *\n * @example\n * const isSelected = createSelector(selectedId)\n * // In each row:\n * class: () => (isSelected(row.id) ? \"selected\" : \"\")\n */\nexport function createSelector<T>(source: () => T): (value: T) => boolean {\n const subs = new Map<T, Set<() => void>>()\n let current: T\n let initialized = false\n\n effect(() => {\n const next = source()\n if (!initialized) {\n initialized = true\n current = next\n return\n }\n if (Object.is(next, current)) return\n const old = current\n current = next\n // Only notify the two affected buckets — O(1) regardless of list size\n const oldBucket = subs.get(old)\n const newBucket = subs.get(next)\n if (oldBucket) for (const fn of [...oldBucket]) fn()\n if (newBucket) for (const fn of [...newBucket]) fn()\n })\n\n // Reusable hosts per value — avoids allocating a closure per trackSubscriber call\n const hosts = new Map<T, { _s: Set<() => void> | null }>()\n\n return (value: T): boolean => {\n let host = hosts.get(value)\n if (!host) {\n let bucket = subs.get(value)\n if (!bucket) {\n bucket = new Set()\n subs.set(value, bucket)\n }\n host = { _s: bucket }\n hosts.set(value, host)\n }\n trackSubscriber(host)\n return Object.is(current, value)\n }\n}\n","/**\n * @pyreon/reactivity debug utilities.\n *\n * Development-only tools for tracing signal updates, inspecting reactive\n * graphs, and understanding why DOM nodes re-render.\n *\n * All utilities are tree-shakeable — they compile away in production builds\n * when unused.\n */\n\nimport type { Signal, SignalDebugInfo } from \"./signal\"\n\n// ─── Signal update tracing ───────────────────────────────────────────────────\n\ninterface SignalUpdateEvent {\n /** The signal that changed */\n signal: Signal<unknown>\n /** Signal name (from options or label) */\n name: string | undefined\n /** Previous value */\n prev: unknown\n /** New value */\n next: unknown\n /** Stack trace at the point of the .set() / .update() call */\n stack: string\n /** Timestamp */\n timestamp: number\n}\n\ntype SignalUpdateListener = (event: SignalUpdateEvent) => void\n\nlet _traceListeners: SignalUpdateListener[] | null = null\n\n/**\n * Register a listener that fires on every signal write.\n * Returns a dispose function.\n *\n * @example\n * const dispose = onSignalUpdate(e => {\n * console.log(`${e.name ?? 'anonymous'}: ${e.prev} → ${e.next}`)\n * })\n */\nexport function onSignalUpdate(listener: SignalUpdateListener): () => void {\n if (!_traceListeners) _traceListeners = []\n _traceListeners.push(listener)\n return () => {\n if (!_traceListeners) return\n _traceListeners = _traceListeners.filter((l) => l !== listener)\n if (_traceListeners.length === 0) _traceListeners = null\n }\n}\n\n/** @internal — called from signal.set() when tracing is active */\nexport function _notifyTraceListeners(sig: Signal<unknown>, prev: unknown, next: unknown): void {\n if (!_traceListeners) return\n const event: SignalUpdateEvent = {\n signal: sig,\n name: sig.label,\n prev,\n next,\n stack: new Error().stack ?? \"\",\n timestamp: performance.now(),\n }\n for (const l of _traceListeners) l(event)\n}\n\n/** Check if any trace listeners are active (fast path for signal.set) */\nexport function isTracing(): boolean {\n return _traceListeners !== null\n}\n\n// ─── why() — trace which signal caused a re-run ──────────────────────────────\n\nlet _whyActive = false\nlet _whyLog: { name: string | undefined; prev: unknown; next: unknown }[] = []\n\n/**\n * Trace the next signal update. Logs which signals fire and what changed.\n * Call before triggering a state change to see what updates and why.\n *\n * @example\n * why()\n * count.set(5)\n * // Console: [pyreon:why] \"count\": 3 → 5 (2 subscribers)\n */\nexport function why(): void {\n if (_whyActive) return\n _whyActive = true\n _whyLog = []\n\n const dispose = onSignalUpdate((e) => {\n const _subCount = (e.signal as unknown as { _s: Set<unknown> | null })._s?.size ?? 0\n const _name = e.name ? `\"${e.name}\"` : \"(anonymous signal)\"\n\n console.log(\n `[pyreon:why] ${_name}: ${JSON.stringify(e.prev)} → ${JSON.stringify(e.next)} (${_subCount} subscriber${_subCount === 1 ? \"\" : \"s\"})`,\n )\n _whyLog.push({ name: e.name, prev: e.prev, next: e.next })\n })\n\n // Auto-dispose after the current microtask (captures the synchronous batch)\n queueMicrotask(() => {\n dispose()\n if (_whyLog.length === 0) {\n console.log(\"[pyreon:why] No signal updates detected\")\n }\n _whyActive = false\n _whyLog = []\n })\n}\n\n// ─── inspectSignal — rich console output ─────────────────────────────────────\n\n/**\n * Print a signal's current state to the console in a readable format.\n *\n * @example\n * const count = signal(42, { name: \"count\" })\n * inspectSignal(count)\n * // Console:\n * // 🔍 Signal \"count\"\n * // value: 42\n * // subscribers: 3\n */\nexport function inspectSignal<T>(sig: Signal<T>): SignalDebugInfo<T> {\n const info = sig.debug()\n\n console.group(`🔍 Signal ${info.name ? `\"${info.name}\"` : \"(anonymous)\"}`)\n console.log(\"value:\", info.value)\n console.log(\"subscribers:\", info.subscriberCount)\n console.groupEnd()\n\n return info\n}\n","import { _notifyTraceListeners, isTracing } from \"./debug\"\nimport { notifySubscribers, trackSubscriber } from \"./tracking\"\n\nexport interface SignalDebugInfo<T> {\n /** Signal name (set via options or inferred) */\n name: string | undefined\n /** Current value (same as peek()) */\n value: T\n /** Number of active subscribers */\n subscriberCount: number\n}\n\nexport interface Signal<T> {\n (): T\n /** Read the current value WITHOUT registering a reactive dependency. */\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n /**\n * Subscribe a static listener directly — no effect overhead (no withTracking,\n * no cleanupEffect, no effectDeps WeakMap). Use when the dependency is fixed\n * and dynamic re-tracking is not needed.\n * Returns a disposer that removes the subscription.\n */\n subscribe(listener: () => void): () => void\n /** Debug name — useful for devtools and logging. */\n label: string | undefined\n /** Returns a snapshot of the signal's debug info (value, name, subscriber count). */\n debug(): SignalDebugInfo<T>\n}\n\nexport interface SignalOptions {\n /** Debug name for this signal — shows up in devtools and debug() output. */\n name?: string\n}\n\n// Internal shape of a signal function — state stored as properties on the\n// function object so methods can be shared via assignment (not per-signal closures).\ninterface SignalFn<T> {\n (): T\n /** @internal current value */\n _v: T\n /** @internal subscriber set (lazily allocated by trackSubscriber) */\n _s: Set<() => void> | null\n /** @internal debug name */\n _n: string | undefined\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n subscribe(listener: () => void): () => void\n label: string | undefined\n debug(): SignalDebugInfo<T>\n}\n\n// Shared method implementations — defined once, assigned to every signal.\n// Uses `this` binding (signal methods are always called as `signal.method()`).\nfunction _peek(this: SignalFn<unknown>) {\n return this._v\n}\n\nfunction _set(this: SignalFn<unknown>, newValue: unknown) {\n if (Object.is(this._v, newValue)) return\n const prev = this._v\n this._v = newValue\n if (isTracing()) _notifyTraceListeners(this as unknown as Signal<unknown>, prev, newValue)\n if (this._s) notifySubscribers(this._s)\n}\n\nfunction _update(this: SignalFn<unknown>, fn: (current: unknown) => unknown) {\n _set.call(this, fn(this._v))\n}\n\nfunction _subscribe(this: SignalFn<unknown>, listener: () => void): () => void {\n if (!this._s) this._s = new Set()\n this._s.add(listener)\n return () => this._s?.delete(listener)\n}\n\nfunction _debug(this: SignalFn<unknown>): SignalDebugInfo<unknown> {\n return {\n name: this._n,\n value: this._v,\n subscriberCount: this._s?.size ?? 0,\n }\n}\n\n// label getter/setter — maps to _n for devtools-friendly access\nconst _labelDescriptor: PropertyDescriptor = {\n get(this: SignalFn<unknown>) {\n return this._n\n },\n set(this: SignalFn<unknown>, v: string | undefined) {\n this._n = v\n },\n enumerable: false,\n configurable: true,\n}\n\n/**\n * Create a reactive signal.\n *\n * Only 1 closure is allocated (the read function). State is stored as\n * properties on the function object (_v, _s) and methods (peek, set,\n * update, subscribe) are shared across all signals — not per-signal closures.\n */\nexport function signal<T>(initialValue: T, options?: SignalOptions): Signal<T> {\n // The read function is the only per-signal closure.\n // It doubles as the SubscriberHost (_s property) for trackSubscriber.\n const read = (() => {\n trackSubscriber(read as SignalFn<T>)\n return read._v\n }) as unknown as SignalFn<T>\n\n read._v = initialValue\n read._s = null\n read._n = options?.name\n read.peek = _peek as () => T\n read.set = _set as (value: T) => void\n read.update = _update as (fn: (current: T) => T) => void\n read.subscribe = _subscribe as (listener: () => void) => () => void\n read.debug = _debug as () => SignalDebugInfo<T>\n Object.defineProperty(read, \"label\", _labelDescriptor)\n\n return read as unknown as Signal<T>\n}\n","/**\n * createStore — deep reactive Proxy store.\n *\n * Wraps a plain object/array in a Proxy that creates a fine-grained signal for\n * every property. Direct mutations (`store.count++`, `store.items[0].label = \"x\"`)\n * trigger only the signals for the mutated properties — not the whole tree.\n *\n * @example\n * const state = createStore({ count: 0, items: [{ id: 1, text: \"hello\" }] })\n *\n * effect(() => console.log(state.count)) // tracks state.count only\n * state.count++ // only the count effect re-runs\n * state.items[0].text = \"world\" // only text-tracking effects re-run\n */\n\nimport { type Signal, signal } from \"./signal\"\n\n// WeakMap: raw object → its reactive proxy (ensures each raw object gets one proxy)\nconst proxyCache = new WeakMap<object, object>()\n\nconst IS_STORE = Symbol(\"pyreon.store\")\n\n/** Returns true if the value is a createStore proxy. */\nexport function isStore(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === \"object\" &&\n (value as Record<symbol, unknown>)[IS_STORE] === true\n )\n}\n\n/**\n * Create a deep reactive store from a plain object or array.\n * Returns a proxy — mutations to the proxy trigger fine-grained reactive updates.\n */\nexport function createStore<T extends object>(initial: T): T {\n return wrap(initial) as T\n}\n\nfunction wrap(raw: object): object {\n const cached = proxyCache.get(raw)\n if (cached) return cached\n\n // Per-property signals. Lazily created on first access.\n const propSignals = new Map<PropertyKey, Signal<unknown>>()\n // For arrays: track length changes separately (push/pop/splice affect length)\n const isArray = Array.isArray(raw)\n const lengthSig = isArray ? signal((raw as unknown[]).length) : null\n\n function getOrCreateSignal(key: PropertyKey): Signal<unknown> {\n if (!propSignals.has(key)) {\n propSignals.set(key, signal((raw as Record<PropertyKey, unknown>)[key]))\n }\n return propSignals.get(key) as Signal<unknown>\n }\n\n const proxy = new Proxy(raw, {\n get(target, key) {\n // Pass through the identity marker and non-string/number keys (symbols, etc.)\n if (key === IS_STORE) return true\n if (typeof key === \"symbol\") return (target as Record<symbol, unknown>)[key]\n\n // Array length — tracked via dedicated signal for push/pop/splice reactivity\n if (isArray && key === \"length\") return lengthSig?.()\n\n // Non-own properties: prototype methods (forEach, map, push, …)\n // These must be returned untracked so array methods work normally.\n // Array methods will then go through set/get on indices via the proxy.\n if (!Object.hasOwn(target, key)) {\n return (target as Record<PropertyKey, unknown>)[key]\n }\n\n // Track via per-property signal\n const value = getOrCreateSignal(key)()\n\n // Deep reactivity: wrap nested objects/arrays transparently\n if (value !== null && typeof value === \"object\") {\n return wrap(value as object)\n }\n\n return value\n },\n\n set(target, key, value) {\n if (typeof key === \"symbol\") {\n ;(target as Record<symbol, unknown>)[key] = value\n return true\n }\n\n const prevLength = isArray ? (target as unknown[]).length : 0\n ;(target as Record<PropertyKey, unknown>)[key] = value\n\n // Array length set directly (e.g. arr.length = 0)\n if (isArray && key === \"length\") {\n lengthSig?.set(value as number)\n return true\n }\n\n // Update or create signal for this property\n if (propSignals.has(key)) {\n propSignals.get(key)?.set(value)\n } else {\n propSignals.set(key, signal(value))\n }\n\n // If array length changed (e.g. via push/splice index assignment), update it\n if (isArray && (target as unknown[]).length !== prevLength) {\n lengthSig?.set((target as unknown[]).length)\n }\n\n return true\n },\n\n deleteProperty(target, key) {\n delete (target as Record<PropertyKey, unknown>)[key]\n if (typeof key !== \"symbol\" && propSignals.has(key)) {\n propSignals.get(key)?.set(undefined)\n propSignals.delete(key)\n }\n if (isArray) lengthSig?.set((target as unknown[]).length)\n return true\n },\n\n has(target, key) {\n return Reflect.has(target, key)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, key) {\n return Reflect.getOwnPropertyDescriptor(target, key)\n },\n })\n\n proxyCache.set(raw, proxy)\n return proxy\n}\n","/**\n * reconcile — surgically diff new state into an existing createStore proxy.\n *\n * Instead of replacing the store root (which would trigger all downstream effects),\n * reconcile walks both the new value and the store in parallel and only calls\n * `.set()` on signals whose value actually changed.\n *\n * Ideal for applying API responses to a long-lived store:\n *\n * @example\n * const state = createStore({ user: { name: \"Alice\", age: 30 }, items: [] })\n *\n * // API response arrives:\n * reconcile({ user: { name: \"Alice\", age: 31 }, items: [{ id: 1 }] }, state)\n * // → only state.user.age signal fires (name unchanged)\n * // → state.items[0] is newly created\n *\n * Arrays are reconciled by index — elements at the same index are recursively\n * diffed rather than replaced wholesale. Excess old elements are removed.\n */\n\nimport { isStore } from \"./store\"\n\ntype AnyObject = Record<PropertyKey, unknown>\n\nexport function reconcile<T extends object>(source: T, target: T): void {\n _reconcileInner(source, target, new WeakSet())\n}\n\nfunction _reconcileInner(source: object, target: object, seen: WeakSet<object>): void {\n if (seen.has(source)) return // circular reference — stop recursion\n seen.add(source)\n if (Array.isArray(source) && Array.isArray(target)) {\n _reconcileArray(source as unknown[], target as unknown[], seen)\n } else {\n _reconcileObject(source as AnyObject, target as AnyObject, seen)\n }\n}\n\nfunction _reconcileArray(source: unknown[], target: unknown[], seen: WeakSet<object>): void {\n const targetLen = target.length\n const sourceLen = source.length\n\n // Update / add entries\n for (let i = 0; i < sourceLen; i++) {\n const sv = source[i]\n const tv = (target as unknown[])[i]\n\n if (\n i < targetLen &&\n sv !== null &&\n typeof sv === \"object\" &&\n tv !== null &&\n typeof tv === \"object\"\n ) {\n // Both sides are objects — recurse\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Scalar or new entry — write directly (signal will skip if equal via Object.is)\n ;(target as unknown[])[i] = sv\n }\n }\n\n // Trim excess entries\n if (targetLen > sourceLen) {\n target.length = sourceLen\n }\n}\n\nfunction _reconcileObject(source: AnyObject, target: AnyObject, seen: WeakSet<object>): void {\n const sourceKeys = Object.keys(source)\n const targetKeys = new Set(Object.keys(target))\n\n for (const key of sourceKeys) {\n const sv = source[key]\n const tv = target[key]\n\n if (sv !== null && typeof sv === \"object\" && tv !== null && typeof tv === \"object\") {\n if (isStore(tv)) {\n // Both objects — recurse into the store node\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Target is a raw object (not yet proxied) — just assign\n target[key] = sv\n }\n } else {\n // Scalar: assign (store proxy's set trap skips if Object.is equal)\n target[key] = sv\n }\n\n targetKeys.delete(key)\n }\n\n // Remove keys that no longer exist in source\n for (const key of targetKeys) {\n delete target[key]\n }\n}\n","import { effect } from \"./effect\"\nimport type { Signal } from \"./signal\"\nimport { signal } from \"./signal\"\nimport { runUntracked } from \"./tracking\"\n\nexport interface Resource<T> {\n /** The latest resolved value (undefined while loading or on error). */\n data: Signal<T | undefined>\n /** True while a fetch is in flight. */\n loading: Signal<boolean>\n /** The last error thrown by the fetcher, or undefined. */\n error: Signal<unknown>\n /** Re-run the fetcher with the current source value. */\n refetch(): void\n}\n\n/**\n * Async data primitive. Fetches data reactively whenever `source()` changes.\n *\n * @example\n * const userId = signal(1)\n * const user = createResource(userId, (id) => fetchUser(id))\n * // user.data() — the fetched user (undefined while loading)\n * // user.loading() — true while in flight\n * // user.error() — last error\n */\nexport function createResource<T, P>(\n source: () => P,\n fetcher: (param: P) => Promise<T>,\n): Resource<T> {\n const data = signal<T | undefined>(undefined)\n const loading = signal(false)\n const error = signal<unknown>(undefined)\n let requestId = 0\n\n const doFetch = (param: P) => {\n const id = ++requestId\n loading.set(true)\n error.set(undefined)\n fetcher(param)\n .then((result) => {\n if (id !== requestId) return\n data.set(result)\n loading.set(false)\n })\n .catch((err: unknown) => {\n if (id !== requestId) return\n error.set(err)\n loading.set(false)\n })\n }\n\n effect(() => {\n const param = source()\n runUntracked(() => doFetch(param))\n })\n\n return {\n data,\n loading,\n error,\n refetch() {\n runUntracked(() => doFetch(source()))\n },\n }\n}\n","import { effect } from \"./effect\"\n\nexport interface WatchOptions {\n /** If true, call the callback immediately with the current value on setup. Default: false. */\n immediate?: boolean\n}\n\n/**\n * Watch a reactive source and run a callback whenever it changes.\n *\n * Returns a stop function that disposes the watcher.\n *\n * The callback receives (newValue, oldValue). On the first call (when\n * `immediate` is true) oldValue is `undefined`.\n *\n * The callback may return a cleanup function that is called before each\n * re-run and on stop — useful for cancelling async work.\n *\n * @example\n * const stop = watch(\n * () => userId(),\n * async (id, prev) => {\n * const data = await fetch(`/api/user/${id}`)\n * setUser(await data.json())\n * },\n * )\n * // Later: stop()\n */\nexport function watch<T>(\n source: () => T,\n // biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callers may return void\n callback: (newVal: T, oldVal: T | undefined) => void | (() => void),\n opts: WatchOptions = {},\n): () => void {\n let oldVal: T | undefined\n let isFirst = true\n let cleanupFn: (() => void) | undefined\n\n const e = effect(() => {\n const newVal = source()\n\n if (isFirst) {\n isFirst = false\n oldVal = newVal\n if (opts.immediate) {\n const result = callback(newVal, undefined)\n if (typeof result === \"function\") cleanupFn = result\n }\n return\n }\n\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n\n const result = callback(newVal, oldVal)\n if (typeof result === \"function\") cleanupFn = result\n oldVal = newVal\n })\n\n return () => {\n e.dispose()\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n }\n}\n"],"mappings":"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"}