import type { CookieParseOptions , CookieSerializeOptions } from "cookie" ; import { parse , serialize } from "cookie" ; import "./cookieSigning" ; export type { CookieParseOptions , CookieSerializeOptions } ; export interface CookieSignatureOptions { /**
     * An array of secrets that may be used to sign/unsign the value of a cookie.
     *
     * The array makes it easy to rotate secrets. New secrets should be added to
     * the beginning of the array. `cookie.serialize()` will always use the first
     * value in the array, but `cookie.parse()` may use any of them so that
     * cookies that were signed with older secrets still work.
     */ secrets ? : string [ ] ; } export type CookieOptions = CookieParseOptions & CookieSerializeOptions & CookieSignatureOptions ; /**
 * A HTTP cookie.
 *
 * A Cookie is a logical container for metadata about a HTTP cookie; its name
 * and options. But it doesn't contain a value. Instead, it has `parse()` and
 * `serialize()` methods that allow a single instance to be reused for
 * parsing/encoding multiple different values.
 */ export interface Cookie { /**
     * The name of the cookie, used in the `Cookie` and `Set-Cookie` headers.
     */ readonly name : string ; /**
     * True if this cookie uses one or more secrets for verification.
     */ readonly isSigned : boolean ; /**
     * The Date this cookie expires.
     *
     * Note: This is calculated at access time using `maxAge` when no `expires`
     * option is provided to `createCookie()`.
     */ readonly expires ? : Date ; /**
     * Parses a raw `Cookie` header and returns the value of this cookie or
     * `null` if it's not present.
     */ parse ( cookieHeader , options ? ) : Promise < any > ; /**
     * Serializes the given value to a string and returns the `Set-Cookie`
     * header.
     */ serialize ( value , options ? ) : Promise < string > ; } /**
 * Creates and returns a new Cookie.
 */ export function createCookie ( name , { secrets = [ ] , ... options } = { } ) { return { get name ( ) { return name ; } , get isSigned ( ) { return secrets . length > 0 ; } , get expires ( ) { return typeof options . maxAge !== "undefined" ? new Date ( Date . now ( ) + options . maxAge * 1000 ) : options . expires ; } , async parse ( cookieHeader , parseOptions ) { if ( ! cookieHeader ) return null ; let cookies = parse ( cookieHeader , { ... options , ... parseOptions } ) ; return name in cookies ? cookies [ name ] === "" ? "" : await decodeCookieValue ( cookies [ name ] , secrets ) : null ; } , async serialize ( value , serializeOptions ) { return serialize ( name , value === "" ? "" : await encodeCookieValue ( value , secrets ) , { ... options , ... serializeOptions } ) ; } } ; } export function isCookie ( object ) { return ( object != null && typeof object . name === "string" && typeof object . isSigned === "boolean" && typeof object . parse === "function" && typeof object . serialize === "function" ) ; } async function encodeCookieValue ( value , secrets ) { let encoded = encodeData ( value ) ; if ( secrets . length > 0 ) { encoded = await sign ( encoded , secrets [ 0 ] ) ; } return encoded ; } async function decodeCookieValue ( value , secrets ) { if ( secrets . length > 0 ) { for ( let secret of secrets ) { let unsignedValue = await unsign ( value , secret ) ; if ( unsignedValue !== false ) { return decodeData ( unsignedValue ) ; } } return null ; } return decodeData ( value ) ; } function encodeData ( value ) { return btoa ( JSON . stringify ( value ) ) ; } function decodeData ( value ) { try { return JSON . parse ( atob ( value ) ) ; } catch ( error ) { return { } ; } }