icflorescu/trpc-sveltekit

trpc context doesn't sync to "local" context

vloe opened this issue · 6 comments

vloe commented

Describe the bug
can't seem to use the trpc context like the local context. example: you can set cookie in load function with event.cookie.set(...), but this doesn't work with trpc context.

To Reproduce
Steps to reproduce the behavior:

  1. return event in context:
// lib/trpc/context
export async function createContext(event: RequestEvent) {
	return {
		event
	};
}
  1. use context to set cookie:
// lib/trpc/routes/auth
ctx.event.cookies.set('token', Md5.hashStr(email));

Expected behavior
whenever the event from trpc context changes, it should sync with "local" context. if not expected behavior how does one do this?

I am dealing exactly with the same issue. It's not a bug of this repo though.

trpc creates it's own response, so updating cookies on event doesn't make sense.

What works is:

createContext: ({ req, resHeaders }) => {
  return {resHeaders};
})

and later you can do:

  ctx.resHeaders.set("set-cookie", cookie.serialize("authToken", session.authToken));

but that's a very ugly workaround, so I wonder what's the expected pattern in this case.

🤞 @icflorescu can give us a better hint.

vloe commented

thanks @michaltaberski, but I didn't manage to get your solution to work. this is the closest I've gotten:

// hooks.server.ts
export const handle = createTRPCHandle({
	router,
	createContext,
	responseMeta() {
		return {
			headers: {
				'set-cookie': 'test'
			}
		};
	}
}) satisfies Handle;

there should definitely be a better way of doing this. isn't the whole point of trpc (besides typesafety) to have full control over the response? otherwise one could just use normal serverless functions...

I’m running into the same problem when trying to set cookies or headers inside a truck procedure.

I'm also having troubles with this when trying to delete or update a cookie initially set in a non tRPC endpoint.

For anyone running into this, one way I've found to still use SvelteKit cookies is to manually add them through the Response Meta. You can create the tRPC Handler like this:

const trpcHandler = createTRPCHandle({
  router: appRouter,
  createContext,
  // @ts-expect-error: `responseMeta` expects `headers` to be `Record<string, string>` but `Record<string, string | string[]>` works .
  responseMeta({ ctx, type }) {
    if (ctx && (type === "mutation" || type === "query")) {
      const { cookies } = ctx;
      return {
        headers: {
          // eslint-disable-next-line @typescript-eslint/naming-convention
          "set-cookie": cookies
            .getAll()
            .map(({ name, value }) =>
              cookies.serialize(name, value, cookieOptions)
            ),
        },
      };
    }

    return {};
  },
}) satisfies Handle;

This will allow you to use SvelteKit cookies in your queries and mutations.

vloe commented

Can confirm @allezxandre's solution works fine, thank you! (: