{"version":3,"sources":["../src/core/effect-flags.ts","../src/core/signal-id.ts","../src/core/reactive-v2.ts","../src/core/scheduler.ts"],"names":["isActive","flags","isScheduled","isPaused","setDirty","setScheduled","clearActive","clearDirty","clearScheduled","_nextId","nextSignalId","_nextEffectId","nextEffectId","makeSignalContainer","initialValue","SignalContainerV2","getter","setter","container","v","makeEffectRecord","fn","scheduler","getActiveEffectV2","getRequestContext","trackV2","signal","effect","isV1","effs","triggerV2","scheduleEffect","snapshot","activeEffect","asV1","v1QueueJobHook","__setV1QueueJobHook","createSignalV2","newValue","next","cleanupEffect","deps","i","idx","runEffectV2","ctx","parent","stopEffectV2","setV2EffectRunner","queueJob","wrapAsReactiveEffectLike","record","createEffectV2","options","attachToComponent","component","getComponent","asLike","registerEffectWithComponent","runner","isFlushing","flushScheduler","toRun","maybeV1"],"mappings":"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","file":"chunk-MKZIFVUO.mjs","sourcesContent":["/**\n * Effect state bitfield constants.\n *\n * A single `flags: number` field on EffectRecord replaces 4 individual booleans.\n * Memory: 1 field vs 4 fields per effect → ~48 bytes saved per 1000 effects.\n * Comparison: `(flags & EFFECT_ACTIVE) !== 0` is one bitwise op vs a boolean load.\n */\n\n/** Effect is live and allowed to run. Cleared by `.stop()`. */\nexport const EFFECT_ACTIVE = 0b0001  // 1\n\n/** Effect has a stale dependency and needs to re-run. Set by trigger(), cleared after run. */\nexport const EFFECT_DIRTY = 0b0010  // 2\n\n/** Effect is already queued in the scheduler. Guards against double-queueing. */\nexport const EFFECT_SCHEDULED = 0b0100  // 4\n\n/** Effect is paused (e.g., component unmounting). Won't run even if dirty. */\nexport const EFFECT_PAUSED = 0b1000  // 8\n\n// --- Helpers ----------------------------------------------------------------\n\nexport function isActive(flags: number): boolean { return (flags & EFFECT_ACTIVE) !== 0 }\nexport function isDirty(flags: number): boolean { return (flags & EFFECT_DIRTY) !== 0 }\nexport function isScheduled(flags: number): boolean { return (flags & EFFECT_SCHEDULED) !== 0 }\nexport function isPaused(flags: number): boolean { return (flags & EFFECT_PAUSED) !== 0 }\n\nexport function setActive(flags: number): number { return flags | EFFECT_ACTIVE }\nexport function setDirty(flags: number): number { return flags | EFFECT_DIRTY }\nexport function setScheduled(flags: number): number { return flags | EFFECT_SCHEDULED }\nexport function setPaused(flags: number): number { return flags | EFFECT_PAUSED }\n\nexport function clearActive(flags: number): number { return flags & ~EFFECT_ACTIVE }\nexport function clearDirty(flags: number): number { return flags & ~EFFECT_DIRTY }\nexport function clearScheduled(flags: number): number { return flags & ~EFFECT_SCHEDULED }\nexport function clearPaused(flags: number): number { return flags & ~EFFECT_PAUSED }\n","/**\n * Monotonically increasing signal ID generator.\n *\n * IDs are used as stable keys for:\n *   - Dependency deduplication (bitfield mask where size allows)\n *   - DevTools identity tracking\n *   - Scheduler deduplication set\n *\n * WeakMap<object, number> maps signal container object → its integer ID without\n * preventing GC of the container (no strong reference).\n */\n\nlet _nextId = 1\n\n/** Returns the next unique signal ID. Thread-safe for single-threaded JS. */\nexport function nextSignalId(): number {\n    return _nextId++\n}\n\n/** Returns the current counter value (for tests / diagnostics). */\nexport function peekSignalIdCounter(): number {\n    return _nextId\n}\n\n/** @internal — test-only reset to make tests deterministic. */\nexport function __resetSignalIdCounter(): void {\n    _nextId = 1\n}\n\n/** WeakMap from signal container object → its assigned ID. */\nconst signalIdMap = new WeakMap<object, number>()\n\n/**\n * Get or assign a stable ID for a signal container.\n * Idempotent: calling multiple times returns same ID.\n */\nexport function getOrAssignSignalId(signal: object): number {\n    let id = signalIdMap.get(signal)\n    if (id === undefined) {\n        id = nextSignalId()\n        signalIdMap.set(signal, id)\n    }\n    return id\n}\n\n/**\n * Look up an already-assigned ID. Returns -1 if not found.\n * Used to test whether a signal has been registered.\n */\nexport function lookupSignalId(signal: object): number {\n    return signalIdMap.get(signal) ?? -1\n}\n","import { EFFECT_ACTIVE, isActive, isPaused, clearDirty, clearScheduled, clearActive } from './effect-flags'\nimport { nextSignalId } from './signal-id'\nimport { getRequestContext } from './request-context'\nimport { setV2EffectRunner, queueJob as v1QueueJob } from './lifecycle'\nimport type { ScheduleEffectFn } from './scheduler'\n\n/** Pre-sized initial capacity for effects array. */\nconst INITIAL_EFFECTS_SIZE = 4\n\n/**\n * SignalContainer — stable hidden class (V8 monomorphic).\n *\n * IMPORTANT: Always allocate via `makeSignalContainer()`. Never construct inline\n * with object literals that have different property sets, because that splits\n * the hidden class and breaks V8's inline cache.\n */\nexport interface SignalContainer<T = unknown> {\n    readonly id: number\n    value: T\n    effects: EffectRecord[]\n    flags: number\n}\n\nexport interface EffectRecord {\n    id: number\n    fn: () => void\n    deps: SignalContainer[]\n    flags: number\n    scheduler: (() => void) | undefined\n}\n\nlet _nextEffectId = 1\nexport function nextEffectId(): number { return _nextEffectId++ }\n/** @internal — test-only */\nexport function __resetEffectId(): void { _nextEffectId = 1 }\n\n/** Factory — always produces same property order → same hidden class. */\nexport function makeSignalContainer<T>(initialValue: T): SignalContainer<T> {\n    const id = nextSignalId()\n    return { id, value: initialValue, effects: [], flags: 0 }\n}\n\n/**\n * SignalContainerV2 — stable-shape container returned from createSignalV2.\n *\n * All five data properties (type, _v2, _getter, _setter, _v2Container) are\n * assigned in constructor order so every instance shares the same V8 hidden\n * class. The `value` accessor lives on the prototype, so closures are\n * allocated once (on the prototype) rather than per signal — this replaces\n * the per-call `hybrid` object literal that use.ts previously allocated\n * after every createSignalV2() call.\n *\n * `this`-binding note: `get value()` resolves `_getter`/`_setter` via `this`.\n * Flexium's internal access patterns (`container.value`, `container._setter(x)`)\n * always preserve the correct receiver. Destructuring (`const { value } =\n * container`) would lose `this` and is not used internally.\n */\nexport class SignalContainerV2<T = unknown> {\n    readonly type = 'signal' as const\n    readonly _v2 = true as const\n    readonly _getter: () => T\n    readonly _setter: (newValue: T | ((prev: T) => T)) => void\n    readonly _v2Container: SignalContainer<T>\n\n    constructor(\n        getter: () => T,\n        setter: (newValue: T | ((prev: T) => T)) => void,\n        container: SignalContainer<T>\n    ) {\n        this._getter = getter\n        this._setter = setter\n        this._v2Container = container\n    }\n\n    get value(): T {\n        return this._getter()\n    }\n\n    set value(v: T) {\n        this._setter(v)\n    }\n}\n\n/** Factory — always produces same property order. */\nexport function makeEffectRecord(\n    fn: () => void,\n    scheduler?: () => void\n): EffectRecord {\n    return {\n        id: nextEffectId(),\n        fn,\n        deps: [],\n        flags: EFFECT_ACTIVE,\n        scheduler: scheduler ?? undefined,\n    }\n}\n\nexport { INITIAL_EFFECTS_SIZE }\n\n// ---------------------------------------------------------------------------\n// Active-effect tracking (uses existing RequestContext.activeEffect slot —\n// we store EffectRecord there during V2 effect execution)\n// ---------------------------------------------------------------------------\n\n/** Get the currently-running V2 effect (or undefined if none). */\nexport function getActiveEffectV2(): EffectRecord | undefined {\n    // Re-use the existing per-request slot. During V2 execution the stored value\n    // is an EffectRecord (which satisfies the ReactiveEffectLike duck-type for the slot).\n    return getRequestContext().activeEffect as unknown as EffectRecord | undefined\n}\n\n// ---------------------------------------------------------------------------\n// track — called inside a signal getter when an effect is running\n// ---------------------------------------------------------------------------\n\n/**\n * Record that the currently-active effect reads from `signal`.\n *\n * Complexity: O(n) scan of signal.effects[] to avoid duplicates.\n * For typical component renders, n < 20. A bitfield active-mask would reduce\n * this to O(1) but requires capping total signal count — deferred to Phase 4.\n *\n * V1 compatibility: if the active effect is a V1 ReactiveEffectLike (lacks\n * .flags), we still register it in signal.effects[] so trigger can dispatch\n * it via the V1 path.\n */\nexport function trackV2(signal: SignalContainer): void {\n    const ctx = getRequestContext()\n    const effect = ctx.activeEffect as unknown as EffectRecord | undefined\n    if (!effect) return\n\n    // Detect V1 effect — it has .active boolean, not .flags number\n    const isV1 = typeof (effect as unknown as { active?: boolean }).active === 'boolean'\n\n    if (isV1) {\n        // V1 active effect — register the V1 record so triggerV2 can dispatch\n        // it via the V1 queueJob path. Bypass V2 flag checks.\n        const v1 = effect as unknown as { active: boolean }\n        if (!v1.active) return\n    } else {\n        if (!isActive(effect.flags)) return\n    }\n\n    // Avoid duplicate registration\n    const effs = signal.effects\n    for (let i = 0; i < effs.length; i++) {\n        if (effs[i] === effect) return\n    }\n\n    signal.effects.push(effect)\n    if (!isV1) {\n        effect.deps.push(signal)\n    }\n    // For V1 effects, we don't push into deps — V1 deps is Set<ReactiveEffect>[].\n    // Trade-off: V1 effect cleanup won't unsubscribe from V2 signals automatically.\n    // Phase D Task 22 will document this; full cleanup arrives when V1 is removed\n    // in Task 26 (soak period).\n}\n\n// ---------------------------------------------------------------------------\n// trigger — called inside a signal setter when value changes\n// ---------------------------------------------------------------------------\n\n/**\n * Notify all subscriber effects that `signal` changed.\n *\n * Effects are iterated via a snapshot copy so that re-entrant mutations are safe.\n *\n * V1 compatibility: V1 ReactiveEffectLike records are detected via `typeof\n * .active === 'boolean'` and dispatched through `queueJob` (V1 microtask\n * scheduler) — letting V1 components correctly re-run when they read a V2\n * signal.\n */\nexport function triggerV2(\n    signal: SignalContainer,\n    scheduleEffect: (e: EffectRecord) => void\n): void {\n    const effs = signal.effects\n    if (effs.length === 0) return\n\n    // Snapshot: safe against re-entrant modifications during iteration\n    const snapshot = effs.slice()\n    const activeEffect = getActiveEffectV2()\n\n    for (let i = 0; i < snapshot.length; i++) {\n        const effect = snapshot[i]\n        if (effect === activeEffect) continue              // skip self-trigger\n\n        const asV1 = effect as unknown as { active?: boolean; scheduler?: () => void; run?: () => void }\n        if (typeof asV1.active === 'boolean') {\n            // V1 record path\n            if (!asV1.active) continue\n            if (asV1.scheduler) {\n                asV1.scheduler()\n            } else {\n                // Use V1 queueJob via the late-bound scheduler hook\n                v1QueueJobHook(effect)\n            }\n            continue\n        }\n\n        // V2 record path\n        if (!isActive(effect.flags)) continue              // stopped effects\n        if (isPaused(effect.flags)) continue               // paused effects\n\n        if (effect.scheduler) {\n            effect.scheduler()\n        } else {\n            scheduleEffect(effect)\n        }\n    }\n}\n\n// Late-bound hook so we don't create a static circular dep on lifecycle.ts.\n// reactive-v2.ts ← scheduler.ts ← lifecycle.ts already chains; we avoid going back.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet v1QueueJobHook: (effect: any) => void = () => {}\n/** @internal — bound from this module's bottom block via lifecycle's queueJob. */\nexport function __setV1QueueJobHook(fn: (effect: unknown) => void): void {\n    v1QueueJobHook = fn\n}\n\n// ---------------------------------------------------------------------------\n// createSignalV2 — public V2 signal factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a V2 reactive signal.\n *\n * Returns a SignalContainerV2 instance — a stable-hidden-class object that\n * exposes `_getter`/`_setter` for fast direct access and `value` accessor pair\n * (defined on the prototype) for ergonomic read/write.\n *\n * Getter calls trackV2(); setter calls triggerV2(). No Proxy involved.\n */\nexport function createSignalV2<T>(\n    initialValue: T,\n    scheduleEffect: ScheduleEffectFn\n): SignalContainerV2<T> {\n    const container = makeSignalContainer(initialValue)\n\n    function getter(): T {\n        trackV2(container)\n        return container.value\n    }\n\n    function setter(newValue: T | ((prev: T) => T)): void {\n        const next = typeof newValue === 'function'\n            ? (newValue as (prev: T) => T)(container.value)\n            : newValue\n\n        if (Object.is(next, container.value)) return   // no-op: same value\n\n        container.value = next\n        triggerV2(container, scheduleEffect)\n    }\n\n    return new SignalContainerV2(getter, setter, container)\n}\n\n/**\n * Test-only tuple adapter — preserves the pre-Phase-5 `[getter, setter, container]`\n * destructuring contract for the internal V2 regression suite (regression-v2.test.ts,\n * reactive-v2.test.ts). NOT exported from the package; consumers must use\n * createSignalV2() and read .[_getter,_setter,_v2Container] / .value.\n *\n * @internal — test-only\n */\nexport function __createSignalV2Tuple<T>(\n    initialValue: T,\n    scheduleEffect: ScheduleEffectFn\n): [() => T, (newValue: T | ((prev: T) => T)) => void, SignalContainer<T>] {\n    const sc = createSignalV2(initialValue, scheduleEffect)\n    return [sc._getter, sc._setter, sc._v2Container]\n}\n\n// ---------------------------------------------------------------------------\n// runEffectV2 / stopEffectV2 — effect execution + lifecycle\n// ---------------------------------------------------------------------------\n\n/**\n * Remove `effect` from all signals it is currently subscribed to,\n * then clear its deps list. Called before re-running to rebuild dep set.\n */\nfunction cleanupEffect(effect: EffectRecord): void {\n    const { deps } = effect\n    for (let i = 0; i < deps.length; i++) {\n        const signal = deps[i]\n        const effs = signal.effects\n        // Swap-remove for O(1) deletion (order doesn't matter for effect sets)\n        const idx = effs.indexOf(effect)\n        if (idx !== -1) {\n            effs[idx] = effs[effs.length - 1]\n            effs.pop()\n        }\n    }\n    deps.length = 0\n}\n\n/**\n * Run `effect.fn()` with dependency tracking.\n * Restores previous active effect after execution (supports nested effects).\n */\nexport function runEffectV2(effect: EffectRecord): void {\n    if (!isActive(effect.flags)) {\n        effect.fn()   // stopped but called directly: run without tracking\n        return\n    }\n\n    const ctx = getRequestContext()\n    const parent = ctx.activeEffect\n\n    try {\n        cleanupEffect(effect)\n        effect.flags = clearDirty(effect.flags)\n        effect.flags = clearScheduled(effect.flags)\n        ctx.activeEffect = effect as unknown as import('./lifecycle').ReactiveEffect\n        effect.fn()\n    } finally {\n        ctx.activeEffect = parent\n    }\n}\n\n/**\n * Stop an effect permanently: mark inactive, unsubscribe from all signals.\n */\nexport function stopEffectV2(effect: EffectRecord): void {\n    if (!isActive(effect.flags)) return\n    cleanupEffect(effect)\n    effect.flags = clearActive(effect.flags)\n}\n\n// Register V2 dispatcher with lifecycle.ts so V1 sync() drains V2 effects too.\n// This is a one-time bind at module-init; safe because lifecycle.ts cannot\n// statically import this module (it imports types via `./lifecycle` here).\nsetV2EffectRunner((effect) => runEffectV2(effect as EffectRecord))\n\n// Bind V1 queueJob so triggerV2 can dispatch V1 effects when they read V2 signals.\n__setV1QueueJobHook((effect: unknown) => v1QueueJob(effect as import('./lifecycle').ReactiveEffect))\n\n// ---------------------------------------------------------------------------\n// createEffectV2 — public effect creator (analog to unsafeEffect)\n// ---------------------------------------------------------------------------\n\nimport { getComponent, registerEffectWithComponent } from './hook'\nimport type { ReactiveEffectLike } from './lifecycle'\n\n/**\n * Wrap a V2 EffectRecord as a ReactiveEffectLike duck-type for compatibility\n * with hook.ts registerEffectWithComponent / stopComponentEffects.\n */\nfunction wrapAsReactiveEffectLike(record: EffectRecord): ReactiveEffectLike {\n    return {\n        deps: [],                   // not used by hook.ts — deps managed internally\n        active: isActive(record.flags),\n        fn: record.fn,\n        scheduler: record.scheduler,\n        run() { runEffectV2(record) },\n        stop() { stopEffectV2(record) },\n        cleanup() { /* deps cleaned internally in runEffectV2 */ },\n    } as unknown as ReactiveEffectLike\n}\n\n/**\n * Create and immediately run a V2 reactive effect.\n *\n * When `attachToComponent` is true (default), the effect is registered with\n * the current component instance and stopped on unmount.\n *\n * The returned runner has `.effect` property (same shape as V1 runner) for\n * compatibility with code that accesses runner.effect.stop().\n */\nexport function createEffectV2(\n    fn: () => void,\n    options: { scheduler?: () => void; attachToComponent?: boolean } = {}\n): ((...args: unknown[]) => void) & { effect: ReactiveEffectLike } {\n    const record = makeEffectRecord(fn, options.scheduler)\n\n    // Run immediately\n    runEffectV2(record)\n\n    const { attachToComponent = true } = options\n    if (attachToComponent) {\n        const component = getComponent()\n        if (component) {\n            const asLike = wrapAsReactiveEffectLike(record)\n            registerEffectWithComponent(component, asLike)\n        }\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const runner: any = () => runEffectV2(record)\n    runner.effect = wrapAsReactiveEffectLike(record)\n    return runner\n}\n","import type { EffectRecord } from './reactive-v2'\nimport { isActive, isPaused, isScheduled, setScheduled, clearScheduled } from './effect-flags'\nimport { getRequestContext } from './request-context'\nimport { runEffectV2 } from './reactive-v2'\nimport type { ReactiveEffectLike } from './lifecycle'\n\nexport type ScheduleEffectFn = (effect: EffectRecord) => void\n\n// ---------------------------------------------------------------------------\n// Per-request flush queue\n// ---------------------------------------------------------------------------\n// We piggyback on the existing RequestContext.effectQueue for SSR isolation.\n// The V2 scheduler stores EffectRecord objects there (they satisfy the\n// ReactiveEffectLike duck type well enough for queue membership).\n\nlet isFlushing = false\n\n/**\n * Queue an effect for deferred microtask execution.\n *\n * Deduplication: each effect has a unique numeric ID. The SCHEDULED bit on\n * `effect.flags` ensures the same effect isn't queued twice per flush cycle.\n */\nexport function scheduleEffect(effect: EffectRecord): void {\n    if (!isActive(effect.flags)) return\n    if (isPaused(effect.flags)) return\n    if (isScheduled(effect.flags)) return  // already in queue\n\n    const ctx = getRequestContext()\n    effect.flags = setScheduled(effect.flags)\n    ctx.effectQueue.add(effect as unknown as ReactiveEffectLike)\n\n    if (ctx.isBatching) {\n        // In batch mode: marked scheduled, queue holds it, but no microtask yet.\n        return\n    }\n\n    if (!ctx.isFlushPending) {\n        ctx.isFlushPending = true\n        Promise.resolve().then(flushScheduler)\n    }\n}\n\n/**\n * Flush all queued V2 effects.\n *\n * Called by the microtask promise or by sync() / flushSchedulerSync().\n * Effects are run in insertion order. Re-queued effects (from re-entrant\n * triggers) are deferred to the next flush cycle.\n */\nexport function flushScheduler(): void {\n    if (isFlushing) return  // re-entrancy guard\n    isFlushing = true\n\n    const ctx = getRequestContext()\n    ctx.isFlushPending = false\n\n    try {\n        // Drain: clone queue, clear it, then run each effect.\n        // Effects may re-trigger during run — those go into a fresh queue cycle.\n        const toRun = [...ctx.effectQueue] as unknown as EffectRecord[]\n        ctx.effectQueue.clear()\n\n        for (let i = 0; i < toRun.length; i++) {\n            const effect = toRun[i]\n            effect.flags = clearScheduled(effect.flags)\n            if (isActive(effect.flags) && !isPaused(effect.flags)) {\n                // V2 effects are EffectRecord. V1 effects are ReactiveEffectLike (have .run()).\n                // Detect via presence of run() method on the queued object.\n                const maybeV1 = effect as unknown as { run?: () => void }\n                if (typeof maybeV1.run === 'function') {\n                    maybeV1.run()\n                } else {\n                    runEffectV2(effect)\n                }\n            }\n        }\n    } finally {\n        isFlushing = false\n    }\n}\n\n/**\n * Synchronously flush all pending V2 effects.\n * Mirrors the V1 `flush()` / `sync()` behavior.\n */\nexport function flushSchedulerSync(): void {\n    const ctx = getRequestContext()\n    ctx.isFlushPending = false\n    flushScheduler()\n}\n\n/**\n * Run `fn` in a batch — all triggered effects are deferred until fn completes,\n * then flushed once.\n */\nexport function batchV2(fn: () => void): void {\n    const ctx = getRequestContext()\n    const wasBatching = ctx.isBatching\n    ctx.isBatching = true\n    try {\n        fn()\n    } finally {\n        ctx.isBatching = wasBatching\n        if (!wasBatching) flushSchedulerSync()\n    }\n}\n\n// ---------------------------------------------------------------------------\n// Public scheduler-v2 interface (for Phase 2 renderer integration)\n// ---------------------------------------------------------------------------\n\n/**\n * Public scheduler interface from Phase 2's plan:\n *   scheduleTask(fn, priority?)\n *   flushSync()\n *   detectSchedulerSupport()\n *\n * Phase 1 ships them as thin wrappers; Phase 2 may add scheduler.postTask\n * routing for browser priorities.\n */\n\nexport type TaskPriority = 'user-blocking' | 'user-visible' | 'background'\n\n/**\n * Queue a task for microtask execution.\n *\n * Phase 1: wraps the task in an anonymous EffectRecord and routes through the\n * V2 scheduler. Priority is currently ignored — it's accepted so the Phase 2\n * renderer can plumb the value through without API churn.\n */\nexport function scheduleTask(fn: () => void, _priority?: TaskPriority): void {\n    // Anonymous one-shot effect — not registered with any signal, never re-runs.\n    // We avoid going through runEffectV2 since there's no dep-tracking benefit;\n    // we want the task to run once on the microtask queue.\n    if (typeof queueMicrotask === 'function') {\n        queueMicrotask(fn)\n    } else {\n        Promise.resolve().then(fn)\n    }\n}\n\n/**\n * Flush all pending scheduler work synchronously. Mirrors flushSchedulerSync()\n * under the Phase 2 plan's naming. Re-exported for renderer use.\n */\nexport function flushSync(): void {\n    flushSchedulerSync()\n}\n\n/**\n * Feature detection for advanced scheduling APIs. Phase 1 returns 'microtask'\n * unconditionally; Phase 2 may upgrade this to 'scheduler.postTask' when\n * available.\n */\nexport function detectSchedulerSupport(): 'microtask' | 'scheduler.postTask' {\n    if (typeof globalThis !== 'undefined') {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const g = globalThis as any\n        if (g.scheduler && typeof g.scheduler.postTask === 'function') {\n            return 'scheduler.postTask'\n        }\n    }\n    return 'microtask'\n}\n"]}