|
import { BROWSER, DEV } from 'esm-env'; |
|
import { hash } from '../hash.js'; |
|
import { b64_decode } from '../utils.js'; |
|
|
|
let loading = 0; |
|
|
|
|
|
export const native_fetch = BROWSER ? window.fetch : (() => {}); |
|
|
|
export function lock_fetch() { |
|
loading += 1; |
|
} |
|
|
|
export function unlock_fetch() { |
|
loading -= 1; |
|
} |
|
|
|
if (DEV && BROWSER) { |
|
let can_inspect_stack_trace = false; |
|
|
|
|
|
|
|
const check_stack_trace = async () => { |
|
const stack = (new Error().stack); |
|
can_inspect_stack_trace = stack.includes('check_stack_trace'); |
|
}; |
|
|
|
check_stack_trace(); |
|
|
|
|
|
|
|
|
|
|
|
window.fetch = (input, init) => { |
|
|
|
|
|
|
|
const url = input instanceof Request ? input.url : input.toString(); |
|
const stack_array = (new Error().stack).split('\n'); |
|
|
|
|
|
|
|
|
|
const cutoff = stack_array.findIndex((a) => a.includes('load@') || a.includes('at load')); |
|
const stack = stack_array.slice(0, cutoff + 2).join('\n'); |
|
|
|
const in_load_heuristic = can_inspect_stack_trace |
|
? stack.includes('src/runtime/client/client.js') |
|
: loading; |
|
|
|
|
|
const used_kit_fetch = init?.__sveltekit_fetch__; |
|
|
|
if (in_load_heuristic && !used_kit_fetch) { |
|
console.warn( |
|
`Loading ${url} using \`window.fetch\`. For best results, use the \`fetch\` that is passed to your \`load\` function: https://kit.svelte.dev/docs/load#making-fetch-requests` |
|
); |
|
} |
|
|
|
const method = input instanceof Request ? input.method : init?.method || 'GET'; |
|
|
|
if (method !== 'GET') { |
|
cache.delete(build_selector(input)); |
|
} |
|
|
|
return native_fetch(input, init); |
|
}; |
|
} else if (BROWSER) { |
|
window.fetch = (input, init) => { |
|
const method = input instanceof Request ? input.method : init?.method || 'GET'; |
|
|
|
if (method !== 'GET') { |
|
cache.delete(build_selector(input)); |
|
} |
|
|
|
return native_fetch(input, init); |
|
}; |
|
} |
|
|
|
const cache = new Map(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function initial_fetch(resource, opts) { |
|
const selector = build_selector(resource, opts); |
|
|
|
const script = document.querySelector(selector); |
|
if (script?.textContent) { |
|
let { body, ...init } = JSON.parse(script.textContent); |
|
|
|
const ttl = script.getAttribute('data-ttl'); |
|
if (ttl) cache.set(selector, { body, init, ttl: 1000 * Number(ttl) }); |
|
const b64 = script.getAttribute('data-b64'); |
|
if (b64 !== null) { |
|
|
|
|
|
body = b64_decode(body); |
|
} |
|
|
|
return Promise.resolve(new Response(body, init)); |
|
} |
|
|
|
return DEV ? dev_fetch(resource, opts) : window.fetch(resource, opts); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function subsequent_fetch(resource, resolved, opts) { |
|
if (cache.size > 0) { |
|
const selector = build_selector(resource, opts); |
|
const cached = cache.get(selector); |
|
if (cached) { |
|
|
|
if ( |
|
performance.now() < cached.ttl && |
|
['default', 'force-cache', 'only-if-cached', undefined].includes(opts?.cache) |
|
) { |
|
return new Response(cached.body, cached.init); |
|
} |
|
|
|
cache.delete(selector); |
|
} |
|
} |
|
|
|
return DEV ? dev_fetch(resolved, opts) : window.fetch(resolved, opts); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function dev_fetch(resource, opts) { |
|
const patched_opts = { ...opts }; |
|
|
|
Object.defineProperty(patched_opts, '__sveltekit_fetch__', { |
|
value: true, |
|
writable: true, |
|
configurable: true |
|
}); |
|
return window.fetch(resource, patched_opts); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function build_selector(resource, opts) { |
|
const url = JSON.stringify(resource instanceof Request ? resource.url : resource); |
|
|
|
let selector = `script[data-sveltekit-fetched][data-url=${url}]`; |
|
|
|
if (opts?.headers || opts?.body) { |
|
|
|
const values = []; |
|
|
|
if (opts.headers) { |
|
values.push([...new Headers(opts.headers)].join(',')); |
|
} |
|
|
|
if (opts.body && (typeof opts.body === 'string' || ArrayBuffer.isView(opts.body))) { |
|
values.push(opts.body); |
|
} |
|
|
|
selector += `[data-hash="${hash(...values)}"]`; |
|
} |
|
|
|
return selector; |
|
} |
|
|