From a700a20291e19cde23705e8e661e833aec7d3095 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:51:50 +0000 Subject: [PATCH] qol(cookies): warn when cookies are set after the headers have been sent (#9627) --- .changeset/kind-waves-travel.md | 5 +++++ packages/astro/src/core/cookies/cookies.ts | 21 +++++++++++++++++++++ packages/astro/src/core/cookies/response.ts | 4 ++-- 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .changeset/kind-waves-travel.md diff --git a/.changeset/kind-waves-travel.md b/.changeset/kind-waves-travel.md new file mode 100644 index 0000000000..b01e6316ab --- /dev/null +++ b/.changeset/kind-waves-travel.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Adds a warning when setting cookies will have no effect diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts index f9214c4834..ddfb14edf8 100644 --- a/packages/astro/src/core/cookies/cookies.ts +++ b/packages/astro/src/core/cookies/cookies.ts @@ -63,10 +63,12 @@ class AstroCookies implements AstroCookiesInterface { #request: Request; #requestValues: Record | null; #outgoing: Map | null; + #consumed: boolean; constructor(request: Request) { this.#request = request; this.#requestValues = null; this.#outgoing = null; + this.#consumed = false; } /** @@ -148,6 +150,16 @@ class AstroCookies implements AstroCookiesInterface { * @param options Options for the cookie, such as the path and security settings. */ set(key: string, value: string | Record, options?: AstroCookieSetOptions): void { + if (this.#consumed) { + const warning = new Error( + 'Astro.cookies.set() was called after the cookies had already been sent to the browser.\n' + + 'This may have happened if this method was called in an imported component.\n' + + 'Please make sure that Astro.cookies.set() is only called in the frontmatter of the main page.' + ); + warning.name = "Warning"; + // eslint-disable-next-line no-console + console.warn(warning); + } let serializedValue: string; if (typeof value === 'string') { serializedValue = value; @@ -193,6 +205,15 @@ class AstroCookies implements AstroCookiesInterface { } } + /** + * Behaves the same as AstroCookies.prototype.headers(), + * but allows a warning when cookies are set after the instance is consumed. + */ + static consume(cookies: AstroCookies): Generator { + cookies.#consumed = true; + return cookies.headers(); + } + #ensureParsed(options: AstroCookieGetOptions | undefined = undefined): Record { if (!this.#requestValues) { this.#parse(options); diff --git a/packages/astro/src/core/cookies/response.ts b/packages/astro/src/core/cookies/response.ts index 013f836bf7..c4dd388934 100644 --- a/packages/astro/src/core/cookies/response.ts +++ b/packages/astro/src/core/cookies/response.ts @@ -1,4 +1,4 @@ -import type { AstroCookies } from './cookies.js'; +import { AstroCookies } from './cookies.js'; const astroCookiesSymbol = Symbol.for('astro.cookies'); @@ -24,7 +24,7 @@ export function* getSetCookiesFromResponse(response: Response): Generator