diff --git a/.changeset/rare-schools-itch.md b/.changeset/rare-schools-itch.md new file mode 100644 index 000000000000..3e4cd3ad8926 --- /dev/null +++ b/.changeset/rare-schools-itch.md @@ -0,0 +1,6 @@ +--- +"@sveltejs/kit": minor +--- + +feat: allow adapters to override getRequest and setResponse + \ No newline at end of file diff --git a/documentation/docs/25-build-and-deploy/99-writing-adapters.md b/documentation/docs/25-build-and-deploy/99-writing-adapters.md index a4002696a018..154c83adf38f 100644 --- a/documentation/docs/25-build-and-deploy/99-writing-adapters.md +++ b/documentation/docs/25-build-and-deploy/99-writing-adapters.md @@ -13,6 +13,8 @@ type AdapterSpecificOptions = any; // @filename: index.js // ---cut--- +import { getRequest, setResponse } from '@sveltejs/kit/node'; + /** @param {AdapterSpecificOptions} options */ export default function (options) { /** @type {import('@sveltejs/kit').Adapter} */ @@ -40,6 +42,15 @@ export default function (options) { // Return `false if it can't, or throw a descriptive error. } }, + getRequest(options) { + const request = getRequest(options); + // modify the Request object here if needed + return request; + }, + setResponse(res, response) { + // handle WebSockets here, for example + setResponse(res, response); + }, vite: { plugins: { // add plugins here to integrate with Vite @@ -53,7 +64,7 @@ export default function (options) { } ``` -Of these, `name` and `adapt` are required. `emulate`, `vite`, and `supports` are optional. +Of these, `name` and `adapt` are required. `emulate`, `vite`, `getRequest`, `setResponse`, and `supports` are optional. Within the `adapt` method, there are a number of things that an adapter should do: diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 8f5cf5f0f4a3..eecdde2b0856 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -17,6 +17,7 @@ import { Plugin } from 'vite'; import { RouteId as AppRouteId, LayoutParams as AppLayoutParams } from '$app/types'; import { ParamMatcher } from '@sveltejs/kit/params'; import { StandardSchemaV1 } from '@standard-schema/spec'; +import { getRequest, setResponse } from '@sveltejs/kit/node'; export { PrerenderOption } from '../types/private.js'; @@ -52,6 +53,18 @@ export interface Adapter { */ instrumentation?: () => boolean; }; + /** + * This function overrides the default behavior to convert an `http.IncomingMessage` to a `Request` object. + * To call the original setRequest function, import it from `@sveltejs/kit/node`. + * @since 3.0.0 + */ + getRequest?: typeof getRequest; + /** + * This function overrides the default behavior to write a `Response` object to an `http.ServerResponse`. + * To call the original setResponse function, import it from `@sveltejs/kit/node`. + * @since 3.0.0 + */ + setResponse?: typeof setResponse; /** * Creates an `Emulator`, which allows the adapter to influence the environment * during dev, build and prerendering. diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index 6057b70cb612..f4d4f3cd813a 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -591,7 +591,7 @@ export async function dev( read: (file) => createReadableStream(from_fs(file)) }); - const request = getRequest({ + const request = (svelte_config.adapter?.getRequest ?? getRequest)({ base, request: req }); @@ -643,11 +643,11 @@ export async function dev( // @ts-expect-error serve_static_middleware.handle(req, res, () => { log_response(rendered.status, request); - setResponse(res, rendered); + (svelte_config.adapter?.setResponse ?? setResponse)(res, rendered); }); } else { log_response(rendered.status, request); - setResponse(res, rendered); + (svelte_config.adapter?.setResponse ?? setResponse)(res, rendered); } } catch (e) { const error = coalesce_to_error(e); diff --git a/packages/kit/src/exports/vite/preview/index.js b/packages/kit/src/exports/vite/preview/index.js index 37524cab3604..9c6db2c28bc3 100644 --- a/packages/kit/src/exports/vite/preview/index.js +++ b/packages/kit/src/exports/vite/preview/index.js @@ -204,12 +204,12 @@ export async function preview(vite, vite_config, svelte_config) { vite.middlewares.use(async (req, res) => { const host = req.headers[':authority'] || req.headers.host; - const request = getRequest({ + const request = (svelte_config.adapter?.getRequest ?? getRequest)({ base: `${protocol}://${host}`, request: req }); - setResponse( + (svelte_config.adapter?.setResponse ?? setResponse)( res, await server.respond(request, { getClientAddress: () => { diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 2694326106bc..1b6553742e4f 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -5,6 +5,7 @@ declare module '@sveltejs/kit' { import type { Plugin } from 'vite'; import type { RouteId as AppRouteId, LayoutParams as AppLayoutParams } from '$app/types'; import type { StandardSchemaV1 } from '@standard-schema/spec'; + import type { getRequest, setResponse } from '@sveltejs/kit/node'; import type { Config } from '@sveltejs/kit/vite'; // @ts-ignore this is an optional peer dependency so could be missing. Written like this so dts-buddy preserves the ts-ignore type Span = import('@opentelemetry/api').Span; @@ -38,6 +39,18 @@ declare module '@sveltejs/kit' { */ instrumentation?: () => boolean; }; + /** + * This function overrides the default behavior to convert an `http.IncomingMessage` to a `Request` object. + * To call the original setRequest function, import it from `@sveltejs/kit/node`. + * @since 3.0.0 + */ + getRequest?: typeof getRequest; + /** + * This function overrides the default behavior to write a `Response` object to an `http.ServerResponse`. + * To call the original setResponse function, import it from `@sveltejs/kit/node`. + * @since 3.0.0 + */ + setResponse?: typeof setResponse; /** * Creates an `Emulator`, which allows the adapter to influence the environment * during dev, build and prerendering.