| 5 | import { sha256Hex } from './specs.js'; |
| 6 | |
| 7 | export async function fetchWithLockfile(spec, lockfile, ctx) { |
| 8 | const { cache, baseUrl, entryDir, knownMissing, integrityActive } = ctx; |
| 9 | |
| 10 | if (integrityActive) { |
| 11 | const expected = lockfile.get(spec); |
| 12 | if (expected) { |
| 13 | const cached = await cache.getBytes(expected); |
| 14 | if (cached) return new Uint8Array(cached); |
| 15 | } |
| 16 | } |
| 17 | |
| 18 | let resp; |
| 19 | try { |
| 20 | const absolute = spec.includes('://') || spec.startsWith('/'); |
| 21 | const path = absolute ? spec : entryDir + spec; |
| 22 | const url = path.includes('://') ? path : new URL(path, baseUrl ?? self.location.href).toString(); |
| 23 | resp = await fetch(url); |
| 24 | } catch (e) { |
| 25 | console.warn(`[edge-python] fetch failed for '${spec}':`, e); |
| 26 | return null; |
| 27 | } |
| 28 | |
| 29 | if (!resp.ok) { |
| 30 | if (resp.status === 404 && spec.endsWith('packages.json')) knownMissing.add(spec); |
| 31 | else console.warn(`[edge-python] ${resp.status} for '${spec}' at ${resp.url}`); |
| 32 | return null; |
| 33 | } |
| 34 | |
| 35 | // A .wasm answered with HTML/text is a schemeless spec resolved relative and hitting an SPA fallback, not a module. |
| 36 | if (spec.endsWith('.wasm')) { |
| 37 | const ct = (resp.headers.get('content-type') || '').toLowerCase(); |
| 38 | if (ct.includes('html') || ct.startsWith('text/')) { |
| 39 | console.warn(`[edge-python] '${spec}' served as '${ct || 'no content-type'}', not a wasm module`); |
| 40 | return null; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | const bytes = new Uint8Array(await resp.arrayBuffer()); |
| 45 | |
| 46 | if (integrityActive) { |
| 47 | const hash = await sha256Hex(bytes); |
| 48 | const expected = lockfile.get(spec); |
| 49 | if (expected && expected !== hash) { |
| 50 | throw new Error(`[edge-python] integrity drift for '${spec}'\n locked: sha256-${expected}\n remote: sha256-${hash}`); |
| 51 | } |
| 52 | await cache.putBytes(hash, bytes); |
| 53 | lockfile.set(spec, hash); |
| 54 | } |
| 55 | |
| 56 | return bytes; |
| 57 | } |