{"version":3,"file":"cookies.mjs","names":[],"sources":["../src/cookies.ts"],"sourcesContent":["import { signCookieValue } from \"./crypto\";\nimport { tryDecode } from \"./utils\";\n\nexport type CookiePrefixOptions = \"host\" | \"secure\";\n\nexport type CookieOptions = {\n\t/**\n\t * Domain of the cookie\n\t *\n\t * The Domain attribute specifies which server can receive a cookie. If specified, cookies are\n\t * available on the specified server and its subdomains. If the it is not\n\t * specified, the cookies are available on the server that sets it but not on\n\t * its subdomains.\n\t *\n\t * @example\n\t * `domain: \"example.com\"`\n\t */\n\tdomain?: string;\n\t/**\n\t * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the\n\t * Expires attribute:\n\t *\n\t * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and\n\t * takes precedence when both are set. The rationale behind this is that when you set an\n\t * Expires date and time, they're relative to the client the cookie is being set on. If the\n\t * server is set to a different time, this could cause errors\n\t */\n\texpires?: Date;\n\t/**\n\t * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie\n\t * property. Note that a cookie that has been created with HttpOnly will still be sent with\n\t * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().\n\t * This mitigates attacks against cross-site scripting\n\t */\n\thttpOnly?: boolean;\n\t/**\n\t * Indicates the number of seconds until the cookie expires. A zero or negative number will\n\t * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.\n\t *\n\t * @example 604800 - 7 days\n\t */\n\tmaxAge?: number;\n\t/**\n\t * Indicates the path that must exist in the requested URL for the browser to send the Cookie\n\t * header.\n\t *\n\t * @example\n\t * \"/docs\"\n\t * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.\n\t */\n\tpath?: string;\n\t/**\n\t * Indicates that the cookie is sent to the server only when a request is made with the https:\n\t * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.\n\t */\n\tsecure?: boolean;\n\t/**\n\t * Controls whether or not a cookie is sent with cross-site requests, providing some protection\n\t * against cross-site request forgery attacks (CSRF).\n\t *\n\t * Strict - Means that the browser sends the cookie only for same-site requests, that is,\n\t * requests originating from the same site that set the cookie. If a request originates from a\n\t * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict\n\t * attribute are sent.\n\t *\n\t * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load\n\t * images or frames, but is sent when a user is navigating to the origin site from an external\n\t * site (for example, when following a link). This is the default behavior if the SameSite\n\t * attribute is not specified.\n\t *\n\t * None - Means that the browser sends the cookie with both cross-site and same-site requests.\n\t * The Secure attribute must also be set when setting this value.\n\t */\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\" | \"strict\" | \"lax\" | \"none\";\n\t/**\n\t * Indicates that the cookie should be stored using partitioned storage. Note that if this is\n\t * set, the Secure directive must also be set.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies\n\t */\n\tpartitioned?: boolean;\n\t/**\n\t * Cooke Prefix\n\t *\n\t * - secure: `__Secure-` -> `__Secure-cookie-name`\n\t * - host: `__Host-` -> `__Host-cookie-name`\n\t *\n\t * `secure` must be set to true to use prefixes\n\t */\n\tprefix?: CookiePrefixOptions;\n};\n\nexport const getCookieKey = (key: string, prefix?: CookiePrefixOptions) => {\n\tlet finalKey = key;\n\tif (prefix) {\n\t\tif (prefix === \"secure\") {\n\t\t\tfinalKey = \"__Secure-\" + key;\n\t\t} else if (prefix === \"host\") {\n\t\t\tfinalKey = \"__Host-\" + key;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn finalKey;\n};\n\n/**\n * Parse an HTTP Cookie header string and returning an object of all cookie\n * name-value pairs.\n *\n * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts\n *\n * @param str the string representing a `Cookie` header value\n */\nexport function parseCookies(str: string) {\n\tif (typeof str !== \"string\") {\n\t\tthrow new TypeError(\"argument str must be a string\");\n\t}\n\n\tconst cookies: Map = new Map();\n\n\tlet index = 0;\n\twhile (index < str.length) {\n\t\tconst eqIdx = str.indexOf(\"=\", index);\n\n\t\tif (eqIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet endIdx = str.indexOf(\";\", index);\n\n\t\tif (endIdx === -1) {\n\t\t\tendIdx = str.length;\n\t\t} else if (endIdx < eqIdx) {\n\t\t\tindex = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = str.slice(index, eqIdx).trim();\n\t\tif (!cookies.has(key)) {\n\t\t\tlet val = str.slice(eqIdx + 1, endIdx).trim();\n\t\t\tif (val.codePointAt(0) === 0x22) {\n\t\t\t\tval = val.slice(1, -1);\n\t\t\t}\n\t\t\tcookies.set(key, tryDecode(val));\n\t\t}\n\n\t\tindex = endIdx + 1;\n\t}\n\n\treturn cookies;\n}\n\nconst _serialize = (key: string, value: string, opt: CookieOptions = {}) => {\n\tlet cookie: string;\n\n\tif (opt?.prefix === \"secure\") {\n\t\tcookie = `${`__Secure-${key}`}=${value}`;\n\t} else if (opt?.prefix === \"host\") {\n\t\tcookie = `${`__Host-${key}`}=${value}`;\n\t} else {\n\t\tcookie = `${key}=${value}`;\n\t}\n\n\tif (key.startsWith(\"__Secure-\") && !opt.secure) {\n\t\topt.secure = true;\n\t}\n\n\tif (key.startsWith(\"__Host-\")) {\n\t\tif (!opt.secure) {\n\t\t\topt.secure = true;\n\t\t}\n\n\t\tif (opt.path !== \"/\") {\n\t\t\topt.path = \"/\";\n\t\t}\n\n\t\tif (opt.domain) {\n\t\t\topt.domain = undefined;\n\t\t}\n\t}\n\n\tif (opt && typeof opt.maxAge === \"number\" && opt.maxAge >= 0) {\n\t\tif (opt.maxAge > 34560000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Max-Age=${Math.floor(opt.maxAge)}`;\n\t}\n\n\tif (opt.domain && opt.prefix !== \"host\") {\n\t\tcookie += `; Domain=${opt.domain}`;\n\t}\n\n\tif (opt.path) {\n\t\tcookie += `; Path=${opt.path}`;\n\t}\n\n\tif (opt.expires) {\n\t\tif (opt.expires.getTime() - Date.now() > 34560000_000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Expires=${opt.expires.toUTCString()}`;\n\t}\n\n\tif (opt.httpOnly) {\n\t\tcookie += \"; HttpOnly\";\n\t}\n\n\tif (opt.secure) {\n\t\tcookie += \"; Secure\";\n\t}\n\n\tif (opt.sameSite) {\n\t\tcookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;\n\t}\n\n\tif (opt.partitioned) {\n\t\tif (!opt.secure) {\n\t\t\topt.secure = true;\n\t\t}\n\t\tcookie += \"; Partitioned\";\n\t}\n\n\treturn cookie;\n};\n\nexport const serializeCookie = (\n\tkey: string,\n\tvalue: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = encodeURIComponent(value);\n\treturn _serialize(key, value, opt);\n};\n\nexport const serializeSignedCookie = async (\n\tkey: string,\n\tvalue: string,\n\tsecret: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = await signCookieValue(value, secret);\n\treturn _serialize(key, value, opt);\n};\n"],"mappings":";;;;AA4FA,MAAa,gBAAgB,KAAa,WAAiC;CAC1E,IAAI,WAAW;AACf,KAAI,OACH,KAAI,WAAW,SACd,YAAW,cAAc;UACf,WAAW,OACrB,YAAW,YAAY;KAEvB;AAGF,QAAO;;;;;;;;;;AAWR,SAAgB,aAAa,KAAa;AACzC,KAAI,OAAO,QAAQ,SAClB,OAAM,IAAI,UAAU,gCAAgC;CAGrD,MAAM,0BAA+B,IAAI,KAAK;CAE9C,IAAI,QAAQ;AACZ,QAAO,QAAQ,IAAI,QAAQ;EAC1B,MAAM,QAAQ,IAAI,QAAQ,KAAK,MAAM;AAErC,MAAI,UAAU,GACb;EAGD,IAAI,SAAS,IAAI,QAAQ,KAAK,MAAM;AAEpC,MAAI,WAAW,GACd,UAAS,IAAI;WACH,SAAS,OAAO;AAC1B,WAAQ,IAAI,YAAY,KAAK,QAAQ,EAAE,GAAG;AAC1C;;EAGD,MAAM,MAAM,IAAI,MAAM,OAAO,MAAM,CAAC,MAAM;AAC1C,MAAI,CAAC,QAAQ,IAAI,IAAI,EAAE;GACtB,IAAI,MAAM,IAAI,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM;AAC7C,OAAI,IAAI,YAAY,EAAE,KAAK,GAC1B,OAAM,IAAI,MAAM,GAAG,GAAG;AAEvB,WAAQ,IAAI,KAAK,UAAU,IAAI,CAAC;;AAGjC,UAAQ,SAAS;;AAGlB,QAAO;;AAGR,MAAM,cAAc,KAAa,OAAe,MAAqB,EAAE,KAAK;CAC3E,IAAI;AAEJ,KAAI,KAAK,WAAW,SACnB,UAAS,GAAG,YAAY,MAAM,GAAG;UACvB,KAAK,WAAW,OAC1B,UAAS,GAAG,UAAU,MAAM,GAAG;KAE/B,UAAS,GAAG,IAAI,GAAG;AAGpB,KAAI,IAAI,WAAW,YAAY,IAAI,CAAC,IAAI,OACvC,KAAI,SAAS;AAGd,KAAI,IAAI,WAAW,UAAU,EAAE;AAC9B,MAAI,CAAC,IAAI,OACR,KAAI,SAAS;AAGd,MAAI,IAAI,SAAS,IAChB,KAAI,OAAO;AAGZ,MAAI,IAAI,OACP,KAAI,SAAS;;AAIf,KAAI,OAAO,OAAO,IAAI,WAAW,YAAY,IAAI,UAAU,GAAG;AAC7D,MAAI,IAAI,SAAS,OAChB,OAAM,IAAI,MACT,sFACA;AAEF,YAAU,aAAa,KAAK,MAAM,IAAI,OAAO;;AAG9C,KAAI,IAAI,UAAU,IAAI,WAAW,OAChC,WAAU,YAAY,IAAI;AAG3B,KAAI,IAAI,KACP,WAAU,UAAU,IAAI;AAGzB,KAAI,IAAI,SAAS;AAChB,MAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,KAAK,GAAG,OACxC,OAAM,IAAI,MACT,wFACA;AAEF,YAAU,aAAa,IAAI,QAAQ,aAAa;;AAGjD,KAAI,IAAI,SACP,WAAU;AAGX,KAAI,IAAI,OACP,WAAU;AAGX,KAAI,IAAI,SACP,WAAU,cAAc,IAAI,SAAS,OAAO,EAAE,CAAC,aAAa,GAAG,IAAI,SAAS,MAAM,EAAE;AAGrF,KAAI,IAAI,aAAa;AACpB,MAAI,CAAC,IAAI,OACR,KAAI,SAAS;AAEd,YAAU;;AAGX,QAAO;;AAGR,MAAa,mBACZ,KACA,OACA,QACI;AACJ,SAAQ,mBAAmB,MAAM;AACjC,QAAO,WAAW,KAAK,OAAO,IAAI;;AAGnC,MAAa,wBAAwB,OACpC,KACA,OACA,QACA,QACI;AACJ,SAAQ,MAAM,gBAAgB,OAAO,OAAO;AAC5C,QAAO,WAAW,KAAK,OAAO,IAAI"}