Skip to content

refactor: use cookie-es for cookie utils #13512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cool-chefs-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

migrate to cookie-es for cookie parsing and splitting
5 changes: 2 additions & 3 deletions packages/adapter-netlify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"esbuild": "^0.24.0",
"set-cookie-parser": "^2.6.0"
"cookie-es": "^2.0.0",
"esbuild": "^0.24.0"
},
"devDependencies": {
"@netlify/functions": "^3.0.0",
Expand All @@ -53,7 +53,6 @@
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "^5.0.1",
"@types/node": "^18.19.48",
"@types/set-cookie-parser": "^2.4.7",
"rollup": "^4.14.2",
"typescript": "^5.3.3",
"vitest": "^3.0.1"
Expand Down
4 changes: 2 additions & 2 deletions packages/adapter-netlify/src/headers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as set_cookie_parser from 'set-cookie-parser';
import { splitSetCookieString } from 'cookie-es';

/**
* Splits headers into two categories: single value and multi value
Expand All @@ -18,7 +18,7 @@ export function split_headers(headers) {
headers.forEach((value, key) => {
if (key === 'set-cookie') {
if (!m[key]) m[key] = [];
m[key].push(...set_cookie_parser.splitCookiesString(value));
m[key].push(...splitSetCookieString(value));
} else {
h[key] = value;
}
Expand Down
5 changes: 1 addition & 4 deletions packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,21 @@
"homepage": "https://svelte.dev",
"type": "module",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^0.6.0",
"cookie-es": "^2.0.0",
"devalue": "^5.1.0",
"esm-env": "^1.2.2",
"import-meta-resolve": "^4.1.0",
"kleur": "^4.1.5",
"magic-string": "^0.30.5",
"mrmime": "^2.0.0",
"sade": "^1.8.1",
"set-cookie-parser": "^2.6.0",
"sirv": "^3.0.0"
},
"devDependencies": {
"@playwright/test": "^1.44.1",
"@sveltejs/vite-plugin-svelte": "^5.0.1",
"@types/connect": "^3.4.38",
"@types/node": "^18.19.48",
"@types/set-cookie-parser": "^2.4.7",
"dts-buddy": "^0.5.5",
"rollup": "^4.14.2",
"svelte": "^5.2.9",
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/src/exports/node/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createReadStream } from 'node:fs';
import { Readable } from 'node:stream';
import * as set_cookie_parser from 'set-cookie-parser';
import { splitSetCookieString } from 'cookie-es';
import { SvelteKitError } from '../../runtime/control.js';

/**
Expand Down Expand Up @@ -145,7 +145,7 @@ export async function setResponse(res, response) {
res.setHeader(
key,
key === 'set-cookie'
? set_cookie_parser.splitCookiesString(
? splitSetCookieString(
// This is absurd but necessary, TODO: investigate why
/** @type {string}*/ (response.headers.get(key))
)
Expand Down
13 changes: 8 additions & 5 deletions packages/kit/src/exports/public.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,13 @@ export interface Cookies {
* @param name the name of the cookie
* @param opts the options, passed directly to `cookie.parse`. See documentation [here](https://github.com/jshttp/cookie#cookieparsestr-options)
*/
get: (name: string, opts?: import('cookie').CookieParseOptions) => string | undefined;
get: (name: string, opts?: import('cookie-es').CookieParseOptions) => string | undefined;

/**
* Gets all cookies that were previously set with `cookies.set`, or from the request headers.
* @param opts the options, passed directly to `cookie.parse`. See documentation [here](https://github.com/jshttp/cookie#cookieparsestr-options)
*/
getAll: (opts?: import('cookie').CookieParseOptions) => Array<{ name: string; value: string }>;
getAll: (opts?: import('cookie-es').CookieParseOptions) => Array<{ name: string; value: string }>;

/**
* Sets a cookie. This will add a `set-cookie` header to the response, but also make the cookie available via `cookies.get` or `cookies.getAll` during the current request.
Expand All @@ -236,7 +236,7 @@ export interface Cookies {
set: (
name: string,
value: string,
opts: import('cookie').CookieSerializeOptions & { path: string }
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => void;

/**
Expand All @@ -246,7 +246,10 @@ export interface Cookies {
* @param name the name of the cookie
* @param opts the options, passed directly to `cookie.serialize`. The `path` must match the path of the cookie you want to delete. See documentation [here](https://github.com/jshttp/cookie#cookieserializename-value-options)
*/
delete: (name: string, opts: import('cookie').CookieSerializeOptions & { path: string }) => void;
delete: (
name: string,
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => void;

/**
* Serialize a cookie name-value pair into a `Set-Cookie` header string, but don't apply it to the response.
Expand All @@ -262,7 +265,7 @@ export interface Cookies {
serialize: (
name: string,
value: string,
opts: import('cookie').CookieSerializeOptions & { path: string }
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => string;
}

Expand Down
7 changes: 0 additions & 7 deletions packages/kit/src/exports/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,6 @@ async function kit({ svelte_config }) {
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false',
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false'
};

// These Kit dependencies are packaged as CommonJS, which means they must always be externalized.
// Without this, the tests will still pass but `pnpm dev` will fail in projects that link `@sveltejs/kit`.
/** @type {NonNullable<import('vite').UserConfig['ssr']>} */ (new_config.ssr).external = [
'cookie',
'set-cookie-parser'
];
}

warn_overridden_config(config, new_config);
Expand Down
8 changes: 4 additions & 4 deletions packages/kit/src/runtime/server/cookie.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parse, serialize } from 'cookie';
import { parse, serialize } from 'cookie-es';
import { normalize_path, resolve } from '../../utils/url.js';
import { add_data_suffix } from '../pathname.js';

Expand Down Expand Up @@ -40,7 +40,7 @@ export function get_cookies(request, url, trailing_slash) {
/** @type {Record<string, import('./page/types.js').Cookie>} */
const new_cookies = {};

/** @type {import('cookie').CookieSerializeOptions} */
/** @type {import('cookie-es').CookieSerializeOptions} */
const defaults = {
httpOnly: true,
sameSite: 'lax',
Expand All @@ -56,7 +56,7 @@ export function get_cookies(request, url, trailing_slash) {

/**
* @param {string} name
* @param {import('cookie').CookieParseOptions} [opts]
* @param {import('cookie-es').CookieParseOptions} [opts]
*/
get(name, opts) {
const c = new_cookies[name];
Expand Down Expand Up @@ -92,7 +92,7 @@ export function get_cookies(request, url, trailing_slash) {
},

/**
* @param {import('cookie').CookieParseOptions} [opts]
* @param {import('cookie-es').CookieParseOptions} [opts]
*/
getAll(opts) {
const cookies = parse(header, { decode: opts?.decode });
Expand Down
10 changes: 4 additions & 6 deletions packages/kit/src/runtime/server/fetch.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as set_cookie_parser from 'set-cookie-parser';
import { splitSetCookieString, parseSetCookie } from 'cookie-es';
import { respond } from './respond.js';
import * as paths from '__sveltekit/paths';
import { read_implementation } from '__sveltekit/server';
Expand Down Expand Up @@ -154,18 +154,16 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade

const set_cookie = response.headers.get('set-cookie');
if (set_cookie) {
for (const str of set_cookie_parser.splitCookiesString(set_cookie)) {
const { name, value, ...options } = set_cookie_parser.parseString(str, {
decodeValues: false
});
for (const str of splitSetCookieString(set_cookie)) {
const { name, value, ...options } = parseSetCookie(str, { decode: false });

const path = options.path ?? (url.pathname.split('/').slice(0, -1).join('/') || '/');

// options.sameSite is string, something more specific is required - type cast is safe
set_internal(name, value, {
path,
encode: (value) => value,
.../** @type {import('cookie').CookieSerializeOptions} */ (options)
.../** @type {import('cookie-es').CookieSerializeOptions} */ (options)
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/page/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CookieSerializeOptions } from 'cookie';
import { CookieSerializeOptions } from 'cookie-es';
import { SSRNode, CspDirectives, ServerDataNode } from 'types';

export interface Fetched {
Expand Down
13 changes: 8 additions & 5 deletions packages/kit/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ declare module '@sveltejs/kit' {
* @param name the name of the cookie
* @param opts the options, passed directly to `cookie.parse`. See documentation [here](https://github.com/jshttp/cookie#cookieparsestr-options)
*/
get: (name: string, opts?: import('cookie').CookieParseOptions) => string | undefined;
get: (name: string, opts?: import('cookie-es').CookieParseOptions) => string | undefined;

/**
* Gets all cookies that were previously set with `cookies.set`, or from the request headers.
* @param opts the options, passed directly to `cookie.parse`. See documentation [here](https://github.com/jshttp/cookie#cookieparsestr-options)
*/
getAll: (opts?: import('cookie').CookieParseOptions) => Array<{ name: string; value: string }>;
getAll: (opts?: import('cookie-es').CookieParseOptions) => Array<{ name: string; value: string }>;

/**
* Sets a cookie. This will add a `set-cookie` header to the response, but also make the cookie available via `cookies.get` or `cookies.getAll` during the current request.
Expand All @@ -218,7 +218,7 @@ declare module '@sveltejs/kit' {
set: (
name: string,
value: string,
opts: import('cookie').CookieSerializeOptions & { path: string }
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => void;

/**
Expand All @@ -228,7 +228,10 @@ declare module '@sveltejs/kit' {
* @param name the name of the cookie
* @param opts the options, passed directly to `cookie.serialize`. The `path` must match the path of the cookie you want to delete. See documentation [here](https://github.com/jshttp/cookie#cookieserializename-value-options)
*/
delete: (name: string, opts: import('cookie').CookieSerializeOptions & { path: string }) => void;
delete: (
name: string,
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => void;

/**
* Serialize a cookie name-value pair into a `Set-Cookie` header string, but don't apply it to the response.
Expand All @@ -244,7 +247,7 @@ declare module '@sveltejs/kit' {
serialize: (
name: string,
value: string,
opts: import('cookie').CookieSerializeOptions & { path: string }
opts: import('cookie-es').CookieSerializeOptions & { path: string }
) => string;
}

Expand Down
Loading
Loading