diff --git a/.changeset/fifty-eagles-invite.md b/.changeset/fifty-eagles-invite.md new file mode 100644 index 00000000..1cc0051d --- /dev/null +++ b/.changeset/fifty-eagles-invite.md @@ -0,0 +1,5 @@ +--- +'@edge-runtime/cookies': patch +--- + +fix cookies() .set() to reflect the priority attribute into set-cookie diff --git a/packages/cookies/src/serialize.ts b/packages/cookies/src/serialize.ts index db68696c..52955d9b 100644 --- a/packages/cookies/src/serialize.ts +++ b/packages/cookies/src/serialize.ts @@ -14,6 +14,7 @@ export function stringifyCookie(c: ResponseCookie | RequestCookie): string { 'secure' in c && c.secure && 'Secure', 'httpOnly' in c && c.httpOnly && 'HttpOnly', 'sameSite' in c && c.sameSite && `SameSite=${c.sameSite}`, + 'priority' in c && c.priority && `Priority=${c.priority}`, ].filter(Boolean) return `${c.name}=${encodeURIComponent(c.value ?? '')}; ${attrs.join('; ')}` @@ -54,10 +55,18 @@ export function parseSetCookie(setCookie: string): undefined | ResponseCookie { } const [[name, value], ...attributes] = parseCookie(setCookie) - const { domain, expires, httponly, maxage, path, samesite, secure } = - Object.fromEntries( - attributes.map(([key, value]) => [key.toLowerCase(), value]), - ) + const { + domain, + expires, + httponly, + maxage, + path, + samesite, + secure, + priority, + } = Object.fromEntries( + attributes.map(([key, value]) => [key.toLowerCase(), value]), + ) const cookie: ResponseCookie = { name, value: decodeURIComponent(value), @@ -68,6 +77,7 @@ export function parseSetCookie(setCookie: string): undefined | ResponseCookie { path, ...(samesite && { sameSite: parseSameSite(samesite) }), ...(secure && { secure: true }), + ...(priority && { priority: parsePriority(priority) }), } return compact(cookie) @@ -91,3 +101,12 @@ function parseSameSite(string: string): ResponseCookie['sameSite'] { ? (string as ResponseCookie['sameSite']) : undefined } + +const PRIORITY: ResponseCookie['priority'][] = ['low', 'medium', 'high'] + +function parsePriority(string: string): ResponseCookie['priority'] { + string = string.toLowerCase() + return PRIORITY.includes(string as any) + ? (string as ResponseCookie['priority']) + : undefined +} diff --git a/packages/cookies/test/response-cookies.test.ts b/packages/cookies/test/response-cookies.test.ts index 28456650..90706a7e 100644 --- a/packages/cookies/test/response-cookies.test.ts +++ b/packages/cookies/test/response-cookies.test.ts @@ -64,6 +64,25 @@ test('reflect .set into `set-cookie`', async () => { ) }) +it('reflect .set all options attributes into `set-cookie`', async () => { + const headers = new Headers() + const cookies = new ResponseCookies(headers) + cookies.set('first-name', 'first-value', { + domain: 'custom-domain', + path: 'custom-path', + secure: true, + sameSite: 'strict', + expires: new Date(2100, 0, 1, 12, 0, 0), + httpOnly: true, + maxAge: 0, + priority: 'high', + }) + const cookiesInHeaders = Object.fromEntries(headers.entries())['set-cookie'] + expect(cookiesInHeaders).toBe( + 'first-name=first-value; Path=custom-path; Expires=Fri, 01 Jan 2100 12:00:00 GMT; Max-Age=0; Domain=custom-domain; Secure; HttpOnly; SameSite=strict; Priority=high', + ) +}) + describe('`set-cookie` into .get and .getAll', () => { test.each([ 'name=value; Secure; HttpOnly',