Skip to content

Commit a700a20

Browse files
authoredJan 10, 2024
qol(cookies): warn when cookies are set after the headers have been sent (#9627)
1 parent a4f90d9 commit a700a20

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed
 

‎.changeset/kind-waves-travel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"astro": patch
3+
---
4+
5+
Adds a warning when setting cookies will have no effect

‎packages/astro/src/core/cookies/cookies.ts

+21
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ class AstroCookies implements AstroCookiesInterface {
6363
#request: Request;
6464
#requestValues: Record<string, string> | null;
6565
#outgoing: Map<string, [string, string, boolean]> | null;
66+
#consumed: boolean;
6667
constructor(request: Request) {
6768
this.#request = request;
6869
this.#requestValues = null;
6970
this.#outgoing = null;
71+
this.#consumed = false;
7072
}
7173

7274
/**
@@ -148,6 +150,16 @@ class AstroCookies implements AstroCookiesInterface {
148150
* @param options Options for the cookie, such as the path and security settings.
149151
*/
150152
set(key: string, value: string | Record<string, any>, options?: AstroCookieSetOptions): void {
153+
if (this.#consumed) {
154+
const warning = new Error(
155+
'Astro.cookies.set() was called after the cookies had already been sent to the browser.\n' +
156+
'This may have happened if this method was called in an imported component.\n' +
157+
'Please make sure that Astro.cookies.set() is only called in the frontmatter of the main page.'
158+
);
159+
warning.name = "Warning";
160+
// eslint-disable-next-line no-console
161+
console.warn(warning);
162+
}
151163
let serializedValue: string;
152164
if (typeof value === 'string') {
153165
serializedValue = value;
@@ -193,6 +205,15 @@ class AstroCookies implements AstroCookiesInterface {
193205
}
194206
}
195207

208+
/**
209+
* Behaves the same as AstroCookies.prototype.headers(),
210+
* but allows a warning when cookies are set after the instance is consumed.
211+
*/
212+
static consume(cookies: AstroCookies): Generator<string, void, unknown> {
213+
cookies.#consumed = true;
214+
return cookies.headers();
215+
}
216+
196217
#ensureParsed(options: AstroCookieGetOptions | undefined = undefined): Record<string, string> {
197218
if (!this.#requestValues) {
198219
this.#parse(options);

‎packages/astro/src/core/cookies/response.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AstroCookies } from './cookies.js';
1+
import { AstroCookies } from './cookies.js';
22

33
const astroCookiesSymbol = Symbol.for('astro.cookies');
44

@@ -24,7 +24,7 @@ export function* getSetCookiesFromResponse(response: Response): Generator<string
2424
if (!cookies) {
2525
return [];
2626
}
27-
for (const headerValue of cookies.headers()) {
27+
for (const headerValue of AstroCookies.consume(cookies)) {
2828
yield headerValue;
2929
}
3030

0 commit comments

Comments
 (0)
Please sign in to comment.