import type { Handle } from "@sveltejs/kit"; import { getConfig } from "$lib/server/config"; // node's fetch hands back the body decoded but keeps these, which would make the // browser decode it again const passThrough = (res: Response) => { const headers = new Headers(res.headers); headers.delete("content-encoding"); headers.delete("content-length"); return new Response(res.body, { status: res.status, headers }); }; export const handle: Handle = async ({ event, resolve }) => { // Keep bobbin off the public network. In Cloudflare this is a Worker // service binding; the browser only ever sees the web origin. if (event.url.pathname === "/xrpc" || event.url.pathname.startsWith("/xrpc/")) { const bobbin = event.platform?.env?.BOBBIN; if (bobbin) { const upstream = new URL(event.request.url); upstream.hostname = "bobbin.internal"; return bobbin.fetch(new Request(upstream, event.request)); } } if (event.url.pathname === "/sitemap.xml" || event.url.pathname.startsWith("/sitemaps/")) { const sitemap = event.platform?.env?.SITEMAP; if (sitemap) { const upstream = new URL(event.request.url); upstream.hostname = "sitemap.internal"; return sitemap.fetch(new Request(upstream, event.request)); } const { sitemapUrl } = getConfig(); if (sitemapUrl) { return passThrough( await fetch(`${sitemapUrl}${event.url.pathname}${event.url.search}`) ); } console.warn("[hooks.server] no SITEMAP binding or SITEMAP_URL; sitemap request unhandled"); } return resolve(event, { // sveltekit blocks atcute fetch handler from reading headers // because it assumes backend APIs might return sensitive headers. // this happens when during CSR we run a fetch that was the same // as one ran during SSR, so sveltekit tries to give that fetch // the data we already had. // so we allow these headers to have atcute function properly. filterSerializedResponseHeaders(name) { return name === "content-type" || name === "content-length"; } }); };