trpc-sveltekit
Version:
SvelteKit adapter for tRPC.io, working with Node.js, Vercel and Netlify
77 lines (76 loc) • 3.59 kB
JavaScript
import { resolveHTTPResponse } from '@trpc/server/http';
import { serialize } from 'cookie';
/**
* Create a SvelteKit handle function for tRPC requests.
*
* If you want to use it in conjunction with other SvelteKit handles,
* consider [the sequence helper function](https://kit.svelte.dev/docs/modules#sveltejs-kit-hooks).
* @see https://kit.svelte.dev/docs/hooks
*/
export function createTRPCHandle({ router, url = '/trpc', createContext, responseMeta, onError }) {
return async ({ event, resolve }) => {
if (event.url.pathname.startsWith(url + '/')) {
const request = event.request;
const req = {
method: request.method,
headers: request.headers,
query: event.url.searchParams,
body: await request.text()
};
// Using the default `event.setHeaders` and `event.cookies` will not work
// as the event in not resolved by SvelteKit. Instead, we "proxy" the access
// to the headers.
const originalSetHeaders = event.setHeaders;
const originalSetCookies = event.cookies.set;
const originalDeleteCookies = event.cookies.delete;
const headersProxy = {};
const cookiesProxy = {};
// Same as the one provided from sveltekit
const defaultCookiesOptions = {
httpOnly: true,
sameSite: 'lax',
secure: event.url.hostname === 'localhost' && event.url.protocol === 'http:' ? false : true
};
event.setHeaders = (headers) => {
for (const [key, value] of Object.entries(headers)) {
headersProxy[key] = value;
}
// Still call the original `event.setHeaders` function, as it may be used in SvelteKit internals.
originalSetHeaders(headers);
};
event.cookies.set = (name, value, options) => {
cookiesProxy[name] = { value, options: { ...defaultCookiesOptions, ...options } };
originalSetCookies(name, value, options);
};
event.cookies.delete = (name, options) => {
cookiesProxy[name] = { value: '', options: { ...options, maxAge: 0 } };
originalDeleteCookies(name, options);
};
const httpResponse = await resolveHTTPResponse({
router,
req,
path: event.url.pathname.substring(url.length + 1),
createContext: async () => createContext?.(event),
responseMeta,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onError: onError
});
const { status, headers, body } = httpResponse;
const finalHeaders = new Headers();
for (const [key, value] of Object.entries(headers)) {
finalHeaders.set(key, value);
}
for (const [key, value] of Object.entries(headersProxy)) {
finalHeaders.set(key, value);
}
if (Object.keys(cookiesProxy).length > 0) {
for (const [name, { value, options }] of Object.entries(cookiesProxy)) {
const serializedCookie = serialize(name, value, options);
finalHeaders.append('Set-Cookie', serializedCookie);
}
}
return new Response(body, { status, headers: finalHeaders });
}
return resolve(event);
};
}