{
  "version": 3,
  "sources": ["db.js"],
  "sourcesContent": ["/*\n * static/js/db.js \u2014 Minimal IndexedDB wrapper for the Snowdesk PWA (SNOW-375).\n *\n * Spec \u00A73.8, \u00A77.2. The base layer every subsequent client-side spec\n * item builds on (mutation queue SNOW-376, event buffer SNOW-385, cached\n * favourites SNOW-418). One IndexedDB database per app; five object\n * stores declared up front so a schema bump only fires when the store\n * namespace itself changes.\n *\n * Object stores (spec \u00A77.2)\n * -------------------------\n *   queue:mutations  pending mutations for SNOW-376 (autoIncrement id)\n *   queue:events     telemetry buffer for SNOW-385 (autoIncrement id)\n *   meta:sync        last-sync timestamps per resource (keyPath: 'resource')\n *   meta:app         install timestamps, first-launch flags, opt-in/out,\n *                    and (SNOW-482) the persisted sync/freshness clocks\n *                    (keyPath: 'key')\n *   data:favourites  cached favourites + region rating,\n *                     for offline reads (SNOW-418; keyPath: 'uuid')\n *   log:sync         rolling record of recent real (un-cached) server\n *                     round-trips, trimmed to the newest 100 rows\n *                     (SNOW-482; autoIncrement id)\n *   data:map_overlays cached favourites / community-reports GeoJSON for\n *                     the map's offline overlay toggles (SNOW-492;\n *                     keyPath: 'key', one row per resource)\n *   log:debug        rolling diagnostic trace of the page-side and\n *                     service-worker decisions the map's silent\n *                     fallbacks would otherwise swallow, trimmed to the\n *                     newest 500 rows (SNOW-812; autoIncrement id)\n *   data:panel_rows  the rendered rows of a map UGC panel, kept so the\n *                     panel can repaint itself offline (SNOW-661;\n *                     keyPath: 'key', one row per panel)\n *   data:*           reserved namespace for further cached server-data\n *                     copies; added on demand by consumers.\n *\n * Reset Required\n * --------------\n * A migration that throws or times out puts the app in the terminal\n * \"Reset Required\" state: pwaDb.open() returns a rejected promise for\n * the rest of the session, pwaDb.isResetRequired() flips to true, and\n * the full-screen #pwa-reset-required overlay is revealed. That overlay\n * carries data-pwa-reset-trigger (and skip-confirm) so the existing\n * SNOW-378 pwa_reset.js wipe runs when the user taps \"Reset now\".\n *\n * Deliberately NOT idb / dexie / similar\n * --------------------------------------\n * The whole file is ~250 lines including copy-pasted comments; a\n * third-party wrapper would triple the bundle for zero functional gain.\n * The Promise-wrapping pattern is well-worn \u2014 every IDBRequest is\n * lifted into a Promise in the private ``_req`` helper.\n */\n\n(function () {\n  'use strict';\n\n  const DB_NAME = 'snowdesk-pwa-v1';\n  // Schema version. Bump when you add / rename / remove an object store,\n  // AND add the corresponding upgrade branch in _runMigrations below.\n  //\n  // v2 (SNOW-418): added 'data:favourites' \u2014 the first consumer of the\n  // reserved data:* namespace, caching each favourite's roster/card\n  // record so the favourites surface can repaint offline.\n  // v3 (SNOW-482): added 'log:sync' \u2014 a rolling record of real server\n  // round-trips backing the manage-page sync-log panel.\n  // v4 (SNOW-492): added 'data:map_overlays' \u2014 cached favourites /\n  // community-reports GeoJSON so the map's overlay toggles keep working\n  // offline (map_overlay_offline_cache.js).\n  // v5 (SNOW-812): added 'log:debug' \u2014 the on-device diagnostic trace\n  // backing the debug-log panel (debug_log.js). Created for every client\n  // at v5 regardless of the debug_log waffle flag: the store is a schema\n  // fact, and gating its CREATION on a per-user flag would mean two\n  // populations running the same DB_VERSION with different schemas, which\n  // no later migration could tell apart. Empty costs nothing.\n  // v6 (SNOW-661): added 'data:panel_rows' \u2014 the rendered rows of a map UGC\n  // panel, so the field-observation panel can repaint itself from its last\n  // good response instead of reporting a failure the user can do nothing\n  // about. See observations_offline.js.\n  // v7 (SNOW-973): added 'data:route_bulletins' \u2014 one saved route's reading\n  // of one day's bulletin, so the map's route detail panel can repaint it\n  // off signal. A store of its own rather than another key in\n  // 'data:panel_rows', whose rows are one body per PANEL: this is one body\n  // per (route, day), and the day in the key is what stops a cached reading\n  // being repainted under a date it does not belong to. Its rows carry the\n  // response's freshness envelope, which no other data:* row does \u2014 a\n  // bulletin reading expires where a cached track does not.\n  // v8 (SNOW-1062): REMOVED 'data:route_bulletins'. The route detail panel\n  // no longer reads the day's bulletin \u2014 the day's danger is a map layer\n  // (SNOW-979) \u2014 so nothing writes or reads the store, and a device that\n  // holds rows drops them on upgrade. See RETIRED_STORES.\n  const DB_VERSION = 8;\n\n  // Static store definitions (name \u2192 createObjectStore options). Any\n  // store present here is created by _runMigrations when it is missing.\n  // Additions bump DB_VERSION; removals bump it and move the name to\n  // RETIRED_STORES below.\n  const STORES = Object.freeze({\n    'queue:mutations': { keyPath: 'id', autoIncrement: true },\n    'queue:events': { keyPath: 'id', autoIncrement: true },\n    'meta:sync': { keyPath: 'resource' },\n    'meta:app': { keyPath: 'key' },\n    // SNOW-418 (v2) \u2014 cached favourite roster/card records, keyed by the\n    // favourite's uuid so a card update can upsert a single record.\n    'data:favourites': { keyPath: 'uuid' },\n    // SNOW-482 (v3) \u2014 rolling log of real (un-cached) server round-trips,\n    // read by the manage-page sync-log panel. Trimmed to newest 100 rows\n    // by appendSyncLog below.\n    'log:sync': { keyPath: 'id', autoIncrement: true },\n    // SNOW-492 (v4) \u2014 cached favourites / community-reports GeoJSON for\n    // the map's overlay toggles, keyed by resource name ('favourites' /\n    // 'community_reports'). See map_overlay_offline_cache.js.\n    'data:map_overlays': { keyPath: 'key' },\n    // SNOW-812 (v5) \u2014 rolling diagnostic trace written by debug_log.js\n    // (page) and relayed from sw.js (worker). Trimmed to the newest 500\n    // rows by appendDebugLogBatch below.\n    'log:debug': { keyPath: 'id', autoIncrement: true },\n    // SNOW-661 (v6) \u2014 the rendered rows of a map UGC panel, keyed by that\n    // panel's key ('observations'). Named for the PANEL rather than for the\n    // thing it lists because a row here is a response body, not a record:\n    // see observations_offline.js for why the markup is what is kept.\n    'data:panel_rows': { keyPath: 'key' },\n  });\n\n  // Stores a past version created and this one deletes on upgrade. A name\n  // stays here for good: a device can skip versions, and whichever version\n  // it upgrades from, the store must not survive.\n  //\n  // SNOW-1062 (v8) \u2014 'data:route_bulletins', SNOW-973's per-(route, day)\n  // copy of a route's bulletin reading. The reading is gone, and a stale\n  // copy of a forecast is the one kind of row that must not linger.\n  const RETIRED_STORES = Object.freeze(['data:route_bulletins']);\n\n  // Session state \u2014 single-page-load lifetime.\n  let _dbPromise = null;\n  let _resetRequired = false;\n  let _contextCache = null;\n\n  /**\n   * Reveal the full-screen Reset Required overlay and flip the internal\n   * flag so every subsequent open() is a hard error. Called on\n   * migration failure only.\n   *\n   * Also binds the overlay's CTA to ``window.pwaResetLocalData`` (the\n   * SNOW-378 six-step wipe) if it's available. Binding here rather than\n   * on page load keeps the reset code path completely inert until the\n   * overlay actually needs to fire.\n   */\n  function _enterResetRequired(reason) {\n    _resetRequired = true;\n    try {\n      console.error('pwa.db.reset_required', reason);\n    } catch (_e) {\n      // Ignore.\n    }\n    try {\n      const el = document.getElementById('pwa-reset-required');\n      if (el) el.classList.remove('hidden');\n      const cta = document.getElementById('pwa-reset-required-cta');\n      if (cta && typeof window.pwaResetLocalData === 'function') {\n        cta.addEventListener('click', (evt) => {\n          evt.preventDefault();\n          // SNOW-384: forced=true \u2014 the user didn't elect to reset, the\n          // app forced their hand by entering an unrecoverable state.\n          // Reports pwa.reset.forced instead of pwa.reset.user_initiated.\n          window.pwaResetLocalData(true).catch(() => window.location.reload());\n        });\n      }\n    } catch (_e) {\n      // Overlay markup missing (unlikely in production, but a stale\n      // template shouldn't crash the whole page).\n    }\n  }\n\n  /**\n   * Wrap an IDBRequest in a Promise.\n   * @param {IDBRequest} req\n   * @returns {Promise<any>}\n   */\n  function _req(req) {\n    return new Promise((resolve, reject) => {\n      req.onsuccess = () => resolve(req.result);\n      req.onerror = () => reject(req.error || new Error('IDBRequest failed'));\n    });\n  }\n\n  /**\n   * Apply the schema for the requested version. Idempotent \u2014 re-running\n   * against a DB already at the target version is a no-op because both\n   * createObjectStore and deleteObjectStore are guarded by\n   * objectStoreNames.contains().\n   *\n   * @param {IDBDatabase} db\n   */\n  function _runMigrations(db) {\n    for (const [name, opts] of Object.entries(STORES)) {\n      if (!db.objectStoreNames.contains(name)) {\n        db.createObjectStore(name, opts);\n      }\n    }\n    for (const name of RETIRED_STORES) {\n      if (db.objectStoreNames.contains(name)) {\n        db.deleteObjectStore(name);\n      }\n    }\n  }\n\n  /**\n   * SNOW-384: cold-start storage-pressure check. Fire-and-forget \u2014 never\n   * awaited by ``open()`` callers, since it's diagnostic only and must\n   * not add latency to every consumer of the DB.\n   *\n   * TODO: tighten the heuristic once real eviction cases surface (no\n   * ticket filed yet). Today it is deliberately conservative to avoid false\n   * positives on ordinary first-ever visits (where zero usage and a\n   * modest quota are both completely normal):\n   *\n   *   - ``quota`` implausibly small for any browser to hand out under\n   *     normal conditions (< 5 MB) \u2014 most browsers grant a meaningful\n   *     fraction of free disk space; a value this low suggests the OS\n   *     / browser is under real storage pressure.\n   *   - ``usage`` is exactly 0 AND this device has an independent\n   *     localStorage marker (``pwa.install.installed_at``, written by\n   *     ``pwa_install.js``) proving the PWA was previously installed \u2014\n   *     i.e. writes were expected to exist. localStorage and IndexedDB\n   *     are evicted somewhat independently, so a surviving localStorage\n   *     marker alongside a wiped IndexedDB is a plausible eviction\n   *     signal rather than \"first visit, nothing written yet\".\n   */\n  function _checkStorageEstimate() {\n    try {\n      if (!('storage' in navigator) || typeof navigator.storage.estimate !== 'function') {\n        return;\n      }\n      navigator.storage\n        .estimate()\n        .then((estimate) => {\n          const quota = estimate && estimate.quota;\n          const usage = estimate && estimate.usage;\n          const MIN_PLAUSIBLE_QUOTA_BYTES = 5 * 1024 * 1024;\n          const quotaSuspiciouslyLow =\n            typeof quota === 'number' && quota > 0 && quota < MIN_PLAUSIBLE_QUOTA_BYTES;\n          let hadPriorInstall = false;\n          try {\n            hadPriorInstall = !!localStorage.getItem('pwa.install.installed_at');\n          } catch (_e) {\n            // Storage unavailable \u2014 treat as no prior-install evidence.\n          }\n          const usageZeroAfterInstall = hadPriorInstall && usage === 0;\n          if (quotaSuspiciouslyLow || usageZeroAfterInstall) {\n            try {\n              window.pwaTelemetry?.emit('pwa.storage.evicted_probable', {\n                quota,\n                usage,\n              });\n            } catch (_e) {\n              // Ignore \u2014 telemetry must never affect DB open.\n            }\n          }\n        })\n        .catch(() => {\n          // storage.estimate() rejected \u2014 nothing to report.\n        });\n    } catch (_e) {\n      // Non-fatal \u2014 this check is diagnostic only.\n    }\n  }\n\n  /**\n   * Open the DB (memoised for the page's lifetime). Rejects immediately\n   * if a prior open() failed and put the app in Reset Required state.\n   *\n   * @returns {Promise<IDBDatabase>}\n   */\n  function open() {\n    if (_resetRequired) {\n      return Promise.reject(new Error('reset_required'));\n    }\n    if (_dbPromise) return _dbPromise;\n    if (typeof indexedDB === 'undefined') {\n      return Promise.reject(new Error('indexeddb_unavailable'));\n    }\n\n    _dbPromise = new Promise((resolve, reject) => {\n      let req;\n      try {\n        req = indexedDB.open(DB_NAME, DB_VERSION);\n      } catch (err) {\n        _enterResetRequired(err);\n        reject(err);\n        return;\n      }\n      req.onupgradeneeded = (evt) => {\n        try {\n          _runMigrations(evt.target.result);\n        } catch (err) {\n          // Migration failure \u2014 abort the upgrade transaction and put\n          // the app in Reset Required state. The onerror below fires\n          // once the aborted transaction settles.\n          try {\n            evt.target.transaction.abort();\n          } catch (_e) {\n            // Already aborted \u2014 ignore.\n          }\n          _enterResetRequired(err);\n        }\n      };\n      req.onsuccess = () => {\n        if (_resetRequired) {\n          try {\n            req.result.close();\n          } catch (_e) {\n            // Ignore.\n          }\n          reject(new Error('reset_required'));\n          return;\n        }\n        // Yield the connection when another connection needs to change the\n        // schema version or delete the DB \u2014 a real second tab bumping\n        // DB_VERSION, or a delete/upgrade elsewhere. Without this, the\n        // memoised connection (held open for the whole page lifetime as\n        // soon as any consumer reads on load, e.g. the SNOW-376 mutation\n        // badge) blocks that other connection's open() indefinitely \u2014 it\n        // sits on `onblocked` forever. Close and drop the cached promise so\n        // the next consumer re-opens cleanly (re-open surfaces a genuine\n        // VersionError as Reset Required via onerror, as before).\n        req.result.onversionchange = () => {\n          try {\n            req.result.close();\n          } catch (_e) {\n            // Already closed \u2014 ignore.\n          }\n          _dbPromise = null;\n        };\n        // SNOW-384: cold-start storage-pressure check \u2014 fire-and-forget,\n        // runs once per successful open() (this handler fires exactly\n        // once per indexedDB.open() call; _dbPromise memoisation means\n        // open() itself is only actually invoked once per page load).\n        _checkStorageEstimate();\n        resolve(req.result);\n      };\n      req.onerror = () => {\n        // Any open error \u2014 corrupt DB, quota exceeded, private-mode\n        // blocked \u2014 is fatal for this session.\n        _enterResetRequired(req.error);\n        reject(req.error || new Error('idb_open_failed'));\n      };\n      req.onblocked = () => {\n        // Another tab is holding the DB open at an older version. Do\n        // NOT enter Reset Required \u2014 the block clears once the other\n        // tab closes. Reject with a distinct code so callers can retry.\n        reject(new Error('idb_blocked'));\n      };\n    }).catch((err) => {\n      // Ensure a failed open doesn't sit cached \u2014 a caller can retry\n      // once the block clears (e.g. after the user closes the other tab).\n      _dbPromise = null;\n      throw err;\n    });\n\n    return _dbPromise;\n  }\n\n  /**\n   * Run one store operation inside a fresh transaction and return the\n   * request's result as a Promise.\n   *\n   * @param {string} storeName\n   * @param {'readonly'|'readwrite'} mode\n   * @param {(store: IDBObjectStore) => IDBRequest} op\n   */\n  async function _tx(storeName, mode, op) {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(storeName, mode);\n      const store = tx.objectStore(storeName);\n      const req = op(store);\n      req.onsuccess = () => resolve(req.result);\n      req.onerror = () => reject(req.error || new Error('IDBRequest failed'));\n      tx.onabort = () =>\n        reject(tx.error || new Error('IDBTransaction aborted'));\n    });\n  }\n\n  async function get(store, key) {\n    return _tx(store, 'readonly', (s) => s.get(key));\n  }\n\n  async function put(store, value) {\n    return _tx(store, 'readwrite', (s) => s.put(value));\n  }\n\n  /**\n   * Read one row, transform it, and write the result back \u2014 all inside a\n   * SINGLE `readwrite` transaction (SNOW-959).\n   *\n   * ## Why this exists\n   *\n   * `get()` then `put()` is two transactions with a gap between them, and\n   * a row holding an ARRAY turns that gap into lost writes. Three\n   * independent functions each read the whole of `meta:app`'s\n   * `basemap.regions` / `basemap.customAreas`, change one entry in a copy,\n   * and write the copy back: `offline_audit.js`'s `stampAreaContent`,\n   * `map_basemap_downloads.js`'s `_stampAreaContent`, and\n   * `map_region_download.js`'s `_stampRegionContent`. Until SNOW-950/953\n   * only the map page ever wrote those rows; now `/offline/` writes them\n   * too, and both pages are `SHELL_PAGES` a user can have open at once. A\n   * region refreshed from the map's roundel while another tab taps Update\n   * on a different area meant both reads saw the same array and the second\n   * `put()` silently discarded the first area's change.\n   *\n   * IndexedDB already has the fix: transactions with overlapping scope and\n   * at least one `readwrite` are serialised by the browser, across every\n   * connection to the database \u2014 other tabs included. Reading and writing\n   * on the SAME transaction therefore makes the pair atomic with no lock,\n   * no version column and no retry loop. Two concurrent stamps queue\n   * instead of interleaving.\n   *\n   * ## `mutate` MUST be synchronous\n   *\n   * Not a style preference \u2014 the correctness condition. An IndexedDB\n   * transaction commits as soon as control returns to the event loop with\n   * no request outstanding on it, so a `mutate` that awaits anything hands\n   * back a transaction that has already closed, and the `put` throws\n   * `TransactionInactiveError`. Every caller's transform is a pure\n   * rearrangement of what it just read, which is the only shape this\n   * helper supports and the only shape it needs to.\n   *\n   * @param {string} storeName\n   * @param {IDBValidKey} key\n   * @param {(current: any) => any} mutate Receives the stored row, or\n   *   `undefined` when the key is absent. Return the row to write, or\n   *   `undefined` to leave the row untouched and commit nothing \u2014 the\n   *   \"nothing here matched, don't rewrite the array\" case all three\n   *   stampers have. A throw aborts the transaction and rejects.\n   * @returns {Promise<any>} The written row, or the unchanged current row\n   *   when `mutate` returned `undefined`.\n   */\n  async function readModifyWrite(storeName, key, mutate) {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(storeName, 'readwrite');\n      const store = tx.objectStore(storeName);\n      const readReq = store.get(key);\n      readReq.onerror = () =>\n        reject(readReq.error || new Error('IDBRequest failed'));\n      readReq.onsuccess = () => {\n        let next;\n        try {\n          next = mutate(readReq.result);\n        } catch (err) {\n          // The read has already happened on this transaction; aborting\n          // is what keeps a half-applied change from committing.\n          try {\n            tx.abort();\n          } catch (_e) {\n            // Already settling \u2014 `tx.onabort` below still rejects.\n          }\n          reject(err);\n          return;\n        }\n        if (next === undefined) {\n          resolve(readReq.result);\n          return;\n        }\n        const writeReq = store.put(next);\n        writeReq.onerror = () =>\n          reject(writeReq.error || new Error('IDBRequest failed'));\n        writeReq.onsuccess = () => resolve(next);\n      };\n      tx.onabort = () => reject(tx.error || new Error('IDBTransaction aborted'));\n    });\n  }\n\n  async function del(store, key) {\n    return _tx(store, 'readwrite', (s) => s.delete(key));\n  }\n\n  async function count(store) {\n    return _tx(store, 'readonly', (s) => s.count());\n  }\n\n  async function clear(store) {\n    return _tx(store, 'readwrite', (s) => s.clear());\n  }\n\n  /**\n   * Read up to ``limit`` entries from a store (all if limit is unset).\n   * IDBObjectStore.getAll accepts null for \"no query\", and a numeric\n   * count as the second argument.\n   */\n  async function getAll(storeName, limit) {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(storeName, 'readonly');\n      const req = tx.objectStore(storeName).getAll(null, limit || undefined);\n      req.onsuccess = () => resolve(req.result || []);\n      req.onerror = () => reject(req.error || new Error('getAll failed'));\n    });\n  }\n\n  // -------------------------------------------------------------------\n  // log:* ring-buffer helpers \u2014 SNOW-482 (log:sync), SNOW-812 (log:debug)\n  //\n  // Both stores are autoIncrement ring buffers: append a row, trim the\n  // oldest away, read the newest back. IDBObjectStore.getAll(query, count)\n  // returns the LOWEST keys first, which is the wrong end for both of\n  // those \u2014 trimming and reading both walk a cursor instead.\n  //\n  // SNOW-812 generalised the pair over a store name rather than copying\n  // forty lines of cursor plumbing for a second, identically-shaped log.\n  // ``appendSyncLog``/``getSyncLog`` stay as the named SNOW-482 surface;\n  // the debug log adds a batched appender because it writes in bursts.\n  // -------------------------------------------------------------------\n\n  const SYNC_LOG_MAX_ROWS = 100;\n  // Deliberately larger than log:sync's 100. A debug session is a burst \u2014\n  // one map load with the trace on emits well over a hundred lines \u2014 and a\n  // buffer that has already discarded the boot sequence by the time the\n  // user opens the panel would answer none of the questions it exists for.\n  const DEBUG_LOG_MAX_ROWS = 500;\n\n  /**\n   * Delete the oldest rows in ``storeName`` until at most ``maxRows``\n   * remain. Ascending cursor order visits the lowest (oldest)\n   * autoIncrement ids first.\n   *\n   * @param {string} storeName\n   * @param {number} maxRows\n   * @returns {Promise<void>}\n   */\n  async function _trimLog(storeName, maxRows) {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(storeName, 'readwrite');\n      const store = tx.objectStore(storeName);\n      const countReq = store.count();\n      countReq.onsuccess = () => {\n        const excess = countReq.result - maxRows;\n        if (excess <= 0) {\n          resolve();\n          return;\n        }\n        let deleted = 0;\n        const cursorReq = store.openCursor();\n        cursorReq.onsuccess = (evt) => {\n          const cursor = evt.target.result;\n          if (!cursor || deleted >= excess) {\n            resolve();\n            return;\n          }\n          cursor.delete();\n          deleted += 1;\n          cursor.continue();\n        };\n        cursorReq.onerror = () => reject(cursorReq.error || new Error('trim cursor failed'));\n      };\n      countReq.onerror = () => reject(countReq.error || new Error('count failed'));\n      tx.onabort = () => reject(tx.error || new Error('IDBTransaction aborted'));\n    });\n  }\n\n  /**\n   * Append one row to the ``log:sync`` store, then trim to the newest\n   * ``SYNC_LOG_MAX_ROWS``.\n   *\n   * @param {object} entry - row to store; must not set ``id`` (autoIncrement).\n   * @returns {Promise<void>}\n   */\n  async function appendSyncLog(entry) {\n    await put('log:sync', entry);\n    await _trimLog('log:sync', SYNC_LOG_MAX_ROWS);\n  }\n\n  /**\n   * Append many rows to the ``log:debug`` store in ONE transaction, then\n   * trim to the newest ``DEBUG_LOG_MAX_ROWS`` (SNOW-812).\n   *\n   * Batched because the debug log's whole point is to record the bursts a\n   * single map load emits. A per-row ``put()`` + trim, the shape\n   * ``appendSyncLog`` uses for its handful of round-trips a session, would\n   * open two transactions per line and make the instrumentation itself the\n   * slowest thing on the page \u2014 which would change the behaviour being\n   * traced. One transaction per flush, one trim after it.\n   *\n   * @param {Array<object>} entries - rows to store; none may set ``id``.\n   * @returns {Promise<void>}\n   */\n  async function appendDebugLogBatch(entries) {\n    if (!entries || entries.length === 0) return;\n    const db = await open();\n    await new Promise((resolve, reject) => {\n      const tx = db.transaction('log:debug', 'readwrite');\n      const store = tx.objectStore('log:debug');\n      for (const entry of entries) store.add(entry);\n      tx.oncomplete = () => resolve();\n      tx.onerror = () => reject(tx.error || new Error('appendDebugLogBatch failed'));\n      tx.onabort = () => reject(tx.error || new Error('IDBTransaction aborted'));\n    });\n    await _trimLog('log:debug', DEBUG_LOG_MAX_ROWS);\n  }\n\n  /**\n   * Read up to ``limit`` rows from ``log:debug``, newest first.\n   *\n   * @param {number} [limit]\n   * @returns {Promise<Array<object>>}\n   */\n  function getDebugLog(limit) {\n    return _readLogNewestFirst('log:debug', limit || DEBUG_LOG_MAX_ROWS);\n  }\n\n  /**\n   * Empty the ``log:debug`` store outright (SNOW-812) \u2014 the panel's\n   * \"Clear\" control, and what switching recording off calls so a device\n   * doesn't carry a stale trace around indefinitely.\n   *\n   * @returns {Promise<void>}\n   */\n  async function clearDebugLog() {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction('log:debug', 'readwrite');\n      tx.objectStore('log:debug').clear();\n      tx.oncomplete = () => resolve();\n      tx.onerror = () => reject(tx.error || new Error('clearDebugLog failed'));\n      tx.onabort = () => reject(tx.error || new Error('IDBTransaction aborted'));\n    });\n  }\n\n  /**\n   * Read up to ``limit`` rows from ``log:sync``, newest first.\n   *\n   * @param {number} [limit]\n   * @returns {Promise<Array<object>>}\n   */\n  function getSyncLog(limit) {\n    return _readLogNewestFirst('log:sync', limit || SYNC_LOG_MAX_ROWS);\n  }\n\n  /**\n   * Read up to ``max`` rows from ``storeName``, newest first. A\n   * descending cursor visits the highest (newest) autoIncrement ids\n   * first.\n   *\n   * @param {string} storeName\n   * @param {number} max\n   * @returns {Promise<Array<object>>}\n   */\n  async function _readLogNewestFirst(storeName, max) {\n    const db = await open();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(storeName, 'readonly');\n      const store = tx.objectStore(storeName);\n      const results = [];\n      const cursorReq = store.openCursor(null, 'prev');\n      cursorReq.onsuccess = (evt) => {\n        const cursor = evt.target.result;\n        if (!cursor || results.length >= max) {\n          resolve(results);\n          return;\n        }\n        results.push(cursor.value);\n        cursor.continue();\n      };\n      cursorReq.onerror = () =>\n        reject(cursorReq.error || new Error(`read ${storeName} failed`));\n    });\n  }\n\n  // -------------------------------------------------------------------\n  // 8-field envelope context helper (spec \u00A716.1)\n  //\n  // Consumers (telemetry, mutation queue) call ``context()`` to build\n  // the fixed context every event / mutation carries. Cached for the\n  // page's lifetime \u2014 the values are immutable within a page load.\n  // -------------------------------------------------------------------\n\n  function _readMeta(name) {\n    try {\n      const el = document.querySelector(`meta[name=\"${name}\"]`);\n      return el ? el.getAttribute('content') || null : null;\n    } catch (_e) {\n      return null;\n    }\n  }\n\n  /**\n   * Draw 16 bytes of CSPRNG entropy and hex-encode them. Used as a\n   * fallback session_id generator on runtimes without\n   * ``crypto.randomUUID`` (older mobile Safari). Deliberately avoids\n   * ``Math.random`` \u2014 CodeQL flags it as insecure in identity-adjacent\n   * contexts and there's no legitimate use of it here.\n   */\n  function _randomHex() {\n    const bytes = new Uint8Array(16);\n    crypto.getRandomValues(bytes);\n    let out = '';\n    for (let i = 0; i < bytes.length; i++) {\n      out += bytes[i].toString(16).padStart(2, '0');\n    }\n    return out;\n  }\n\n  function _sessionId() {\n    // Tab-scoped random identifier; regenerates on tab close.\n    try {\n      const KEY = 'pwa.telemetry.session_id';\n      const existing = sessionStorage.getItem(KEY);\n      if (existing) return existing;\n      const uuid =\n        typeof crypto !== 'undefined' && crypto.randomUUID\n          ? crypto.randomUUID()\n          : _randomHex();\n      sessionStorage.setItem(KEY, uuid);\n      return uuid;\n    } catch (_e) {\n      // Safari private-mode: sessionStorage throws on set. Fall back\n      // to a per-page-load random value \u2014 telemetry still groups by\n      // this key within a single page but not across reloads.\n      try {\n        return 'anon-' + _randomHex();\n      } catch (_e2) {\n        // No crypto either \u2014 return a fixed sentinel so telemetry\n        // doesn't crash. Distinct per-tab identity is lost; the shared\n        // sentinel is caught by the \"unknown user_id\" branch downstream.\n        return 'anon-unavailable';\n      }\n    }\n  }\n\n  function _platform() {\n    try {\n      const ua = navigator.userAgent || '';\n      if (/iPad|iPhone|iPod/.test(ua)) return 'ios';\n      if (/Android/.test(ua)) return 'android';\n      return 'web';\n    } catch (_e) {\n      return 'web';\n    }\n  }\n\n  function _installState() {\n    try {\n      if (\n        window.matchMedia &&\n        window.matchMedia('(display-mode: standalone)').matches\n      ) {\n        return 'standalone';\n      }\n      // iOS Safari legacy affordance.\n      if (typeof navigator !== 'undefined' && navigator.standalone === true) {\n        return 'standalone';\n      }\n      return 'browser';\n    } catch (_e) {\n      return 'browser';\n    }\n  }\n\n  function _swState() {\n    try {\n      if (!('serviceWorker' in navigator)) return 'none';\n      const ctrl = navigator.serviceWorker.controller;\n      if (ctrl) return 'activated';\n      // Registration exists but no controller yet \u2192 installing.\n      return 'none';\n    } catch (_e) {\n      return 'none';\n    }\n  }\n\n  function _connection() {\n    try {\n      const c =\n        navigator.connection ||\n        navigator.mozConnection ||\n        navigator.webkitConnection;\n      if (c && c.effectiveType) return c.effectiveType;\n      return 'unknown';\n    } catch (_e) {\n      return 'unknown';\n    }\n  }\n\n  function context() {\n    if (_contextCache) return _contextCache;\n    _contextCache = Object.freeze({\n      session_id: _sessionId(),\n      user_id: _readMeta('pwa-user-id'),\n      client_version: _readMeta('pwa-app-version') || '',\n      platform: _platform(),\n      install_state: _installState(),\n      sw_state: _swState(),\n      connection: _connection(),\n    });\n    return _contextCache;\n  }\n\n  function isResetRequired() {\n    return _resetRequired;\n  }\n\n  // -------------------------------------------------------------------\n  // Public surface\n  // -------------------------------------------------------------------\n  Object.defineProperty(window, 'pwaDb', {\n    value: Object.freeze({\n      open,\n      get,\n      put,\n      readModifyWrite,\n      delete: del,\n      getAll,\n      count,\n      clear,\n      appendSyncLog,\n      getSyncLog,\n      appendDebugLogBatch,\n      getDebugLog,\n      clearDebugLog,\n      context,\n      isResetRequired,\n      // Exposed for tests + doc reference. Do not mutate.\n      DB_NAME,\n      DB_VERSION,\n      STORE_NAMES: Object.freeze(Object.keys(STORES)),\n    }),\n    writable: false,\n    configurable: false,\n  });\n})();\n"],
  "mappings": "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",
  "names": ["DB_NAME", "STORES", "RETIRED_STORES", "_dbPromise", "_resetRequired", "_contextCache", "_enterResetRequired", "reason", "el", "cta", "evt", "_req", "req", "resolve", "reject", "_runMigrations", "db", "name", "opts", "_checkStorageEstimate", "estimate", "quota", "usage", "MIN_PLAUSIBLE_QUOTA_BYTES", "quotaSuspiciouslyLow", "hadPriorInstall", "open", "err", "_tx", "storeName", "mode", "op", "tx", "store", "get", "key", "s", "put", "value", "readModifyWrite", "mutate", "readReq", "next", "writeReq", "del", "count", "clear", "getAll", "limit", "SYNC_LOG_MAX_ROWS", "DEBUG_LOG_MAX_ROWS", "_trimLog", "maxRows", "countReq", "excess", "deleted", "cursorReq", "cursor", "appendSyncLog", "entry", "appendDebugLogBatch", "entries", "getDebugLog", "_readLogNewestFirst", "clearDebugLog", "getSyncLog", "max", "results", "_readMeta", "_randomHex", "bytes", "out", "i", "_sessionId", "KEY", "existing", "uuid", "_platform", "ua", "_installState", "_swState", "_connection", "c", "context", "isResetRequired"]
}
