0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

qol(cookies): warn when cookies are set after the headers have been sent (#9627)

This commit is contained in:
Arsh 2024-01-10 14:51:50 +00:00 committed by GitHub
parent a4f90d95ff
commit a700a20291
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 2 deletions

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
Adds a warning when setting cookies will have no effect

View file

@ -63,10 +63,12 @@ class AstroCookies implements AstroCookiesInterface {
#request: Request; #request: Request;
#requestValues: Record<string, string> | null; #requestValues: Record<string, string> | null;
#outgoing: Map<string, [string, string, boolean]> | null; #outgoing: Map<string, [string, string, boolean]> | null;
#consumed: boolean;
constructor(request: Request) { constructor(request: Request) {
this.#request = request; this.#request = request;
this.#requestValues = null; this.#requestValues = null;
this.#outgoing = 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. * @param options Options for the cookie, such as the path and security settings.
*/ */
set(key: string, value: string | Record<string, any>, options?: AstroCookieSetOptions): void { set(key: string, value: string | Record<string, any>, 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; let serializedValue: string;
if (typeof value === 'string') { if (typeof value === 'string') {
serializedValue = value; 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<string, void, unknown> {
cookies.#consumed = true;
return cookies.headers();
}
#ensureParsed(options: AstroCookieGetOptions | undefined = undefined): Record<string, string> { #ensureParsed(options: AstroCookieGetOptions | undefined = undefined): Record<string, string> {
if (!this.#requestValues) { if (!this.#requestValues) {
this.#parse(options); this.#parse(options);

View file

@ -1,4 +1,4 @@
import type { AstroCookies } from './cookies.js'; import { AstroCookies } from './cookies.js';
const astroCookiesSymbol = Symbol.for('astro.cookies'); const astroCookiesSymbol = Symbol.for('astro.cookies');
@ -24,7 +24,7 @@ export function* getSetCookiesFromResponse(response: Response): Generator<string
if (!cookies) { if (!cookies) {
return []; return [];
} }
for (const headerValue of cookies.headers()) { for (const headerValue of AstroCookies.consume(cookies)) {
yield headerValue; yield headerValue;
} }