{"version":3,"file":"addons.mjs","sources":["../src/addons/computed.js","../src/addons/watch.js","../src/addons/repeat.js","../src/addons/debug.js","../src/addons/withPlugins.js","../src/addons/cleanupGroup.js","../src/addons/hydrateState.js","../src/addons/persist.js","../src/addons/index.js"],"sourcesContent":["/**\n * Lume-JS Computed Addon\n * \n * Creates computed values that automatically update when dependencies change.\n * Uses core effect() for automatic dependency tracking.\n * \n * Usage:\n *   import { computed } from \"lume-js/addons/computed\";\n *   \n *   const doubled = computed(() => store.count * 2);\n *   console.log(doubled.value); // Auto-updates when store.count changes\n * \n * Features:\n * - Automatic dependency tracking (no manual recompute)\n * - Cached values (only recomputes when dependencies change)\n * - Subscribe to changes\n * - Cleanup with dispose()\n * \n * @module addons/computed\n */\n\nimport { effect } from '../core/effect.js';\nimport { logError } from '../utils/log.js';\n\n/**\n * Creates a computed value with automatic dependency tracking\n * \n * The computation function runs immediately and tracks which state\n * properties are accessed. When any dependency changes, the value\n * is automatically recomputed.\n *\n * ⚠️ Circular self-mutations are automatically suppressed. If a computed\n * mutates a state property it depends on, the flush triggered by that\n * mutation is skipped to prevent an infinite microtask loop.\n *\n * @security After each computation, a re-entry guard stays active until the\n * next microtask. If a dependency changes synchronously during this window,\n * the computed will not recompute until a subsequent microtask. This is\n * intentional — it prevents infinite loops from self-mutating computeds.\n *\n * @param {function} fn - Function that computes the value\n * @returns {object} Object with .value property and methods\n * \n * @example\n * const store = state({ count: 5 });\n * \n * const doubled = computed(() => store.count * 2);\n * console.log(doubled.value); // 10\n * \n * store.count = 10;\n * // After microtask:\n * console.log(doubled.value); // 20 (auto-updated)\n * \n * @example\n * // Subscribe to changes\n * const unsub = doubled.subscribe(value => {\n *   console.log('Doubled changed to:', value);\n * });\n * \n * @example\n * // Cleanup\n * doubled.dispose();\n */\nexport function computed(fn) {\n  if (typeof fn !== 'function') {\n    throw new Error('computed() requires a function');\n  }\n\n  let cachedValue;\n  let isInitialized = false;\n  let isInComputation = false;\n  let disposed = false;\n  const subscribers = [];\n\n  // Use effect to automatically track dependencies\n  const cleanupEffect = effect(() => {\n    // Skip re-entry from a flush triggered by our own synchronous mutation.\n    // The mutation inside fn() queues a microtask flush; we stay flagged\n    // until a subsequent microtask clears it, so that flush is dropped.\n    if (isInComputation || disposed) return;\n\n    isInComputation = true;\n\n    try {\n      const newValue = fn();\n\n      // Check if value actually changed - Object.is() handles NaN and -0\n      if (!isInitialized || !Object.is(newValue, cachedValue)) {\n        cachedValue = newValue;\n        isInitialized = true;\n\n        // Notify all subscribers\n        subscribers.forEach(callback => callback(cachedValue));\n      }\n    } catch (error) {\n      logError('[Lume.js computed] Error in computation:', error);\n      // Set to undefined on error, mark as initialized\n      if (!isInitialized || cachedValue !== undefined) {\n        cachedValue = undefined;\n        isInitialized = true;\n\n        // Notify subscribers of error state\n        subscribers.forEach(callback => callback(cachedValue));\n      }\n    } finally {\n      // Defer clearing the flag so any flush microtask queued by fn()\n      // sees it still set and skips re-entry.\n      queueMicrotask(() => {\n        if (!disposed) {\n          isInComputation = false;\n        }\n      });\n    }\n  });\n\n  return {\n    /**\n     * Get the current computed value\n     */\n    get value() {\n      if (!isInitialized) {\n        throw new Error('Computed value accessed before initialization');\n      }\n      return cachedValue;\n    },\n\n    /**\n     * Subscribe to changes in computed value\n     * \n     * @param {function} callback - Called when value changes\n     * @returns {function} Unsubscribe function\n     */\n    subscribe(callback) {\n      if (typeof callback !== 'function') {\n        throw new Error('subscribe() requires a function');\n      }\n\n      subscribers.push(callback);\n\n      // Call immediately with current value\n      if (isInitialized) {\n        callback(cachedValue);\n      }\n\n      // Return unsubscribe function\n      return () => {\n        const index = subscribers.indexOf(callback);\n        if (index > -1) {\n          subscribers.splice(index, 1);\n        }\n      };\n    },\n\n    /**\n     * Clean up computed value and stop tracking\n     */\n    dispose() {\n      disposed = true;\n      cleanupEffect();\n      subscribers.length = 0;\n      isInitialized = false;\n      isInComputation = false;\n    }\n  };\n}","/**\n * watch - observes changes to a state key and triggers callback\n * @param {Object} store - reactive store created with state()\n * @param {string} key - key in store to watch\n * @param {Function} callback - called with new value\n * @param {Object} [options]\n * @param {boolean} [options.immediate=true] - call callback immediately with current value\n * @returns {Function} unsubscribe function\n */\nexport function watch(store, key, callback, { immediate = true } = {}) {\n  if (!store.$subscribe) {\n    throw new Error(\"store must be created with state()\");\n  }\n  if (!immediate) {\n    let skipped = false;\n    return store.$subscribe(key, (val) => {\n      if (!skipped) { skipped = true; return; }\n      callback(val);\n    });\n  }\n  return store.$subscribe(key, callback);\n}","/**\n * Lume-JS List Rendering (Addon)\n *\n * Renders lists with automatic subscription and element reuse by key.\n * \n * Core guarantees:\n * Element reuse by key (same DOM nodes, not recreated)\n * Minimal DOM operations (only updates what changed)\n * Memory efficiency (cleanup on remove)\n * \n * Default behavior (can be disabled/customized):\n * ✅ Focus preservation (maintains activeElement and selection)\n * ✅ Scroll preservation (intelligent positioning for add/remove/reorder)\n * \n * Philosophy: No artificial limitations\n * - All preservation logic is overridable via options\n * - Set to null/false to disable, or provide custom functions\n * - Export utilities so you can wrap/extend them\n *\n * ⚠️ IMPORTANT: Arrays must be updated immutably!\n * store.items.push(x)      // ❌ Won't trigger update\n * store.items = [...items] // ✅ Triggers update\n * \n * ═══════════════════════════════════════════════════════════════════════\n * PATTERN 0: Template-based (recommended) — declarative, zero DOM code\n * ═══════════════════════════════════════════════════════════════════════\n *\n *   HTML — a standard <template> element, valid HTML, no custom syntax:\n *\n *   <ul id=\"list\">\n *     <template>\n *       <li>\n *         <strong data-bind=\"name\"></strong>\n *         <span data-bind=\"role\"></span>\n *         <em data-bind=\"$index\"></em>\n *       </li>\n *     </template>\n *   </ul>\n *\n *   JS:\n *\n *   repeat('#list', store, 'people', {\n *     key: p => p.id,\n *     template: true   // use the <template> inside the container\n *   });\n *\n *   data-bind paths resolve against EACH ITEM: \"name\" → item.name,\n *   \"user.city\" → item.user.city, \"$item\" → the item itself (primitive\n *   arrays), \"$index\" → current index. Inputs get .value/.checked, other\n *   elements get textContent — identical semantics to bindDom's data-bind.\n *   These are one-way snapshot bindings re-applied per list update (items\n *   are plain objects, not stores). Combine with create/update for event\n *   listeners or extra binding. template also accepts a CSS selector or an\n *   HTMLTemplateElement.\n *\n * ═══════════════════════════════════════════════════════════════════════\n * PATTERN 1: Simple (render only) - for simple cases or backward compat\n * ═══════════════════════════════════════════════════════════════════════\n * \n *   repeat('#list', store, 'todos', {\n *     key: todo => todo.id,\n *     render: (todo, el) => {\n *       el.textContent = todo.name;  // Called on every update\n *     }\n *   });\n *\n * ═══════════════════════════════════════════════════════════════════════\n * PATTERN 2: Clean separation (create + update) - recommended\n * ═══════════════════════════════════════════════════════════════════════\n *\n *   repeat('#list', store, 'todos', {\n *     key: todo => todo.id,\n *     create: (todo, el) => {\n *       // Called ONCE when element is created - build DOM structure\n *       const nameSpan = document.createElement('span');\n *       nameSpan.className = 'name';\n *       el.appendChild(nameSpan);\n *       const btn = document.createElement('button');\n *       btn.textContent = 'Delete';\n *       btn.onclick = () => deleteTodo(todo.id);\n *       el.appendChild(btn);\n *\n *       // Return a cleanup function — called automatically when element is removed\n *       return () => {\n *         // Unsubscribe from external listeners, remove timers, etc.\n *       };\n *     },\n *     update: (todo, el, index, { isFirstRender }) => {\n *       // Called on every update - bind data\n *       // isFirstRender = true on initial render, false on subsequent\n *       // Skipped if same object reference (optimization)\n *       el.querySelector('.name').textContent = todo.name;\n *     }\n *   });\n *\n * ═══════════════════════════════════════════════════════════════════════\n * ADVANCED: Custom preservation strategies\n * ═══════════════════════════════════════════════════════════════════════\n * \n *   import { defaultFocusPreservation, defaultScrollPreservation } from \"lume-js/addons\";\n *   \n *   repeat('#list', store, 'items', {\n *     key: item => item.id,\n *     create: (item, el) => { ... },\n *     update: (item, el) => { ... },\n *     preserveFocus: null, // disable focus preservation\n *     preserveScroll: (container, context) => {\n *       const restore = defaultScrollPreservation(container, context);\n *       return () => { restore(); console.log('Scroll restored!'); };\n *     }\n *   });\n */\nimport { logWarn, logError } from '../utils/log.js';\nimport { applyBindValue } from '../core/bindDom.js';\n\n/**\n * Mark the longest increasing subsequence over the previous positions of\n * reused nodes — the maximal set already in the right relative order, which\n * reconciliation can leave untouched. positions[i] is node i's previous\n * index, or -1 for brand-new nodes (never part of the chain). Patience\n * sorting with predecessor links, O(n log n).\n *\n * @param {number[]} positions - previous index per desired slot (-1 = new)\n * @returns {boolean[]} true where the node keeps its place\n */\nfunction stableChainMarkers(positions) {\n  const n = positions.length;\n  const prev = new Array(n);\n  const tails = []; // indices of chain tails, one per chain length\n  for (let i = 0; i < n; i++) {\n    const v = positions[i];\n    if (v < 0) continue;\n    let lo = 0;\n    let hi = tails.length;\n    while (lo < hi) {\n      const mid = (lo + hi) >> 1;\n      if (positions[tails[mid]] < v) lo = mid + 1;\n      else hi = mid;\n    }\n    prev[i] = lo > 0 ? tails[lo - 1] : -1;\n    tails[lo] = i;\n  }\n  const settled = new Array(n).fill(false);\n  let k = tails.length ? tails[tails.length - 1] : -1;\n  while (k !== -1) {\n    settled[k] = true;\n    k = prev[k];\n  }\n  return settled;\n}\n\n/**\n * Resolve the template option to the <template> element.\n * Accepts true (first <template> inside the container), a CSS selector,\n * or an HTMLTemplateElement directly.\n */\nfunction resolveTemplateEl(template, containerEl) {\n  let templateEl = template;\n  if (template === true) {\n    templateEl = containerEl.querySelector('template');\n  } else if (typeof template === 'string') {\n    templateEl = document.querySelector(template);\n  }\n  if (!templateEl || templateEl.tagName !== 'TEMPLATE') {\n    throw new Error('[Lume.js] repeat(): template not found or not a <template> element');\n  }\n  if (templateEl.content.children.length !== 1) {\n    throw new Error('[Lume.js] repeat(): template must contain exactly one root element');\n  }\n  return templateEl;\n}\n\n/**\n * Resolve the template option to its clone root, plus the container child\n * that is (or contains) the source <template>. Reconciliation and cleanup\n * must leave that child alone — it's the user's markup, and removing it\n * would break re-binding with `template: true` after cleanup. keepEl is\n * null when there is no template or it lives outside the container.\n */\nfunction resolveTemplate(template, containerEl) {\n  if (!template) return { templateRoot: null, keepEl: null };\n  const templateEl = resolveTemplateEl(template, containerEl);\n  let keepEl = templateEl;\n  while (keepEl && keepEl.parentNode !== containerEl) keepEl = keepEl.parentNode;\n  return { templateRoot: templateEl.content.firstElementChild, keepEl };\n}\n\n/**\n * Collect [data-bind] nodes of a cloned item element into a compiled\n * binding list. Paths are resolved against the ITEM (not the store):\n *   data-bind=\"name\"      → item.name\n *   data-bind=\"user.city\" → item.user.city\n *   data-bind=\"$item\"     → the item itself (for primitive arrays)\n *   data-bind=\"$index\"    → the item's current index\n */\nfunction collectItemBindings(el) {\n  const bindings = [];\n  const add = (node) => {\n    const path = node.getAttribute('data-bind');\n    bindings.push({ node, path, keys: path === '$item' || path === '$index' ? null : path.split('.') });\n  };\n  if (el.hasAttribute('data-bind')) add(el);\n  for (const node of el.querySelectorAll('[data-bind]')) add(node);\n  return bindings;\n}\n\nfunction applyItemBindings(bindings, item, index) {\n  for (const b of bindings) {\n    let val;\n    if (b.path === '$index') {\n      val = index;\n    } else if (b.path === '$item') {\n      val = item;\n    } else {\n      val = item;\n      for (let i = 0; i < b.keys.length && val != null; i++) {\n        val = val[b.keys[i]];\n      }\n    }\n    applyBindValue(b.node, val);\n  }\n}\n\n/**\n * Default focus preservation strategy\n * Saves activeElement and selection state before DOM updates\n * \n * @param {HTMLElement} container - The list container\n * @returns {Function|null} Restore function, or null if nothing to restore\n */\nexport function defaultFocusPreservation(container) {\n  const activeEl = document.activeElement;\n  const shouldRestore = container.contains(activeEl);\n\n  if (!shouldRestore) return null;\n\n  let selectionStart = null;\n  let selectionEnd = null;\n\n  if (activeEl.tagName === 'INPUT' || activeEl.tagName === 'TEXTAREA') {\n    selectionStart = activeEl.selectionStart;\n    selectionEnd = activeEl.selectionEnd;\n  }\n\n  return () => {\n    if (document.body.contains(activeEl)) {\n      activeEl.focus();\n      if (selectionStart !== null && selectionEnd !== null) {\n        activeEl.setSelectionRange(selectionStart, selectionEnd);\n      }\n    }\n  };\n}\n\n/**\n * Default scroll preservation strategy\n * Uses anchor-based preservation for add/remove, pixel position for reorder\n * \n * @param {HTMLElement} container - The list container\n * @param {Object} context - Additional context\n * @param {boolean} context.isReorder - Whether this is a reorder operation\n * @returns {Function} Restore function\n */\nexport function defaultScrollPreservation(container, context = {}) {\n  const { isReorder = false } = context;\n  const scrollTop = container.scrollTop;\n\n  // Early return if no scroll\n  if (scrollTop === 0) {\n    return () => { container.scrollTop = 0; };\n  }\n\n  let anchorElement = null;\n  let anchorOffset = 0;\n\n  // Only use anchor-based preservation for add/remove, not reorder\n  if (!isReorder) {\n    const containerRect = container.getBoundingClientRect();\n    // Avoid Array.from - iterate children directly\n    for (let child = container.firstElementChild; child; child = child.nextElementSibling) {\n      const rect = child.getBoundingClientRect();\n\n      if (rect.bottom > containerRect.top) {\n        anchorElement = child;\n        anchorOffset = rect.top - containerRect.top;\n        break;\n      }\n    }\n  }\n\n  return () => {\n    if (anchorElement && document.body.contains(anchorElement)) {\n      const newRect = anchorElement.getBoundingClientRect();\n      const containerRect = container.getBoundingClientRect();\n      const currentOffset = newRect.top - containerRect.top;\n      const scrollAdjustment = currentOffset - anchorOffset;\n\n      container.scrollTop = container.scrollTop + scrollAdjustment;\n    } else {\n      container.scrollTop = scrollTop;\n    }\n  };\n}\n\n/**\n * Efficiently render a list with element reuse\n * \n * @param {string|HTMLElement} container - Container element or selector\n * @param {Object} store - Reactive state object\n * @param {string} arrayKey - Key in store containing the array\n * @param {Object} options - Configuration\n * @param {Function} options.key - Function to extract unique key: (item) => key\n * @param {Function} [options.render] - Function to render item (called for all items): (item, element, index) => void\n * @param {Function} [options.create] - Function for new elements only: (item, element, index) => void | Function. If a function is returned, it is registered as the element's cleanup and called automatically when the element is removed (by list update or full cleanup).\n * @param {Function} [options.update] - Function for data binding: (item, element, index, { isFirstRender }) => void. Skipped if same item reference AND same index.\n * @param {Function} [options.remove] - Additional cleanup when element is removed: (item, element) => void. Called after any cleanup function returned by create(). Optional — prefer returning a cleanup from create() for automatic lifecycle management.\n * @param {true|string|HTMLTemplateElement} [options.template] - Declarative item structure from a <template> element: true = first <template> inside the container, string = CSS selector, or the element itself. The template must have exactly one root element; it is cloned per item and its [data-bind] paths are bound to the item on every update (\"name\", \"user.city\", \"$item\", \"$index\"). When set, options.element is ignored and options.render is ignored (with a warning); create/update remain available on top.\n * @param {string|Function} [options.element='div'] - Element tag name or factory function (ignored when options.template is set)\n * @param {Function|null} [options.preserveFocus=defaultFocusPreservation] - Focus preservation strategy (null to disable)\n * @param {Function|null} [options.preserveScroll=defaultScrollPreservation] - Scroll preservation strategy (null to disable)\n * @returns {Function} Cleanup function\n */\n\nexport function repeat(container, store, arrayKey, options) {\n  const {\n    key,\n    render,\n    create,\n    update,\n    remove,\n    template = null,\n    element = 'div',\n    preserveFocus = defaultFocusPreservation,\n    preserveScroll = defaultScrollPreservation\n  } = options;\n\n  // Resolve container\n  const containerEl =\n    typeof container === 'string'\n      ? document.querySelector(container)\n      : container;\n\n  if (!containerEl) {\n    logWarn(`[Lume.js] repeat(): container \"${container}\" not found`);\n    return () => { };\n  }\n\n  if (typeof key !== 'function') {\n    throw new Error('[Lume.js] repeat(): options.key must be a function');\n  }\n\n  // Template mode: structure and data binding come from the <template>;\n  // render/create/update are all optional on top of it.\n  const { templateRoot, keepEl } = resolveTemplate(template, containerEl);\n\n  if (templateRoot && typeof render === 'function') {\n    logWarn('[Lume.js] repeat(): options.render is ignored when options.template is set — use create/update instead');\n  }\n\n  if (!templateRoot && typeof render !== 'function' && typeof create !== 'function') {\n    throw new Error('[Lume.js] repeat(): options.render or options.create must be a function');\n  }\n\n  // key -> HTMLElement\n  const elementsByKey = new Map();\n  // key -> previous item (for reference comparison)\n  const prevItemsByKey = new Map();\n  // key -> previous index (for reorder detection)\n  const prevIndexByKey = new Map();\n  // key -> cleanup function returned by create()\n  const cleanupByKey = new Map();\n  // key -> compiled [data-bind] nodes of the clone (template mode only)\n  const bindingsByKey = new Map();\n  const seenKeys = new Set();\n\n  function createElement() {\n    if (templateRoot) return templateRoot.cloneNode(true);\n    return typeof element === 'function'\n      ? element()\n      : document.createElement(element);\n  }\n\n  /**\n   * Empty the container, preserving the in-container source template.\n   * Manual removal (not replaceChildren) for two reasons: replaceChildren\n   * is Chrome 86+/Safari 14+ — above the documented ES2020-era browser\n   * floor — and re-inserting keepEl would re-parent a template the user\n   * has since moved (or resurrect one they deleted).\n   */\n  function clearContainer() {\n    let node = containerEl.firstChild;\n    while (node) {\n      const next = node.nextSibling;\n      if (node !== keepEl) containerEl.removeChild(node);\n      node = next;\n    }\n  }\n\n  // Reorders with minimal moves: nodes whose previous positions already\n  // form an increasing chain (the longest one) are in the right relative\n  // order and never touched; everything else is inserted before the\n  // nearest settled node, walking end to start. Moving a DOM node is the\n  // expensive part of a list update (layout invalidation, and iframes or\n  // videos reset when reinserted), so a k-item change costs O(k) moves\n  // instead of cascading into every node after the first mismatch.\n  function reconcileDOM(container, nextEls) {\n    // Drop rows that left the list first, so they don't shift the\n    // stability math (the source template is never a row).\n    const staying = new Set(nextEls);\n    let node = container.firstChild;\n    while (node) {\n      const next = node.nextSibling;\n      if (node !== keepEl && !staying.has(node)) container.removeChild(node);\n      node = next;\n    }\n\n    // Previous index of every surviving row.\n    const prevIndex = new Map();\n    let pi = 0;\n    for (let el = container.firstElementChild; el; el = el.nextElementSibling) {\n      if (el !== keepEl) prevIndex.set(el, pi++);\n    }\n\n    const positions = new Array(nextEls.length);\n    for (let i = 0; i < nextEls.length; i++) {\n      const p = prevIndex.get(nextEls[i]);\n      positions[i] = p === undefined ? -1 : p; // -1: brand-new node\n    }\n    const settled = stableChainMarkers(positions);\n\n    let anchor = null; // insert before this; null appends at the end\n    for (let i = nextEls.length - 1; i >= 0; i--) {\n      const el = nextEls[i];\n      if (settled[i]) {\n        anchor = el;\n        continue;\n      }\n      container.insertBefore(el, anchor);\n      anchor = el;\n    }\n  }\n\n  function applyPreservation(container, fn, isReorder) {\n    const shouldPreserve = document.body.contains(container);\n    const restoreFocus = shouldPreserve && preserveFocus ? preserveFocus(container) : null;\n    const restoreScroll = shouldPreserve && preserveScroll ? preserveScroll(container, { isReorder }) : null;\n\n    fn();\n\n    if (restoreFocus) restoreFocus();\n    if (restoreScroll) restoreScroll();\n  }\n\n  // eslint-disable-next-line sonarjs/cognitive-complexity -- keyed DOM reconciliation: create/reuse/remove nodes, key dedup, scroll/focus preservation\n  function updateList() {\n    const items = store[arrayKey];\n\n    if (!Array.isArray(items)) {\n      logWarn(`[Lume.js] repeat(): store.${arrayKey} is not an array`);\n      return;\n    }\n\n    // Only compute isReorder if scroll preservation needs it.\n    // Uses elementsByKey (previous state) and items directly — no Set allocations.\n    let isReorder = false;\n    if (preserveScroll && elementsByKey.size === items.length) {\n      isReorder = true;\n      for (let i = 0; i < items.length; i++) {\n        if (!elementsByKey.has(key(items[i]))) { isReorder = false; break; }\n      }\n    }\n\n    seenKeys.clear();\n    const nextEls = [];\n\n    // Build ordered list of DOM nodes (created or reused)\n    for (let i = 0; i < items.length; i++) {\n      const item = items[i];\n      const k = key(item);\n\n      if (seenKeys.has(k)) {\n        logWarn(`[Lume.js] repeat(): duplicate key \"${k}\"`);\n        continue;\n      }\n      seenKeys.add(k);\n\n      let el = elementsByKey.get(k);\n      const isFirstRender = !el;\n\n      if (isFirstRender) {\n        el = createElement();\n        elementsByKey.set(k, el);\n        if (templateRoot) {\n          bindingsByKey.set(k, collectItemBindings(el));\n        }\n      }\n\n      try {\n        // Call create for new elements (DOM structure / event listeners)\n        if (isFirstRender && create) {\n          const cleanup = create(item, el, i);\n          if (typeof cleanup === 'function') {\n            cleanupByKey.set(k, cleanup);\n          }\n        }\n\n        // Data binding (new and existing elements)\n        // Skip if same item reference AND same index (optimization)\n        const prevItem = prevItemsByKey.get(k);\n        const prevIndex = prevIndexByKey.get(k);\n        if (templateRoot) {\n          if (prevItem !== item || prevIndex !== i) {\n            applyItemBindings(bindingsByKey.get(k), item, i);\n            // update is optional extra binding on top of the template\n            if (update) update(item, el, i, { isFirstRender });\n          }\n        } else if (update) {\n          if (prevItem !== item || prevIndex !== i) {\n            update(item, el, i, { isFirstRender });\n          }\n        } else if (render) {\n          // Backward compatibility: render handles both create and update\n          render(item, el, i);\n        }\n\n        // Store reference and index for next comparison\n        prevItemsByKey.set(k, item);\n        prevIndexByKey.set(k, i);\n\n      } catch (err) {\n        logError(`[Lume.js] repeat(): error rendering key \"${k}\":`, err);\n      }\n\n      nextEls.push(el);\n    }\n\n    // eslint-disable-next-line sonarjs/cognitive-complexity -- DOM cleanup pass: remove stale nodes, call per-item cleanup callbacks, update maps\n    applyPreservation(containerEl, () => {\n      reconcileDOM(containerEl, nextEls);\n\n      // Clean maps: remove keys not in seenKeys (new state)\n      if (elementsByKey.size !== seenKeys.size) {\n        for (const k of elementsByKey.keys()) {\n          if (!seenKeys.has(k)) {\n            const el = elementsByKey.get(k);\n            const prevItem = prevItemsByKey.get(k);\n            // Call create-returned cleanup first, then remove callback\n            const cleanup = cleanupByKey.get(k);\n            if (typeof cleanup === 'function') {\n              try {\n                cleanup();\n              } catch (err) {\n                logError(`[Lume.js] repeat(): cleanup error for key \"${k}\":`, err);\n              }\n            }\n            if (typeof remove === 'function' && el) {\n              remove(prevItem, el);\n            }\n            elementsByKey.delete(k);\n            prevItemsByKey.delete(k);\n            prevIndexByKey.delete(k);\n            cleanupByKey.delete(k);\n            bindingsByKey.delete(k);\n          }\n        }\n      }\n    }, isReorder);\n  }\n\n  // Subscription — $subscribe calls updateList immediately (initial render),\n  // so no separate updateList() call is needed for reactive stores.\n  let unsubscribe;\n  if (typeof store.$subscribe === 'function') {\n    unsubscribe = store.$subscribe(arrayKey, updateList);\n  } else if (typeof store.subscribe === 'function') {\n    // Generic subscribe (e.g. computed) — subscribe first, then initial render\n    const subResult = store.subscribe(() => updateList());\n    updateList();\n    // Normalize both function-style and object-style (RxJS Subscription) returns\n    unsubscribe = typeof subResult === 'function'\n      ? subResult\n      : () => { subResult?.unsubscribe?.(); };\n  } else {\n    // Non-reactive store — render once and return cleanup\n    updateList();\n    logWarn('[Lume.js] repeat(): store is not reactive (no $subscribe or subscribe method)');\n    return () => {\n      for (const [k, el] of elementsByKey) {\n        const prevItem = prevItemsByKey.get(k);\n        const cleanup = cleanupByKey.get(k);\n        if (typeof cleanup === 'function') {\n          try {\n            cleanup();\n          } catch (err) {\n            logError(`[Lume.js] repeat(): cleanup error for key \"${k}\":`, err);\n          }\n        }\n        if (typeof remove === 'function') {\n          remove(prevItem, el);\n        }\n      }\n      clearContainer();\n      elementsByKey.clear();\n      prevItemsByKey.clear();\n      prevIndexByKey.clear();\n      cleanupByKey.clear();\n      bindingsByKey.clear();\n      seenKeys.clear();\n    };\n  }\n\n  return () => {\n    if (typeof unsubscribe === 'function') {\n      unsubscribe();\n    }\n    // Invoke cleanup and remove callback for all remaining elements before clearing\n    for (const [k, el] of elementsByKey) {\n      const prevItem = prevItemsByKey.get(k);\n      const cleanup = cleanupByKey.get(k);\n      if (typeof cleanup === 'function') {\n        try {\n          cleanup();\n        } catch (err) {\n          logError(`[Lume.js] repeat(): cleanup error for key \"${k}\":`, err);\n        }\n      }\n      if (typeof remove === 'function') {\n        remove(prevItem, el);\n      }\n    }\n    // Clear DOM elements (preserving the source template, if any)\n    clearContainer();\n    elementsByKey.clear();\n    prevItemsByKey.clear();\n    prevIndexByKey.clear();\n    cleanupByKey.clear();\n    bindingsByKey.clear();\n    seenKeys.clear();\n  };\n}\n","/**\n * Lume-JS Debug Addon\n * \n * Developer-friendly logging and inspection of reactive state operations.\n * Critical for adoption - hard to debug = hard to adopt.\n * \n * Usage:\n *   import { state } from \"lume-js\";\n *   import { withPlugins, createDebugPlugin, debug } from \"lume-js/addons\";\n *   \n *   const store = withPlugins(state({ count: 0 }), [createDebugPlugin({ label: 'myStore' })]);\n *   \n *   debug.enable();  // Enable logging\n *   debug.filter('count');  // Only log 'count' key\n *   debug.stats();  // Show statistics\n * \n * @module addons/debug\n */\n\n// Global debug state\nlet globalEnabled = true;\nlet globalFilter = null; // string, RegExp, or null\nconst stats = new Map(); // label -> { gets: Map, sets: Map, notifies: Map }\n\n/**\n * Check if a key matches the current filter\n * @param {string} key\n * @returns {boolean}\n */\nfunction matchesFilter(key) {\n  if (globalFilter === null) return true;\n  if (typeof globalFilter === 'string') {\n    return key.includes(globalFilter);\n  }\n  if (globalFilter instanceof RegExp) {\n    return globalFilter.test(key);\n  }\n  return true;\n}\n\n/**\n * Get or create stats entry for a label\n * @param {string} label\n * @returns {object}\n */\nfunction getStats(label) {\n  if (!stats.has(label)) {\n    stats.set(label, {\n      gets: new Map(),\n      sets: new Map(),\n      notifies: new Map()\n    });\n  }\n  return stats.get(label);\n}\n\n/**\n * Increment a stat counter\n * @param {string} label\n * @param {'gets'|'sets'|'notifies'} type\n * @param {string} key\n */\nfunction incrementStat(label, type, key) {\n  const s = getStats(label);\n  const map = s[type];\n  map.set(key, (map.get(key) || 0) + 1);\n}\n\nconst MAX_LOG_LEN = 100;\nconst TRUNCATED_LEN = MAX_LOG_LEN - 3;\n\n/**\n * Format value for logging (truncate long values)\n * @param {any} value\n * @returns {string}\n */\nfunction formatValue(value) {\n  try {\n    const json = JSON.stringify(value);\n    if (json.length > MAX_LOG_LEN) {\n      return json.slice(0, TRUNCATED_LEN) + '...';\n    }\n    return json;\n  } catch {\n    return String(value);\n  }\n}\n\n/**\n * Create a debug plugin instance for a reactive state store.\n * \n * @param {object} [options] - Configuration options\n * @param {string} [options.label='store'] - Label for log messages\n * @param {boolean} [options.logGet=false] - Log property reads (can be noisy)\n * @param {boolean} [options.logSet=true] - Log property writes\n * @param {boolean} [options.logNotify=true] - Log subscriber notifications\n * @param {boolean} [options.trace=false] - Show stack trace for SET operations\n * @returns {object} Plugin object for state()\n * \n * @example\n * const store = withPlugins(state({ count: 0 }), [createDebugPlugin({ label: 'counter' })]);\n * \n * @example\n * // With stack traces for debugging where state changes originate\n * const store = withPlugins(state({ count: 0 }), [createDebugPlugin({ label: 'counter', trace: true })]);\n */\nexport function createDebugPlugin(options = {}) {\n  const label = options.label ?? 'store';\n\n  // IMPORTANT: Do NOT destructure options here!\n  // Options may contain getters for dynamic runtime toggling (e.g., from UI).\n  // Destructuring would copy values once at creation time, breaking reactivity.\n  // Use getOpt() helper to read options dynamically in each hook.\n  const getOpt = (name, defaultVal) => {\n    const val = options[name];\n    return val !== undefined ? val : defaultVal;\n  };\n\n  return {\n    name: `debug:${label}`,\n\n    onInit: () => {\n      if (globalEnabled) {\n        console.log(`%c[${label}]%c initialized`, 'color: #888; font-weight: bold', 'color: inherit');\n      }\n    },\n\n    onGet: (key, value) => {\n      // Skip internal properties\n      if (typeof key === 'string' && key.startsWith('$')) {\n        return value;\n      }\n\n      incrementStat(label, 'gets', key);\n\n      if (globalEnabled && getOpt('logGet', false) && matchesFilter(key)) {\n        console.log(\n          `%c[${label}]%c GET %c${key}%c = ${formatValue(value)}`,\n          'color: #888; font-weight: bold',\n          'color: #4CAF50',\n          'color: #2196F3; font-weight: bold',\n          'color: inherit'\n        );\n      }\n\n      return value;\n    },\n\n    onSet: (key, newValue, oldValue) => {\n      // Skip internal properties\n      if (typeof key === 'string' && key.startsWith('$')) {\n        return newValue;\n      }\n\n      incrementStat(label, 'sets', key);\n\n      if (globalEnabled && getOpt('logSet', true) && matchesFilter(key)) {\n        console.log(\n          `%c[${label}]%c SET %c${key}%c: ${formatValue(oldValue)} → ${formatValue(newValue)}`,\n          'color: #888; font-weight: bold',\n          'color: #FF9800',\n          'color: #2196F3; font-weight: bold',\n          'color: inherit'\n        );\n\n        // Show stack trace if enabled (helps find where state changes originate)\n        if (getOpt('trace', false)) {\n          console.trace(`%c[${label}] Stack trace for ${key}`, 'color: #888');\n        }\n      }\n\n      return newValue;\n    },\n\n    onSubscribe: (key) => {\n      if (globalEnabled && matchesFilter(key)) {\n        console.log(\n          `%c[${label}]%c SUBSCRIBE %c${key}`,\n          'color: #888; font-weight: bold',\n          'color: #9C27B0',\n          'color: #2196F3; font-weight: bold'\n        );\n      }\n    },\n\n    onNotify: (key, value) => {\n      // Skip internal properties\n      if (typeof key === 'string' && key.startsWith('$')) {\n        return;\n      }\n\n      incrementStat(label, 'notifies', key);\n\n      if (globalEnabled && getOpt('logNotify', true) && matchesFilter(key)) {\n        console.log(\n          `%c[${label}]%c NOTIFY %c${key}%c = ${formatValue(value)}`,\n          'color: #888; font-weight: bold',\n          'color: #E91E63',\n          'color: #2196F3; font-weight: bold',\n          'color: inherit'\n        );\n      }\n    }\n  };\n}\n\n/**\n * Global debug controls\n */\nexport const debug = {\n  /**\n   * Enable debug logging globally\n   */\n  enable() {\n    globalEnabled = true;\n    console.log('%c[lume-debug]%c Logging enabled', 'color: #888; font-weight: bold', 'color: #4CAF50');\n  },\n\n  /**\n   * Disable debug logging globally\n   */\n  disable() {\n    globalEnabled = false;\n    console.log('%c[lume-debug]%c Logging disabled', 'color: #888; font-weight: bold', 'color: #F44336');\n  },\n\n  /**\n   * Check if debug logging is currently enabled\n   * @returns {boolean}\n   */\n  isEnabled() {\n    return globalEnabled;\n  },\n\n  /**\n   * Filter logs by key pattern\n   * @param {string|RegExp|null} pattern - Pattern to match, or null to clear filter\n   */\n  filter(pattern) {\n    globalFilter = pattern;\n    if (pattern === null) {\n      console.log('%c[lume-debug]%c Filter cleared', 'color: #888; font-weight: bold', 'color: inherit');\n    } else {\n      console.log(`%c[lume-debug]%c Filter set: ${pattern}`, 'color: #888; font-weight: bold', 'color: inherit');\n    }\n  },\n\n  /**\n   * Get current filter pattern\n   * @returns {string|RegExp|null}\n   */\n  getFilter() {\n    return globalFilter;\n  },\n\n  /**\n   * Get statistics data (silent - no console output)\n   * Use logStats() if you want to see stats in console.\n   * @returns {object} Stats object for programmatic access\n   */\n  stats() {\n    const result = {};\n\n    for (const [label, data] of stats) {\n      result[label] = {\n        gets: Object.fromEntries(data.gets),\n        sets: Object.fromEntries(data.sets),\n        notifies: Object.fromEntries(data.notifies)\n      };\n    }\n\n    return result;\n  },\n\n  /**\n   * Log statistics summary to console (with formatting)\n   * @returns {object} Stats object for programmatic access\n   */\n  logStats() {\n    const result = this.stats();\n\n    if (Object.keys(result).length === 0) {\n      console.log('%c[lume-debug]%c No stats collected yet', 'color: #888; font-weight: bold', 'color: inherit');\n      return result;\n    }\n\n    console.group('%c[lume-debug] Statistics', 'color: #888; font-weight: bold');\n\n    for (const [label, data] of Object.entries(result)) {\n      console.group(`%c${label}`, 'color: #2196F3; font-weight: bold');\n\n      // Use console.table for better formatted output\n      const tableData = [];\n      const allKeys = new Set([\n        ...Object.keys(data.gets),\n        ...Object.keys(data.sets),\n        ...Object.keys(data.notifies)\n      ]);\n\n      for (const key of allKeys) {\n        tableData.push({\n          key,\n          gets: data.gets[key] || 0,\n          sets: data.sets[key] || 0,\n          notifies: data.notifies[key] || 0\n        });\n      }\n\n      if (tableData.length > 0) {\n        console.table(tableData);\n      }\n\n      console.groupEnd();\n    }\n\n    console.groupEnd();\n\n    return result;\n  },\n\n  /**\n   * Reset all collected statistics\n   */\n  resetStats() {\n    stats.clear();\n    console.log('%c[lume-debug]%c Stats reset', 'color: #888; font-weight: bold', 'color: inherit');\n  }\n};\n","/**\n * Lume-JS withPlugins Addon\n *\n * Wraps a reactive state proxy with a plugin layer that intercepts\n * get/set/notify/subscribe operations via plugin hooks.\n *\n * Only stores that opt into debugging or custom behaviors need this.\n * Core state() is not aware of plugins.\n *\n * Usage:\n *   import { state } from \"lume-js\";\n *   import { withPlugins, createDebugPlugin } from \"lume-js/addons\";\n *\n *   const store = withPlugins(state({ count: 0 }), [createDebugPlugin({ label: 'counter' })]);\n */\n\n/**\n * Wrap a reactive state proxy with plugin hooks.\n *\n * Plugin hooks (all optional):\n *   onInit()                         — called once at wrap time\n *   onGet(key, value) → value|void   — intercept/transform reads\n *   onSet(key, newVal, oldVal) → val|void — intercept/transform writes\n *   onNotify(key, value)             — called before subscribers are notified\n *   onSubscribe(key)                 — called when $subscribe is invoked\n *\n * @security Plugins run with full application privilege. A plugin can read\n * all state, alter any write, or suppress mutations. Only pass trusted objects.\n * Plugin objects are frozen after registration to prevent post-init mutation.\n *\n * @param {object} store - A reactive proxy from state()\n * @param {Array<object>} plugins - Array of plugin objects\n * @returns {Proxy} A new proxy wrapping the store with plugin behavior\n */\nimport { logError } from '../utils/log.js';\n\nexport function withPlugins(store, plugins = []) {\n  if (!plugins.length) return store;\n\n  // Call onInit hooks once at wrap time, then freeze each plugin to prevent\n  // post-registration mutation of its hooks (defense-in-depth).\n  for (const p of plugins) {\n    try {\n      p.onInit?.();\n    } catch (e) {\n      logError(`[Lume.js] Plugin \"${p.name}\" error in onInit:`, e);\n    }\n    Object.freeze(p);\n  }\n\n  // Track pending notifications for onNotify hooks.\n  // Instead of a separate microtask, we hook into the underlying state's\n  // flush via $beforeFlush so onNotify and subscribers share one microtask.\n  const pendingNotifications = new Map();\n\n  function runNotifyHooks() {\n    for (const [key, value] of pendingNotifications) {\n      for (const p of plugins) {\n        try {\n          p.onNotify?.(key, value);\n        } catch (e) {\n          logError(`[Lume.js] Plugin \"${p.name}\" error in onNotify:`, e);\n        }\n      }\n    }\n    pendingNotifications.clear();\n  }\n\n  // Register once on the underlying state; capture unsubscribe for cleanup.\n  let flushUnsub;\n  if (typeof store.$beforeFlush === 'function') {\n    flushUnsub = store.$beforeFlush(runNotifyHooks);\n  }\n\n  return new Proxy(store, {\n    get(target, key) {\n      // $dispose — remove the beforeFlush hook and clear pending state\n      if (key === '$dispose') {\n        return () => {\n          if (flushUnsub) flushUnsub();\n          pendingNotifications.clear();\n        };\n      }\n\n      // Pass $-prefixed meta methods through without interception\n      if (typeof key === 'string' && key.startsWith('$')) {\n        const method = target[key];\n        if (key === '$subscribe' && typeof method === 'function') {\n          // Wrap $subscribe to call onSubscribe hooks\n          return (subKey, fn) => {\n            for (const p of plugins) {\n              try {\n                p.onSubscribe?.(subKey);\n              } catch (e) {\n                logError(`[Lume.js] Plugin \"${p.name}\" error in onSubscribe:`, e);\n              }\n            }\n            return method(subKey, fn);\n          };\n        }\n        return method;\n      }\n\n      let value = target[key];\n\n      // onGet chain\n      for (const p of plugins) {\n        try {\n          const r = p.onGet?.(key, value);\n          if (r !== undefined) value = r;\n        } catch (e) {\n          logError(`[Lume.js] Plugin \"${p.name}\" error in onGet:`, e);\n        }\n      }\n\n      return value;\n    },\n\n    set(target, key, value) {\n      const oldValue = target[key];\n      let newValue = value;\n\n      // onSet chain\n      for (const p of plugins) {\n        try {\n          const r = p.onSet?.(key, newValue, oldValue);\n          if (r !== undefined) newValue = r;\n        } catch (e) {\n          logError(`[Lume.js] Plugin \"${p.name}\" error in onSet:`, e);\n        }\n      }\n\n      // Only queue onNotify if the value actually changed after plugin chain\n      if (!Object.is(newValue, oldValue)) {\n        pendingNotifications.set(key, newValue);\n      }\n\n      target[key] = newValue;\n      return true;\n    }\n  });\n}\n","/**\n * Creates a cleanup group that can collect and dispose multiple\n * cleanup/unsubscribe functions at once.\n *\n * @returns {CleanupGroup}\n *\n * @example\n * ```js\n * import { createCleanupGroup } from 'lume-js/addons';\n *\n * const group = createCleanupGroup();\n * group.add(bindDom(root, store));\n * group.add(effect(() => { ... }));\n * group.add(store.$subscribe('key', fn));\n *\n * // Dispose everything at once\n * group.dispose();\n * ```\n */\nexport function createCleanupGroup() {\n  const cleanups = [];\n\n  return {\n    /**\n     * Add a cleanup function to the group.\n     * @param {Function} fn - Cleanup/unsubscribe function\n     */\n    add(fn) {\n      if (typeof fn === 'function') {\n        cleanups.push(fn);\n      }\n    },\n\n    /**\n     * Run all collected cleanup functions and clear the group.\n     */\n    dispose() {\n      while (cleanups.length) {\n        const fn = cleanups.pop();\n        try { fn(); } catch (e) { /* ignore cleanup errors */ }\n      }\n    },\n  };\n}\n","/**\n * Reads initial state from a `<script type=\"application/json\">` element\n * embedded in the server-rendered HTML. Useful for SSR / hydration patterns.\n *\n * @security Hydration trusts the DOM. An attacker who can inject HTML before\n * the legitimate script (DOM clobbering) can control the parsed data. The\n * element must be a real `<script type=\"application/json\">` tag; non-script\n * elements are rejected. Use the optional `validate` parameter to enforce a\n * schema (e.g., whitelist allowed keys) before passing to `state()`.\n *\n * @param {string} [selector='#__LUME_DATA__'] - CSS selector for the script element\n * @param {function} [validate] - Optional validator: (data) => boolean. If it\n *   returns false, hydrateState returns {} instead of the parsed data.\n * @returns {object} Parsed JSON object, or empty object if not found / invalid / rejected\n *\n * @example\n * ```html\n * <script id=\"__LUME_DATA__\" type=\"application/json\">\n *   {\"title\": \"Welcome\", \"count\": 42}\n * </script>\n * ```\n *\n * ```js\n * import { state } from 'lume-js';\n * import { hydrateState } from 'lume-js/addons';\n *\n * // With optional schema validation\n * const data = hydrateState('#__LUME_DATA__', d =>\n *   typeof d.title === 'string' && typeof d.count === 'number'\n * );\n * const store = state(data);\n * ```\n */\nexport function hydrateState(selector = '#__LUME_DATA__', validate) {\n  const el = typeof document !== 'undefined' ? document.querySelector(selector) : null;\n  if (!el) return {};\n\n  // Reject non-script elements or scripts without the correct type.\n  // This mitigates DOM clobbering where an attacker injects a matching\n  // element with a different tag name (e.g., a div or a script with\n  // a different type that would still match querySelector by id).\n  if (el.tagName !== 'SCRIPT' || el.type !== 'application/json') {\n    return {};\n  }\n\n  let data;\n  try {\n    data = JSON.parse(el.textContent);\n  } catch {\n    return {};\n  }\n\n  if (typeof validate === 'function' && !validate(data)) {\n    return {};\n  }\n\n  return data;\n}\n","/**\n * Lume-JS Persist Addon\n *\n * Keeps selected store keys in sync with localStorage/sessionStorage (or\n * any Storage-like object): hydrates them on call, then saves on change.\n *\n * Usage:\n *   import { state } from \"lume-js\";\n *   import { persist } from \"lume-js/addons\";\n *\n *   const store = state({ todos: [], filter: 'all', draft: '' });\n *\n *   // Hydrate + auto-save todos/filter; draft stays in-memory only\n *   const stop = persist(store, 'my-app', { keys: ['todos', 'filter'] });\n *\n * Behavior:\n * - Hydration assigns stored values through the proxy, so subscribers and\n *   bindings see them like any other write.\n * - Saves are coalesced to one storage write per microtask, and skipped\n *   entirely when the serialized snapshot is unchanged.\n * - Storage failures (quota, unavailable, corrupted JSON, unserializable\n *   values) are contained: a console warning, never a throw.\n *\n * @security Storage is same-origin but survives schema changes — hydration\n * only assigns keys you watch (never unknown keys from storage), and the\n * core set trap independently blocks prototype-polluting keys.\n *\n * @module addons/persist\n */\n\nimport { logWarn } from '../utils/log.js';\n\n/**\n * Read and parse the stored JSON blob. Returns a plain object, or null\n * when missing, corrupted, or not an object (warns on read errors).\n */\nfunction readStored(storage, storageKey) {\n  try {\n    const raw = storage.getItem(storageKey);\n    if (!raw) return null;\n    const data = JSON.parse(raw);\n    return data && typeof data === 'object' && !Array.isArray(data) ? data : null;\n  } catch {\n    logWarn(`[Lume.js] persist(): could not read \"${storageKey}\" — starting fresh`);\n    return null;\n  }\n}\n\n/** Serialize the watched subset of the store. May throw (circular refs). */\nfunction serializeKeys(store, watched) {\n  const out = {};\n  for (const k of watched) out[k] = store[k];\n  return JSON.stringify(out);\n}\n\n// storage object → Set of storage keys currently managed by a persist()\n// instance. Two instances on one entry silently overwrite each other's\n// subsets (each serializes only its own watched keys over the whole blob),\n// so the second registration gets a loud warning.\nconst activeEntries = new WeakMap();\n\n/**\n * Default storage resolution. Wrapped because accessing localStorage can\n * THROW (SecurityError) in cookie-blocked iframes and some privacy modes —\n * persist() must degrade to a warning, never crash the app at setup.\n */\nfunction defaultStorage() {\n  try {\n    return typeof localStorage !== 'undefined' ? localStorage : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Sync store keys with a Storage object.\n *\n * @param {object} store - Reactive store created with state()\n * @param {string} storageKey - The storage entry name to read/write\n * @param {object} [options]\n * @param {string[]} [options.keys] - Keys to persist. Default: all own\n *   non-$ keys of the store at call time.\n * @param {Storage} [options.storage] - Storage object. Default: localStorage.\n *   Pass sessionStorage for per-tab persistence.\n * @returns {function} Dispose function — stops watching and saving.\n */\nexport function persist(store, storageKey, options = {}) {\n  if (!store || typeof store.$subscribe !== 'function') {\n    throw new Error('[Lume.js] persist() requires a reactive store from state()');\n  }\n  if (typeof storageKey !== 'string' || storageKey.length === 0) {\n    throw new Error('[Lume.js] persist() requires a non-empty storage key');\n  }\n\n  const storage = options.storage !== undefined\n    ? options.storage\n    : defaultStorage();\n\n  if (!storage || typeof storage.getItem !== 'function') {\n    logWarn('[Lume.js] persist(): no storage available — persistence disabled');\n    return () => {};\n  }\n\n  // An explicit array is respected as-is — including [] (persist nothing).\n  // Only an absent/non-array option falls back to all own non-$ keys.\n  const watched = Array.isArray(options.keys)\n    ? options.keys.slice()\n    : Object.keys(store).filter(k => !k.startsWith('$'));\n\n  // Warn when another live persist() already manages this storage entry\n  let entrySet = activeEntries.get(storage);\n  if (!entrySet) {\n    entrySet = new Set();\n    activeEntries.set(storage, entrySet);\n  }\n  const ownsEntry = !entrySet.has(storageKey);\n  if (ownsEntry) {\n    entrySet.add(storageKey);\n  } else {\n    logWarn(\n      `[Lume.js] persist(): \"${storageKey}\" is already managed by another persist() on this storage — ` +\n      'instances will overwrite each other\\'s data. Use a distinct key per store.'\n    );\n  }\n\n  // ── Hydrate ────────────────────────────────────────────────────────────\n  // Only watched keys are assigned — stale storage can't inject others.\n  const stored = readStored(storage, storageKey);\n  if (stored) {\n    for (const k of watched) {\n      if (Object.prototype.hasOwnProperty.call(stored, k)) {\n        store[k] = stored[k];\n      }\n    }\n  }\n\n  // ── Save on change ─────────────────────────────────────────────────────\n  // Remember what storage holds (post-hydration) so unchanged flushes —\n  // including the hydration echo itself — skip the write.\n  let lastWritten = null;\n  try {\n    lastWritten = serializeKeys(store, watched);\n  } catch {\n    // Unserializable initial state: first save attempt will warn.\n  }\n\n  let scheduled = false;\n  let disposed = false;\n\n  const flushSave = () => {\n    scheduled = false;\n    if (disposed) return;\n\n    let json;\n    try {\n      json = serializeKeys(store, watched);\n    } catch (err) {\n      logWarn('[Lume.js] persist(): state not serializable — skipping save', err);\n      return;\n    }\n    if (json === lastWritten) return;\n\n    try {\n      storage.setItem(storageKey, json);\n      lastWritten = json;\n    } catch (err) {\n      logWarn('[Lume.js] persist(): could not write — storage full or unavailable?', err);\n    }\n  };\n\n  const save = () => {\n    if (scheduled) return;\n    scheduled = true;\n    queueMicrotask(flushSave);\n  };\n\n  const unsubs = watched.map(k => {\n    let first = true;\n    return store.$subscribe(k, () => {\n      if (first) { first = false; return; } // skip $subscribe's immediate call\n      save();\n    });\n  });\n\n  return () => {\n    disposed = true;\n    if (ownsEntry) entrySet.delete(storageKey);\n    while (unsubs.length) unsubs.pop()();\n  };\n}\n","import { REACTIVE_BRAND } from \"../core/state.js\";\n\nexport { computed } from \"./computed.js\";\nexport { watch } from \"./watch.js\";\nexport { repeat, defaultFocusPreservation, defaultScrollPreservation } from \"./repeat.js\";\nexport { createDebugPlugin, debug } from \"./debug.js\";\nexport { withPlugins } from \"./withPlugins.js\";\nexport { createCleanupGroup } from \"./cleanupGroup.js\";\nexport { hydrateState } from \"./hydrateState.js\";\nexport { persist } from \"./persist.js\";\n\n/**\n * Returns true if the value is a Lume reactive proxy created by state().\n *\n * Checks the shared reactive brand first (a registry symbol stamped by\n * state(), reliable across module copies), then falls back to duck-typing\n * ($subscribe) for proxies from older lume-js versions whose brand was not\n * shared. The brand check uses the `in` operator, which does not pass\n * through the proxy `get` trap — calling isReactive inside an effect does\n * not create a spurious dependency.\n *\n * @param {any} obj\n * @returns {boolean}\n */\nexport function isReactive(obj) {\n  return !!(obj && typeof obj === 'object' &&\n    (REACTIVE_BRAND in obj || typeof obj.$subscribe === 'function'));\n}\n"],"names":["container"],"mappings":"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"}