{"version":3,"sources":["../src/core/packed-dep-set.ts","../src/core/effect-id-allocator.ts","../src/core/lifecycle.ts"],"names":["PackedDepSet","initialCap","id","buf","len","i","cb","newBuf","_nextId","allocateEffectId","v1EffectRegistry","ReactiveEffectLike","fn","scheduler","ctx","getRequestContext","parent","deps","getActiveEffect","_unsafeEffectImpl","options","attachToComponent","_effect","component","getComponent","registerEffectWithComponent","runner","unsafeEffect","__DEV__","trackEffect","dep","activeEffect","first","depsArr","queueJob","effect","flush","v2EffectRunner","setV2EffectRunner","draining","maybeV2","flags","setBatching","value","triggerEffects","ids","activeId","sync"],"mappings":"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","file":"chunk-CLNU7JKC.mjs","sourcesContent":["/**\n * PackedDepSet — Uint32Array-backed set of effect IDs.\n *\n * Drop-in replacement for `Set<ReactiveEffect>` in dependency tracking, with\n * three measurable wins:\n *   - **Memory**: 4 bytes per entry (Uint32) vs ~24-40 bytes for a Set entry\n *     with hash slot + pointer + V8 internal accounting.\n *   - **Cache locality**: linear scans walk a contiguous buffer that fits in\n *     a single L1 cache line for typical signal arity (1-4 subscribers).\n *   - **Pre-sized**: starts with capacity 4, doubles on overflow. Most signals\n *     fit forever in the initial allocation.\n *\n * Layout: `[id0, id1, ..., id(size-1), 0, 0, ...]`. The 0 sentinel is safe\n * because the effect-ID allocator never returns 0 (reserved as \"no effect\").\n *\n * Tracks size separately from buffer length so deletions can swap-with-last\n * in O(1) without leaving holes.\n */\nexport class PackedDepSet {\n    private _buf: Uint32Array\n    private _size: number = 0\n\n    constructor(initialCap = 4) {\n        this._buf = new Uint32Array(Math.max(4, initialCap))\n    }\n\n    get size(): number {\n        return this._size\n    }\n\n    get capacity(): number {\n        return this._buf.length\n    }\n\n    has(id: number): boolean {\n        const buf = this._buf\n        const len = this._size\n        for (let i = 0; i < len; i++) {\n            if (buf[i] === id) return true\n        }\n        return false\n    }\n\n    add(id: number): void {\n        if (this.has(id)) return\n        if (this._size >= this._buf.length) this._grow()\n        this._buf[this._size++] = id\n    }\n\n    delete(id: number): void {\n        const buf = this._buf\n        const len = this._size\n        for (let i = 0; i < len; i++) {\n            if (buf[i] === id) {\n                // Swap with last element and shrink — preserves dense packing\n                buf[i] = buf[len - 1]\n                buf[len - 1] = 0\n                this._size--\n                return\n            }\n        }\n    }\n\n    forEach(cb: (id: number) => void): void {\n        const buf = this._buf\n        const len = this._size\n        for (let i = 0; i < len; i++) {\n            cb(buf[i])\n        }\n    }\n\n    clear(): void {\n        this._buf.fill(0)\n        this._size = 0\n    }\n\n    toArray(): number[] {\n        return Array.from(this._buf.subarray(0, this._size))\n    }\n\n    private _grow(): void {\n        const newBuf = new Uint32Array(this._buf.length * 2)\n        newBuf.set(this._buf)\n        this._buf = newBuf\n    }\n}\n","/**\n * Effect ID allocator — Phase 4 monotonic counter for effect identity.\n *\n * Standalone module with no imports so it can be safely imported by both\n * `lifecycle.ts` (V1 effects) and `reactive-v2.ts` (V2 EffectRecord) without\n * creating a cycle.\n *\n * IDs are 32-bit unsigned integers. 0 is reserved as the \"empty slot\" sentinel\n * in dense typed arrays (PackedDepSet) and as the \"no effect\" comparison value.\n *\n * `reactive-v2.ts` re-exports `nextEffectId` / `__resetEffectId` from this\n * module so existing V2 call sites (and tests that call `__resetEffectId`)\n * continue to work unchanged.\n */\n\nlet _nextId = 1\n\nexport function allocateEffectId(): number {\n    return _nextId++\n}\n\n/** Alias used by V2 EffectRecord factory — same counter, different name for legacy reasons. */\nexport function nextEffectId(): number {\n    return _nextId++\n}\n\n/** @internal — test-only reset. */\nexport function resetEffectIdForTest(): void {\n    _nextId = 1\n}\n\n/** @internal — alias for V2 test code that calls `__resetEffectId`. */\nexport function __resetEffectId(): void {\n    _nextId = 1\n}\n","// Reactive effect system\n//\n// Phase 4 hot-path collection audit (2026-05-16):\n//\n//   COLD (module init, called once):\n//     - v1EffectRegistry: new Map<number, ReactiveEffectLike>  (lifecycle.ts:18)\n//     - globalRegistry:   new Map<string, RegistryEntry>        (use.ts:43)\n//     - effectQueue:      new Set<ReactiveEffect>               (request-context per-fork)\n//\n//   WARM (per component mount):\n//     - ReactiveEffectLike.deps: PackedDepSet[] = []           (lifecycle.ts:31)\n//     - DOMComponentInstance.children: new Set                 (render.ts:192)\n//     - instance.nodes: Node[]                                 (render.ts:96)\n//     - hookSignatures: string[] (dev only)                    (hook.ts:32)\n//     - effects: ReactiveEffectLike[]                          (hook.ts:99)\n//     - globalKeys: string[]                                   (use.ts:318/435)\n//\n//   HOT (per render / per signal trigger):\n//     - reconcile() resultNodes, toRemove, toInsert: Node[]    (render.ts:565/572/589)\n//     - renderNode array branch: oldKeys/usedKeys/nodes Set    (render.ts:318-340)\n//\n// Phase 4 pre-sizing strategy:\n//   - PackedDepSet already starts at capacity 4 — covers most signals\n//   - Component.effects[] starts empty; 95% of components have 0-2 effects so\n//     [] + lazy push is already optimal (no resize until > 7)\n//   - reconcile arrays start [] — typical lists have 0 inserts most renders;\n//     pre-sizing to a guessed N would waste memory on cold paths\n//   - The biggest single win remaining is avoiding the [...effectQueue] spread\n//     in flush() — Task 15 below\nimport { getComponent, registerEffectWithComponent } from './hook'\nimport { getRequestContext } from './request-context'\nimport { PackedDepSet } from './packed-dep-set'\nimport { allocateEffectId } from './effect-id-allocator'\n\n/**\n * V1 effect registry: maps the V1 effect's numeric ID back to its instance.\n *\n * Populated on construction, drained on `stop()`. Lookups happen in\n * triggerEffects, which now iterates a PackedDepSet of IDs instead of a\n * Set<ReactiveEffectLike> of references.\n *\n * V2 effect IDs share the same allocator (effect-id-allocator.ts re-exports\n * Phase 1's nextEffectId), so V1 and V2 effect IDs are guaranteed disjoint.\n * This map only holds V1 records — V2 records live in signal.effects directly.\n */\nconst v1EffectRegistry = new Map<number, ReactiveEffectLike>()\n\n/** @internal — test-only inspection of registry size. */\nexport function __v1EffectRegistrySize(): number {\n    return v1EffectRegistry.size\n}\n\nexport class ReactiveEffectLike {\n    readonly id: number\n    /**\n     * V1 dep tracking: each entry is the PackedDepSet that has registered this\n     * effect's ID. On re-run, cleanup() iterates these and calls .delete(this.id).\n     */\n    deps: PackedDepSet[] = []\n    active = true\n\n    constructor(\n        public fn: () => void,\n        public scheduler?: () => void\n    ) {\n        this.id = allocateEffectId()\n        v1EffectRegistry.set(this.id, this)\n    }\n\n    run() {\n        if (!this.active) {\n            return this.fn()\n        }\n\n        const ctx = getRequestContext()\n        const parent: ReactiveEffect | undefined = ctx.activeEffect\n        try {\n            this.cleanup()\n            ctx.activeEffect = this\n            return this.fn()\n        } finally {\n            ctx.activeEffect = parent\n        }\n    }\n\n    stop() {\n        if (this.active) {\n            this.cleanup()\n            this.active = false\n            v1EffectRegistry.delete(this.id)\n        }\n    }\n\n    cleanup() {\n        const { deps } = this\n        if (deps.length) {\n            for (let i = 0; i < deps.length; i++) {\n                deps[i].delete(this.id)\n            }\n            deps.length = 0\n        }\n    }\n}\n\n/** Get the currently running reactive effect (for the current request/execution context). */\nexport function getActiveEffect(): ReactiveEffect | undefined {\n    return getRequestContext().activeEffect\n}\n\nexport type ReactiveEffect = ReactiveEffectLike\n\nfunction _unsafeEffectImpl(\n    fn: () => void,\n    options: { scheduler?: () => void } = {},\n    attachToComponent: boolean\n): ((...args: unknown[]) => void) & { effect: ReactiveEffectLike } {\n    const _effect = new ReactiveEffectLike(fn, options.scheduler)\n    _effect.run()\n\n    if (attachToComponent) {\n        const component = getComponent()\n        if (component) {\n            registerEffectWithComponent(component, _effect)\n        }\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const runner: any = _effect.run.bind(_effect) // typed as any to allow attaching .effect property\n    runner.effect = _effect\n    return runner\n}\n\ninterface UnsafeEffectFn {\n    /**\n     * Run a reactive effect.\n     *\n     * When called inside a component render, the effect is automatically registered\n     * with the current component instance and is `.stop()`-ed on unmount.\n     *\n     * For framework-level or genuinely free-form effects that should survive component\n     * teardown, use {@link unsafeEffect.detached}.\n     *\n     * @example\n     * function Counter() {\n     *   const [count] = use(0);\n     *   unsafeEffect(() => console.log('count is', count()));\n     *   return f('div', null, count());\n     * }\n     */\n    (\n        fn: () => void,\n        options?: { scheduler?: () => void }\n    ): ((...args: unknown[]) => void) & { effect: ReactiveEffectLike }\n    /**\n     * Run a reactive effect WITHOUT auto-cleanup.\n     *\n     * Use only for renderers or genuinely root effects that must survive component\n     * teardown. Component-scoped effects should use plain {@link unsafeEffect}.\n     *\n     * @example\n     * unsafeEffect.detached(() => renderToDom(root));\n     */\n    detached(\n        fn: () => void,\n        options?: { scheduler?: () => void }\n    ): ((...args: unknown[]) => void) & { effect: ReactiveEffectLike }\n}\n\nexport const unsafeEffect: UnsafeEffectFn = ((fn: () => void, options?: { scheduler?: () => void }) =>\n    _unsafeEffectImpl(fn, options ?? {}, true)) as UnsafeEffectFn\n\nunsafeEffect.detached = (fn: () => void, options?: { scheduler?: () => void }) =>\n    _unsafeEffectImpl(fn, options ?? {}, false)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst __DEV__: boolean = (typeof process !== 'undefined' && (process as any)?.env?.NODE_ENV !== 'production')\n\nexport function trackEffect(dep: PackedDepSet) {\n    const { activeEffect } = getRequestContext()\n    if (activeEffect) {\n        // V1 active effect always has .id (PackedDepSet keys by ID).\n        // V2 EffectRecord also has .id but a different .deps shape\n        // (SignalContainer[] not PackedDepSet[]) — we still record the ID\n        // here, but skip pushing the dep into V2's deps list because that\n        // would corrupt V2's typed array.\n        if (__DEV__ && activeEffect.deps && activeEffect.deps.length > 0) {\n            // Sanity: the first dep should expose `.add(id)`/`.delete(id)`,\n            // matching PackedDepSet. If a V2 SignalContainer slips in, the\n            // shape diverges and we warn so the bug surfaces in development.\n            const first = activeEffect.deps[0] as unknown as { add?: unknown; delete?: unknown }\n            if (typeof first !== 'object' || first === null || typeof first.add !== 'function') {\n                console.warn(\n                    '[flexium] trackEffect(V1) called with a V2-shaped active effect. ' +\n                    'This indicates a V1/V2 routing bug — please report to the flexium maintainers.'\n                )\n            }\n        }\n        dep.add(activeEffect.id)\n        // Only push into deps if the deps array is V1-shaped (PackedDepSet entries).\n        // V2 EffectRecord.deps is SignalContainer[] — pushing a PackedDepSet would corrupt it.\n        // Detect by checking if the first existing entry is a PackedDepSet (has .add accepting number).\n        // For an empty deps array we cannot tell — but V2 effects only enter this path when reading\n        // a V1 reactive() proxy from inside a V2 effect, which is an exotic case the V2 code branch\n        // never produces in practice. Safe default: push.\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- effect.deps holds PackedDepSet[] in V1; in V2 path it is SignalContainer[] and we deliberately skip the push then.\n        const depsArr = activeEffect.deps as any[]\n        if (depsArr.length === 0 || depsArr[0] instanceof PackedDepSet) {\n            depsArr.push(dep)\n        }\n    }\n}\n\nexport function queueJob(effect: ReactiveEffect) {\n    const ctx = getRequestContext()\n    if (!ctx.effectQueue.has(effect)) {\n        ctx.effectQueue.add(effect)\n        if (!ctx.isFlushPending && !ctx.isBatching) {\n            ctx.isFlushPending = true\n            Promise.resolve().then(flush)\n        }\n    }\n}\n\n// Late-bound V2 dispatcher — set by reactive-v2.ts at module init to avoid\n// circular import. lifecycle.ts ↔ reactive-v2.ts cannot both static-import each\n// other (reactive-v2.ts already imports types from this module).\nlet v2EffectRunner: ((effect: unknown) => void) | null = null\n\n/** @internal — called from reactive-v2.ts at module init to register the V2 dispatcher. */\nexport function setV2EffectRunner(fn: (effect: unknown) => void): void {\n    v2EffectRunner = fn\n}\n\nexport function flush() {\n    const ctx = getRequestContext()\n    ctx.isFlushPending = false\n\n    // Phase 4: avoid `[...ctx.effectQueue]` spread which allocates a new Array\n    // per flush. Instead, swap the Set with a fresh one — the old Set is\n    // iterated locally and then discarded. Effects scheduled DURING iteration\n    // land in the new Set and will flush on the next microtask, matching the\n    // intended single-microtask semantics.\n    const draining = ctx.effectQueue\n    ctx.effectQueue = new Set()\n\n    for (const effect of draining) {\n        // V1 effects expose .active + .run(); V2 effects (EffectRecord) expose .flags + .id.\n        // Duck-type detection — branch lets V1 sync() drain V2-queued records.\n        const maybeV2 = effect as unknown as { flags?: number; id?: number; run?: () => void }\n        if (typeof maybeV2.run === 'function') {\n            if (effect.active) effect.run()\n        } else if (typeof maybeV2.flags === 'number' && v2EffectRunner) {\n            // V2 record in the queue — clear SCHEDULED bit + dispatch via V2 runner.\n            const flags = maybeV2.flags\n            if ((flags & 0b0001) !== 0) {  // EFFECT_ACTIVE\n                maybeV2.flags = flags & ~0b0100  // clear EFFECT_SCHEDULED\n                v2EffectRunner(effect)\n            }\n        }\n    }\n}\n\nexport function setBatching(value: boolean) {\n    getRequestContext().isBatching = value\n}\n\nexport function triggerEffects(dep: PackedDepSet) {\n    // Snapshot IDs into a local typed array to make iteration safe against\n    // re-entrant modifications (effect.run() may call cleanup which mutates\n    // dep). Snapshot allocation is bounded by signal arity.\n    const ids = dep.toArray()\n    const { activeEffect } = getRequestContext()\n    const activeId = activeEffect?.id ?? 0\n    for (let i = 0; i < ids.length; i++) {\n        const id = ids[i]\n        if (id === activeId) continue\n        const effect = v1EffectRegistry.get(id)\n        if (!effect || !effect.active) continue\n        if (effect.scheduler) {\n            effect.scheduler()\n        } else {\n            queueJob(effect)\n        }\n    }\n}\n\n/**\n * Unified sync API\n * - sync(): Force refresh (flush pending effects)\n * - sync(fn): Batch updates (run fn then flush)\n */\nexport function sync(fn?: () => void) {\n    if (fn) {\n        setBatching(true)\n        try {\n            fn()\n        } finally {\n            setBatching(false)\n            flush()\n        }\n    } else {\n        flush()\n    }\n}\n"]}