diff --git a/.changeset/polite-files-relate.md b/.changeset/polite-files-relate.md new file mode 100644 index 000000000000..8ad02e77daab --- /dev/null +++ b/.changeset/polite-files-relate.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-vercel': minor +--- + +feat: provide access to request context via `event.platform` diff --git a/packages/adapter-vercel/ambient.d.ts b/packages/adapter-vercel/ambient.d.ts index 537f7cc041d1..a106f64e3f12 100644 --- a/packages/adapter-vercel/ambient.d.ts +++ b/packages/adapter-vercel/ambient.d.ts @@ -1,8 +1,12 @@ -declare module 'SERVER' { - export { Server } from '@sveltejs/kit'; -} +import { RequestContext } from './index.js'; -declare module 'MANIFEST' { - import { SSRManifest } from '@sveltejs/kit'; - export const manifest: SSRManifest; +declare global { + namespace App { + export interface Platform { + /** + * `context` is only available in Edge Functions + */ + context?: RequestContext; + } + } } diff --git a/packages/adapter-vercel/files/edge.js b/packages/adapter-vercel/files/edge.js index b7d58f9c9c32..ce603b6e3920 100644 --- a/packages/adapter-vercel/files/edge.js +++ b/packages/adapter-vercel/files/edge.js @@ -8,12 +8,16 @@ const initialized = server.init({ /** * @param {Request} request + * @param {import('../index.js').RequestContext} context */ -export default async (request) => { +export default async (request, context) => { await initialized; return server.respond(request, { getClientAddress() { return /** @type {string} */ (request.headers.get('x-forwarded-for')); + }, + platform: { + context } }); }; diff --git a/packages/adapter-vercel/index.d.ts b/packages/adapter-vercel/index.d.ts index 6f95260b4349..ea45bf4e0ac5 100644 --- a/packages/adapter-vercel/index.d.ts +++ b/packages/adapter-vercel/index.d.ts @@ -1,4 +1,5 @@ import { Adapter } from '@sveltejs/kit'; +import './ambient.js'; export default function plugin(config?: Config): Adapter; @@ -77,3 +78,59 @@ export interface EdgeConfig { } export type Config = EdgeConfig | ServerlessConfig; + +// we copy the RequestContext interface from `@vercel/edge` because that package can't co-exist with `@types/node`. +// see https://github.com/sveltejs/kit/pull/9280#issuecomment-1452110035 + +/** + * An extension to the standard `Request` object that is passed to every Edge Function. + * + * @example + * ```ts + * import type { RequestContext } from '@vercel/edge'; + * + * export default async function handler(request: Request, ctx: RequestContext): Promise { + * // ctx is the RequestContext + * } + * ``` + */ +export interface RequestContext { + /** + * A method that can be used to keep the function running after a response has been sent. + * This is useful when you have an async task that you want to keep running even after the + * response has been sent and the request has ended. + * + * @example + * + * Sending an internal error to an error tracking service + * + * ```ts + * import type { RequestContext } from '@vercel/edge'; + * + * export async function handleRequest(request: Request, ctx: RequestContext): Promise { + * try { + * return await myFunctionThatReturnsResponse(); + * } catch (e) { + * ctx.waitUntil((async () => { + * // report this error to your error tracking service + * await fetch('https://my-error-tracking-service.com', { + * method: 'POST', + * body: JSON.stringify({ + * stack: e.stack, + * message: e.message, + * name: e.name, + * url: request.url, + * }), + * }); + * })()); + * return new Response('Internal Server Error', { status: 500 }); + * } + * } + * ``` + */ + waitUntil( + /** + * A promise that will be kept alive until it resolves or rejects. + */ promise: Promise + ): void; +} diff --git a/packages/adapter-vercel/internal.d.ts b/packages/adapter-vercel/internal.d.ts new file mode 100644 index 000000000000..537f7cc041d1 --- /dev/null +++ b/packages/adapter-vercel/internal.d.ts @@ -0,0 +1,8 @@ +declare module 'SERVER' { + export { Server } from '@sveltejs/kit'; +} + +declare module 'MANIFEST' { + import { SSRManifest } from '@sveltejs/kit'; + export const manifest: SSRManifest; +} diff --git a/packages/adapter-vercel/tsconfig.json b/packages/adapter-vercel/tsconfig.json index ddff01c72d30..f93d6d1bbcc8 100644 --- a/packages/adapter-vercel/tsconfig.json +++ b/packages/adapter-vercel/tsconfig.json @@ -14,5 +14,5 @@ "@sveltejs/kit": ["../kit/types/index"] } }, - "include": ["**/*.js", "ambient.d.ts"] + "include": ["**/*.js", "index.d.ts", "internal.d.ts"] }