Repository: withastro/astro
File: packages/astro/src/core/cookies/cookies.ts (TypeScript)

Code before:
		if (key in values) {
			const value = values[key];
			if (value) {
				return new AstroCookie(value);
			}
		}
	}

	/**
	 * Astro.cookies.has(key) returns a boolean indicating whether this cookie is either
	 * part of the initial request or set via Astro.cookies.set(key)
	 * @param key The cookie to check for.
	 * @returns
	 */
	has(key: string, options: AstroCookieGetOptions | undefined = undefined): boolean {
		if (this.#outgoing?.has(key)) {
			let [, , isSetValue] = this.#outgoing.get(key)!;
			return isSetValue;
		}
		const values = this.#ensureParsed(options);
		return !!values[key];
	}

	/**
	 * Astro.cookies.set(key, value) is used to set a cookie's value. If provided
	 * an object it will be stringified via JSON.stringify(value). Additionally you
	 * can provide options customizing how this cookie will be set, such as setting httpOnly
	 * in order to prevent the cookie from being read in client-side JavaScript.
	 * @param key The name of the cookie to set.
	 * @param value A value, either a string or other primitive or an object.
	 * @param options Options for the cookie, such as the path and security settings.
	 */
	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';
			console.warn(warning);
		}
		let serializedValue: string;
		if (typeof value === 'string') {
			serializedValue = value;
		} else {
			// Support stringifying JSON objects for convenience. First check that this is
			// a plain object and if it is, stringify. If not, allow support for toString() overrides.
			let toStringValue = value.toString();
			if (toStringValue === Object.prototype.toString.call(value)) {
				serializedValue = JSON.stringify(value);

Review comment (suggestion):
Previously it would return `false` for `has()` when the cookie had a falsy value, even if it existed

Code after:
		// decodeURIComponent is the default decode function for cookies
		const decode = options?.decode ?? decodeURIComponent

		const values = this.#ensureParsed();
		if (key in values) {
			const value = values[key];
			if (value) {
				return new AstroCookie(decode(value));
			}
		}
	}

	/**
	 * Astro.cookies.has(key) returns a boolean indicating whether this cookie is either
	 * part of the initial request or set via Astro.cookies.set(key)
	 * @param key The cookie to check for.
	 * @param _options This parameter is no longer used.
	 * @returns
	 */
	has(key: string, _options?: AstroCookieGetOptions): boolean {
		if (this.#outgoing?.has(key)) {
			let [, , isSetValue] = this.#outgoing.get(key)!;
			return isSetValue;
		}
		const values = this.#ensureParsed();
		return values[key] !== undefined;
	}

	/**
	 * Astro.cookies.set(key, value) is used to set a cookie's value. If provided
	 * an object it will be stringified via JSON.stringify(value). Additionally you
	 * can provide options customizing how this cookie will be set, such as setting httpOnly
	 * in order to prevent the cookie from being read in client-side JavaScript.
	 * @param key The name of the cookie to set.
	 * @param value A value, either a string or other primitive or an object.
	 * @param options Options for the cookie, such as the path and security settings.
	 */
	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';
			console.warn(warning);
		}
		let serializedValue: string;
		if (typeof value === 'string') {
			serializedValue = value;
		} else {