{"version":3,"file":"cache-size.cjs","names":[],"sources":["../../src/perf/cache-size.ts"],"sourcesContent":["/**\n * How large the assets a page precached actually are.\n *\n * Prefers the stored `Content-Length`, because materializing a cached ONNX model\n * or WASM binary to learn its length would pull tens of megabytes into memory on\n * every measurement. When the header is missing the size is counted off the body\n * stream instead — chunk by chunk, keeping only one chunk alive at a time.\n *\n * The fallback exists because \"no `Content-Length`\" is not the rare case a\n * header-only reader assumes. A chunked transfer drops it, a proxy that\n * re-encodes drops it, and a cross-origin response only exposes it under CORS\n * rules — and in a report a `null` from any of those is indistinguishable from a\n * model nobody measured. FAMACHApp shipped 12 field runs with both model-size\n * columns empty for exactly this reason.\n */\n\n/**\n * Count a response body's bytes without holding it in memory.\n *\n * @param response The response to drain. Consumed by this call, which is why\n *   callers pass a clone.\n * @returns The byte count, or `null` when the body cannot be read.\n */\nasync function countBodyBytes(response: Response): Promise<number | null> {\n    const body = response.body;\n    if (!body) return null;\n    const reader = body.getReader();\n    let total = 0;\n    try {\n        for (;;) {\n            const { done, value } = await reader.read();\n            if (done) break;\n            total += value.byteLength;\n        }\n    } catch {\n        return null;\n    } finally {\n        reader.releaseLock();\n    }\n    return total;\n}\n\n/**\n * Byte size of a response sitting in a Cache Storage bucket.\n *\n * @param cacheName The cache bucket to look in.\n * @param url The request URL the response was stored under.\n * @returns The size in bytes, or `null` when Cache Storage is unavailable, the\n *   entry is absent, or the body cannot be read either.\n *\n * @example\n * ```typescript\n * const bytes = await cachedResponseBytes(\"app-models\", \"/models/detect.onnx\");\n * console.log(bytes === null ? \"—\" : formatBytes(bytes)); // \"12.0 MB\"\n * ```\n */\nexport async function cachedResponseBytes(cacheName: string, url: string): Promise<number | null> {\n    if (typeof caches === \"undefined\") return null;\n    try {\n        const cache = await caches.open(cacheName);\n        const response = await cache.match(url);\n        if (!response) return null;\n\n        const header = response.headers.get(\"content-length\");\n        if (header) {\n            const bytes = Number.parseInt(header, 10);\n            if (Number.isFinite(bytes)) return bytes;\n        }\n        return await countBodyBytes(response.clone());\n    } catch {\n        return null;\n    }\n}\n"],"mappings":"AAuBA,eAAe,EAAe,EAA4C,CACtE,IAAM,EAAO,EAAS,KACtB,GAAI,CAAC,EAAM,OAAO,KAClB,IAAM,EAAS,EAAK,UAAU,EAC1B,EAAQ,EACZ,GAAI,CACA,OAAS,CACL,GAAM,CAAE,OAAM,SAAU,MAAM,EAAO,KAAK,EAC1C,GAAI,EAAM,MACV,GAAS,EAAM,UACnB,CACJ,MAAQ,CACJ,OAAO,IACX,QAAU,CACN,EAAO,YAAY,CACvB,CACA,OAAO,CACX,CAgBA,eAAsB,EAAoB,EAAmB,EAAqC,CAC9F,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,GAAI,CAEA,IAAM,EAAW,MAAM,MADH,OAAO,KAAK,CAAS,EAAA,CACZ,MAAM,CAAG,EACtC,GAAI,CAAC,EAAU,OAAO,KAEtB,IAAM,EAAS,EAAS,QAAQ,IAAI,gBAAgB,EACpD,GAAI,EAAQ,CACR,IAAM,EAAQ,OAAO,SAAS,EAAQ,EAAE,EACxC,GAAI,OAAO,SAAS,CAAK,EAAG,OAAO,CACvC,CACA,OAAO,MAAM,EAAe,EAAS,MAAM,CAAC,CAChD,MAAQ,CACJ,OAAO,IACX,CACJ"}