Expose `add_cookies_to_headers` via `cookies.write`
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 20.8k
- Forks
- 2.3k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 156
Description
Describe the problem
This has been discussed before in #8409 and #7611, but I think we have a bit of a different use case here.
We're working on a cookie manager library that layers on some additional niceties to the cookies API in SvelteKit (e.g. defining and validating the shape of cookies, handling serializing to/from JSON and base64, ability to manage and write cookies both server side and client side, etc). The manager allows libraries to define their own cookies and then export them, so you can have shared cookies between different libraries more easily:
export const cookieManager = new SvelteKitCookieManager({
deviceId: {
key: 'device_id',
validator: (z) => z.string(),
}
});
// Usage
cookieManager.getWriter('server', event).get('deviceId');
cookieManager.getWriter('server', event).set('deviceId', 'foo');
This is all typed and really nice to work with. The tricky part is that we can't really use it in both hooks and +page.server.ts contexts, because in hooks we can't use the cookies API, but in +page.server.ts we must use the cookies API, there's no way for us to add set-cookies headers otherwise. Currently it seems like the only option is to have a new type of writer or some other option for changing the behavior in hooks vs pages.
cookieManager.getWriter('server', event.cookies).get('deviceId');
cookieManager.getWriter('server-hooks', event.headers.get('cookie')).set('deviceId', 'foo');
Describe the proposed solution
I feel like this could be remedied by exposing the add_cookies_to_headers function on the cookies API. This would only be callable once per request, it would throw if called a second time. The purpose would be so that hooks that return custom responses can optionally choose to write out the added cookies manually at some point.
Alternatives considered
We could allow users to add the set-cookie header via the headers API. Our library currently outputs the set-cookie value as a string, so it would be easy to add it that way, but it does seem a bit hacky.
We could also always serialize cookies to all responses, but this would be tricky. I think there are a couple ways to approach this:
- Serialize cookies at the end of hooks. As noted in #7611 this would result in a gap between cookies being added and hooks resolving, so hooks would no longer see any added cookies. This would also be a breaking API change so probably not worth it.
- Add cookies at the end of handle IFF they have not been added by
resolve(e.g. resolve has not been called). Throw an error otherwise. This would work well, but would mean that users can't callresolve, ignore the response, and then set cookies, which would be a weird edge case. - Add cookies twice, once at the end of resolve and once at the end of handle. Set cookies would be cleared in between so they don't set twice, just new ones would be added the second time. This would allow the API to be used in all cases and allow
resolvecookies to be ignored by hooks, but would be more complex and require some additional bookkeeping to flush the cookies between sets.
Importance
nice to have
Additional Information
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the cookies API and the hooks/resolve response flow described in the issue, then review discussions #8409 and #7611 for prior constraints. The work is done when a caller can invoke add_cookies_to_headers through cookies.write once for a custom response, with a second invocation rejected, and the behavior is covered by relevant tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100