Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/early-lions-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-vercel': patch
---

fix: ensure `read` works in an edge function that has deployment protection. Protection bypass automation must be enabled
4 changes: 4 additions & 0 deletions documentation/docs/25-build-and-deploy/90-adapter-vercel.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,7 @@ You can't use `fs` in edge functions.
You _can_ use it in serverless functions, but it won't work as expected, since files are not copied from your project into your deployment. Instead, use the [`read`]($app-server#read) function from `$app/server` to access your files. It also works inside routes deployed as edge functions by fetching the file from the deployed public assets location.

Alternatively, you can [prerender](page-options#prerender) the routes in question.

### Deployment protection

If using [`read`]($app-server#read) in an edge function, SvelteKit will `fetch` the file in question from your deployment. If you are using [Deployment Protection](https://vercel.com/docs/deployment-protection), you must also enable [Protection Bypass for Automation](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation) so that the request does not result in a [401 Unauthorized](https://http.dog/401) response.
28 changes: 26 additions & 2 deletions packages/adapter-vercel/files/edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import { manifest } from 'MANIFEST';

const server = new Server(manifest);

/** @type {HeadersInit | undefined} */
let read_headers;
if (process.env.VERCEL_AUTOMATION_BYPASS_SECRET) {
read_headers = {
'x-vercel-protection-bypass': process.env.VERCEL_AUTOMATION_BYPASS_SECRET
};
}

/**
* We don't know the origin until we receive a request, but
* that's guaranteed to happen before we call `read`
Expand All @@ -15,10 +23,26 @@ let origin;
const initialized = server.init({
env: /** @type {Record<string, string>} */ (process.env),
read: async (file) => {
const response = await fetch(`${origin}/${file}`);
const url = `${origin}/${file}`;
const response = await fetch(url, {
// we need to add a bypass header if the user has deployment protection enabled
// see https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation
headers: read_headers
});

if (!response.ok) {
throw new Error(`Failed to fetch ${file}: ${response.status} ${response.statusText}`);
if (response.status === 401) {
throw new Error(
`Please enable Protection Bypass for Automation: https://svelte.dev/docs/kit/adapter-vercel#Troubleshooting-Deployment-protection`
);
}

// belt and braces — not sure how we could end up here
throw new Error(
`read(...) failed: could not fetch ${url} (${response.status} ${response.statusText})`
);
}

return response.body;
}
});
Expand Down
Loading