@remix-run/cookie 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/cookie-signing.js +1 -1
- package/dist/lib/cookie.d.ts +68 -46
- package/dist/lib/cookie.d.ts.map +1 -1
- package/dist/lib/cookie.js +179 -68
- package/package.json +8 -7
- package/src/index.ts +1 -1
- package/src/lib/cookie-signing.ts +1 -1
- package/src/lib/cookie.ts +177 -132
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ let sessionCookie = createCookie('session', {
|
|
|
57
57
|
secrets: ['secret1'],
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
console.log(sessionCookie.
|
|
60
|
+
console.log(sessionCookie.signed) // true
|
|
61
61
|
|
|
62
62
|
let response = new Response('Hello, world!', {
|
|
63
63
|
headers: {
|
|
@@ -86,7 +86,7 @@ let response = new Response('Hello, world!', {
|
|
|
86
86
|
|
|
87
87
|
### Custom Encoding
|
|
88
88
|
|
|
89
|
-
By default,
|
|
89
|
+
By default, [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) and [`decodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) are used to encode and decode the cookie value. This is suitable for most use cases, but you can provide your own functions to customize the encoding and decoding of the cookie value.
|
|
90
90
|
|
|
91
91
|
```tsx
|
|
92
92
|
let sessionCookie = createCookie('session', {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type
|
|
1
|
+
export { type CookieOptions, Cookie, createCookie } from './lib/cookie.ts';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createCookie } from "./lib/cookie.js";
|
|
1
|
+
export { Cookie, createCookie } from "./lib/cookie.js";
|
|
@@ -27,7 +27,7 @@ export async function unsign(cookie, secret) {
|
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
function createKey(secret, usages) {
|
|
31
31
|
return crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, usages);
|
|
32
32
|
}
|
|
33
33
|
function byteStringToArray(byteString) {
|
package/dist/lib/cookie.d.ts
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import { type CookieProperties } from '@remix-run/headers';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a cookie.
|
|
4
|
+
*/
|
|
5
|
+
export interface CookieOptions extends CookieProperties {
|
|
6
|
+
/**
|
|
7
|
+
* A function that decodes the cookie value. Decodes any URL-encoded sequences into their
|
|
8
|
+
* original characters.
|
|
9
|
+
*
|
|
10
|
+
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
11
|
+
*
|
|
12
|
+
* @default decodeURIComponent
|
|
13
|
+
*/
|
|
14
|
+
decode?: (value: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* A function that encodes the cookie value. Percent-encodes all characters that are not allowed
|
|
17
|
+
* in a cookie value.
|
|
18
|
+
*
|
|
19
|
+
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
20
|
+
*
|
|
21
|
+
* @default encodeURIComponent
|
|
22
|
+
*/
|
|
23
|
+
encode?: (value: string) => string;
|
|
24
|
+
/**
|
|
25
|
+
* An array of secrets that may be used to sign/unsign the value of a cookie.
|
|
26
|
+
*
|
|
27
|
+
* The array makes it easy to rotate secrets. New secrets should be added to
|
|
28
|
+
* the beginning of the array. `cookie.serialize()` will always use the first
|
|
29
|
+
* value in the array, but `cookie.parse()` may use any of them so that
|
|
30
|
+
* cookies that were signed with older secrets still work.
|
|
31
|
+
*/
|
|
32
|
+
secrets?: string[];
|
|
33
|
+
}
|
|
2
34
|
type SameSiteValue = 'Strict' | 'Lax' | 'None';
|
|
3
35
|
/**
|
|
4
36
|
* Represents a HTTP cookie.
|
|
@@ -8,39 +40,48 @@ type SameSiteValue = 'Strict' | 'Lax' | 'None';
|
|
|
8
40
|
* Also supports cryptographic signing of the cookie value to ensure it's not tampered with, and
|
|
9
41
|
* secret rotation to easily rotate secrets without breaking existing cookies.
|
|
10
42
|
*/
|
|
11
|
-
export
|
|
43
|
+
export declare class Cookie implements CookieProperties {
|
|
44
|
+
#private;
|
|
45
|
+
/**
|
|
46
|
+
* @param name The name of the cookie
|
|
47
|
+
* @param options Options for the cookie
|
|
48
|
+
*/
|
|
49
|
+
constructor(name: string, options?: CookieOptions);
|
|
12
50
|
/**
|
|
13
51
|
* The domain of the cookie.
|
|
14
52
|
*
|
|
15
53
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#domaindomain-value)
|
|
16
54
|
*/
|
|
17
|
-
|
|
55
|
+
get domain(): string | undefined;
|
|
18
56
|
/**
|
|
19
57
|
* The expiration date of the cookie.
|
|
20
58
|
*
|
|
21
59
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#expiresdate)
|
|
22
60
|
*/
|
|
23
|
-
|
|
61
|
+
get expires(): Date | undefined;
|
|
24
62
|
/**
|
|
25
63
|
* True if the cookie is HTTP-only.
|
|
26
64
|
*
|
|
27
65
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#httponly)
|
|
66
|
+
*
|
|
67
|
+
* @default false
|
|
28
68
|
*/
|
|
29
|
-
|
|
69
|
+
get httpOnly(): boolean;
|
|
30
70
|
/**
|
|
31
71
|
* The maximum age of the cookie in seconds.
|
|
32
72
|
*
|
|
33
73
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#max-agenumber)
|
|
34
74
|
*/
|
|
35
|
-
|
|
75
|
+
get maxAge(): number | undefined;
|
|
36
76
|
/**
|
|
37
77
|
* The name of the cookie.
|
|
38
78
|
*
|
|
39
79
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#cookie-namecookie-value)
|
|
40
80
|
*/
|
|
41
|
-
|
|
81
|
+
get name(): string;
|
|
42
82
|
/**
|
|
43
83
|
* Extracts the value of this cookie from a `Cookie` header value.
|
|
84
|
+
*
|
|
44
85
|
* @param headerValue The `Cookie` header to parse
|
|
45
86
|
* @returns The value of this cookie, or `null` if it's not present
|
|
46
87
|
*/
|
|
@@ -49,72 +90,53 @@ export interface Cookie {
|
|
|
49
90
|
* True if the cookie is partitioned.
|
|
50
91
|
*
|
|
51
92
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#partitioned)
|
|
93
|
+
*
|
|
94
|
+
* @default false
|
|
52
95
|
*/
|
|
53
|
-
|
|
96
|
+
get partitioned(): boolean;
|
|
54
97
|
/**
|
|
55
|
-
* The path of the cookie.
|
|
98
|
+
* The path of the cookie.
|
|
56
99
|
*
|
|
57
100
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)
|
|
101
|
+
*
|
|
102
|
+
* @default '/'
|
|
58
103
|
*/
|
|
59
|
-
|
|
104
|
+
get path(): string;
|
|
60
105
|
/**
|
|
61
|
-
* The `SameSite` attribute of the cookie.
|
|
106
|
+
* The `SameSite` attribute of the cookie.
|
|
62
107
|
*
|
|
63
108
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)
|
|
109
|
+
*
|
|
110
|
+
* @default 'Lax'
|
|
64
111
|
*/
|
|
65
|
-
|
|
112
|
+
get sameSite(): SameSiteValue;
|
|
66
113
|
/**
|
|
67
114
|
* True if the cookie is secure (only sent over HTTPS).
|
|
68
115
|
*
|
|
69
116
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)
|
|
117
|
+
*
|
|
118
|
+
* @default false
|
|
70
119
|
*/
|
|
71
|
-
|
|
120
|
+
get secure(): boolean;
|
|
72
121
|
/**
|
|
73
122
|
* Returns the value to use in a `Set-Cookie` header for this cookie.
|
|
123
|
+
*
|
|
74
124
|
* @param value The value to serialize
|
|
75
|
-
* @param props
|
|
76
|
-
* @returns The `Set-Cookie` header for this cookie
|
|
125
|
+
* @param props Additional properties to use when serializing the cookie
|
|
126
|
+
* @returns The `Set-Cookie` header value for this cookie
|
|
77
127
|
*/
|
|
78
128
|
serialize(value: string, props?: CookieProperties): Promise<string>;
|
|
79
129
|
/**
|
|
80
130
|
* True if this cookie uses one or more secrets for verification.
|
|
81
131
|
*/
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
export interface CookieOptions extends CookieProperties {
|
|
85
|
-
/**
|
|
86
|
-
* A function that decodes the cookie value.
|
|
87
|
-
*
|
|
88
|
-
* Defaults to `decodeURIComponent`, which decodes any URL-encoded sequences into their original
|
|
89
|
-
* characters.
|
|
90
|
-
*
|
|
91
|
-
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
92
|
-
*/
|
|
93
|
-
decode?: (value: string) => string;
|
|
94
|
-
/**
|
|
95
|
-
* A function that encodes the cookie value.
|
|
96
|
-
*
|
|
97
|
-
* Defaults to `encodeURIComponent`, which percent-encodes all characters that are not allowed
|
|
98
|
-
* in a cookie value.
|
|
99
|
-
*
|
|
100
|
-
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
101
|
-
*/
|
|
102
|
-
encode?: (value: string) => string;
|
|
103
|
-
/**
|
|
104
|
-
* An array of secrets that may be used to sign/unsign the value of a cookie.
|
|
105
|
-
*
|
|
106
|
-
* The array makes it easy to rotate secrets. New secrets should be added to
|
|
107
|
-
* the beginning of the array. `cookie.serialize()` will always use the first
|
|
108
|
-
* value in the array, but `cookie.parse()` may use any of them so that
|
|
109
|
-
* cookies that were signed with older secrets still work.
|
|
110
|
-
*/
|
|
111
|
-
secrets?: string[];
|
|
132
|
+
get signed(): boolean;
|
|
112
133
|
}
|
|
113
134
|
/**
|
|
114
135
|
* Creates a new cookie object.
|
|
136
|
+
*
|
|
115
137
|
* @param name The name of the cookie
|
|
116
|
-
* @param options
|
|
117
|
-
* @returns A
|
|
138
|
+
* @param options Options for the cookie
|
|
139
|
+
* @returns A new `Cookie` object
|
|
118
140
|
*/
|
|
119
141
|
export declare function createCookie(name: string, options?: CookieOptions): Cookie;
|
|
120
142
|
export {};
|
package/dist/lib/cookie.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../../src/lib/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAA;AAI3B,KAAK,aAAa,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../../src/lib/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAA;AAI3B;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,gBAAgB;IACrD;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,KAAK,aAAa,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;AAG9C;;;;;;;GAOG;AACH,qBAAa,MAAO,YAAW,gBAAgB;;IAc7C;;;OAGG;IACH,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,EAiChD;IAED;;;;OAIG;IACH,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED;;;;OAIG;IACH,IAAI,OAAO,IAAI,IAAI,GAAG,SAAS,CAE9B;IAED;;;;;;OAMG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACH,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;OAKG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW9D;IAED;;;;;;OAMG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;;;OAMG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;OAMG;IACH,IAAI,QAAQ,IAAI,aAAa,CAE5B;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;;;;;OAMG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBxE;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;CACF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAE1E"}
|
package/dist/lib/cookie.js
CHANGED
|
@@ -1,78 +1,189 @@
|
|
|
1
1
|
import { Cookie as CookieHeader, SetCookie as SetCookieHeader, } from '@remix-run/headers';
|
|
2
2
|
import { sign, unsign } from "./cookie-signing.js";
|
|
3
|
+
/**
|
|
4
|
+
* Represents a HTTP cookie.
|
|
5
|
+
*
|
|
6
|
+
* Supports parsing and serializing the cookie to/from `Cookie` and `Set-Cookie` headers.
|
|
7
|
+
*
|
|
8
|
+
* Also supports cryptographic signing of the cookie value to ensure it's not tampered with, and
|
|
9
|
+
* secret rotation to easily rotate secrets without breaking existing cookies.
|
|
10
|
+
*/
|
|
11
|
+
export class Cookie {
|
|
12
|
+
#name;
|
|
13
|
+
#decode;
|
|
14
|
+
#encode;
|
|
15
|
+
#secrets;
|
|
16
|
+
#domain;
|
|
17
|
+
#expires;
|
|
18
|
+
#httpOnly;
|
|
19
|
+
#maxAge;
|
|
20
|
+
#partitioned;
|
|
21
|
+
#path;
|
|
22
|
+
#sameSite;
|
|
23
|
+
#secure;
|
|
24
|
+
/**
|
|
25
|
+
* @param name The name of the cookie
|
|
26
|
+
* @param options Options for the cookie
|
|
27
|
+
*/
|
|
28
|
+
constructor(name, options) {
|
|
29
|
+
let { decode = decodeURIComponent, encode = encodeURIComponent, secrets = [], domain, expires, httpOnly, maxAge, path = '/', partitioned, secure, sameSite = 'Lax', } = options ?? {};
|
|
30
|
+
if (partitioned === true) {
|
|
31
|
+
// Partitioned cookies must be set with Secure
|
|
32
|
+
// See https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies
|
|
33
|
+
secure = true;
|
|
34
|
+
}
|
|
35
|
+
this.#name = name;
|
|
36
|
+
this.#decode = decode;
|
|
37
|
+
this.#encode = encode;
|
|
38
|
+
this.#secrets = secrets;
|
|
39
|
+
this.#domain = domain;
|
|
40
|
+
this.#expires = expires;
|
|
41
|
+
this.#httpOnly = httpOnly;
|
|
42
|
+
this.#maxAge = maxAge;
|
|
43
|
+
this.#partitioned = partitioned;
|
|
44
|
+
this.#path = path;
|
|
45
|
+
this.#sameSite = sameSite;
|
|
46
|
+
this.#secure = secure;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The domain of the cookie.
|
|
50
|
+
*
|
|
51
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#domaindomain-value)
|
|
52
|
+
*/
|
|
53
|
+
get domain() {
|
|
54
|
+
return this.#domain;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The expiration date of the cookie.
|
|
58
|
+
*
|
|
59
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#expiresdate)
|
|
60
|
+
*/
|
|
61
|
+
get expires() {
|
|
62
|
+
return this.#expires;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* True if the cookie is HTTP-only.
|
|
66
|
+
*
|
|
67
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#httponly)
|
|
68
|
+
*
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
get httpOnly() {
|
|
72
|
+
return this.#httpOnly ?? false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The maximum age of the cookie in seconds.
|
|
76
|
+
*
|
|
77
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#max-agenumber)
|
|
78
|
+
*/
|
|
79
|
+
get maxAge() {
|
|
80
|
+
return this.#maxAge;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The name of the cookie.
|
|
84
|
+
*
|
|
85
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#cookie-namecookie-value)
|
|
86
|
+
*/
|
|
87
|
+
get name() {
|
|
88
|
+
return this.#name;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Extracts the value of this cookie from a `Cookie` header value.
|
|
92
|
+
*
|
|
93
|
+
* @param headerValue The `Cookie` header to parse
|
|
94
|
+
* @returns The value of this cookie, or `null` if it's not present
|
|
95
|
+
*/
|
|
96
|
+
async parse(headerValue) {
|
|
97
|
+
if (!headerValue)
|
|
98
|
+
return null;
|
|
99
|
+
let header = new CookieHeader(headerValue);
|
|
100
|
+
if (!header.has(this.#name))
|
|
101
|
+
return null;
|
|
102
|
+
let value = header.get(this.#name);
|
|
103
|
+
if (value === '')
|
|
104
|
+
return '';
|
|
105
|
+
let decoded = await decodeCookieValue(value, this.#secrets, this.#decode);
|
|
106
|
+
return decoded;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* True if the cookie is partitioned.
|
|
110
|
+
*
|
|
111
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#partitioned)
|
|
112
|
+
*
|
|
113
|
+
* @default false
|
|
114
|
+
*/
|
|
115
|
+
get partitioned() {
|
|
116
|
+
return this.#partitioned ?? false;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The path of the cookie.
|
|
120
|
+
*
|
|
121
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)
|
|
122
|
+
*
|
|
123
|
+
* @default '/'
|
|
124
|
+
*/
|
|
125
|
+
get path() {
|
|
126
|
+
return this.#path;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The `SameSite` attribute of the cookie.
|
|
130
|
+
*
|
|
131
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)
|
|
132
|
+
*
|
|
133
|
+
* @default 'Lax'
|
|
134
|
+
*/
|
|
135
|
+
get sameSite() {
|
|
136
|
+
return this.#sameSite;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* True if the cookie is secure (only sent over HTTPS).
|
|
140
|
+
*
|
|
141
|
+
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)
|
|
142
|
+
*
|
|
143
|
+
* @default false
|
|
144
|
+
*/
|
|
145
|
+
get secure() {
|
|
146
|
+
return this.#secure ?? false;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Returns the value to use in a `Set-Cookie` header for this cookie.
|
|
150
|
+
*
|
|
151
|
+
* @param value The value to serialize
|
|
152
|
+
* @param props Additional properties to use when serializing the cookie
|
|
153
|
+
* @returns The `Set-Cookie` header value for this cookie
|
|
154
|
+
*/
|
|
155
|
+
async serialize(value, props) {
|
|
156
|
+
let header = new SetCookieHeader({
|
|
157
|
+
name: this.#name,
|
|
158
|
+
value: value === '' ? '' : await encodeCookieValue(value, this.#secrets, this.#encode),
|
|
159
|
+
domain: this.#domain,
|
|
160
|
+
expires: this.#expires,
|
|
161
|
+
httpOnly: this.#httpOnly,
|
|
162
|
+
maxAge: this.#maxAge,
|
|
163
|
+
partitioned: this.#partitioned,
|
|
164
|
+
path: this.#path,
|
|
165
|
+
sameSite: this.#sameSite,
|
|
166
|
+
secure: this.#secure,
|
|
167
|
+
...props,
|
|
168
|
+
});
|
|
169
|
+
return header.toString();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* True if this cookie uses one or more secrets for verification.
|
|
173
|
+
*/
|
|
174
|
+
get signed() {
|
|
175
|
+
return this.#secrets.length > 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
3
178
|
/**
|
|
4
179
|
* Creates a new cookie object.
|
|
180
|
+
*
|
|
5
181
|
* @param name The name of the cookie
|
|
6
|
-
* @param options
|
|
7
|
-
* @returns A
|
|
182
|
+
* @param options Options for the cookie
|
|
183
|
+
* @returns A new `Cookie` object
|
|
8
184
|
*/
|
|
9
185
|
export function createCookie(name, options) {
|
|
10
|
-
|
|
11
|
-
if (partitioned === true) {
|
|
12
|
-
// Partitioned cookies must be set with Secure
|
|
13
|
-
// See https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies
|
|
14
|
-
secure = true;
|
|
15
|
-
}
|
|
16
|
-
return {
|
|
17
|
-
get domain() {
|
|
18
|
-
return domain;
|
|
19
|
-
},
|
|
20
|
-
get expires() {
|
|
21
|
-
return expires;
|
|
22
|
-
},
|
|
23
|
-
get httpOnly() {
|
|
24
|
-
return httpOnly ?? false;
|
|
25
|
-
},
|
|
26
|
-
get maxAge() {
|
|
27
|
-
return maxAge;
|
|
28
|
-
},
|
|
29
|
-
get name() {
|
|
30
|
-
return name;
|
|
31
|
-
},
|
|
32
|
-
async parse(headerValue) {
|
|
33
|
-
if (!headerValue)
|
|
34
|
-
return null;
|
|
35
|
-
let header = new CookieHeader(headerValue);
|
|
36
|
-
if (!header.has(name))
|
|
37
|
-
return null;
|
|
38
|
-
let value = header.get(name);
|
|
39
|
-
if (value === '')
|
|
40
|
-
return '';
|
|
41
|
-
let decoded = await decodeCookieValue(value, secrets, decode);
|
|
42
|
-
return decoded;
|
|
43
|
-
},
|
|
44
|
-
get partitioned() {
|
|
45
|
-
return partitioned ?? false;
|
|
46
|
-
},
|
|
47
|
-
get path() {
|
|
48
|
-
return path;
|
|
49
|
-
},
|
|
50
|
-
get sameSite() {
|
|
51
|
-
return sameSite;
|
|
52
|
-
},
|
|
53
|
-
get secure() {
|
|
54
|
-
return secure ?? false;
|
|
55
|
-
},
|
|
56
|
-
async serialize(value, props) {
|
|
57
|
-
let header = new SetCookieHeader({
|
|
58
|
-
name: name,
|
|
59
|
-
value: value === '' ? '' : await encodeCookieValue(value, secrets, encode),
|
|
60
|
-
domain,
|
|
61
|
-
expires,
|
|
62
|
-
httpOnly,
|
|
63
|
-
maxAge,
|
|
64
|
-
partitioned,
|
|
65
|
-
path,
|
|
66
|
-
sameSite,
|
|
67
|
-
secure,
|
|
68
|
-
...props,
|
|
69
|
-
});
|
|
70
|
-
return header.toString();
|
|
71
|
-
},
|
|
72
|
-
get signed() {
|
|
73
|
-
return secrets.length > 0;
|
|
74
|
-
},
|
|
75
|
-
};
|
|
186
|
+
return new Cookie(name, options);
|
|
76
187
|
}
|
|
77
188
|
async function decodeCookieValue(value, secrets, decode) {
|
|
78
189
|
if (secrets.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/cookie",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "A toolkit for working with cookies in JavaScript",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,10 +26,11 @@
|
|
|
26
26
|
"./package.json": "./package.json"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^24.6.0"
|
|
29
|
+
"@types/node": "^24.6.0",
|
|
30
|
+
"@typescript/native-preview": "7.0.0-dev.20251125.1"
|
|
30
31
|
},
|
|
31
|
-
"
|
|
32
|
-
"@remix-run/headers": "^0.
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@remix-run/headers": "^0.19.0"
|
|
33
34
|
},
|
|
34
35
|
"keywords": [
|
|
35
36
|
"http",
|
|
@@ -39,9 +40,9 @@
|
|
|
39
40
|
"set-cookie"
|
|
40
41
|
],
|
|
41
42
|
"scripts": {
|
|
42
|
-
"build": "
|
|
43
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
43
44
|
"clean": "git clean -fdX",
|
|
44
|
-
"test": "node --disable-warning=ExperimentalWarning --test
|
|
45
|
-
"typecheck": "
|
|
45
|
+
"test": "node --disable-warning=ExperimentalWarning --test",
|
|
46
|
+
"typecheck": "tsgo --noEmit"
|
|
46
47
|
}
|
|
47
48
|
}
|
package/src/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { type
|
|
1
|
+
export { type CookieOptions, Cookie, createCookie } from './lib/cookie.ts'
|
|
@@ -34,7 +34,7 @@ export async function unsign(cookie: string, secret: string): Promise<string | f
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
function createKey(secret: string, usages: CryptoKey['usages']): Promise<CryptoKey> {
|
|
38
38
|
return crypto.subtle.importKey(
|
|
39
39
|
'raw',
|
|
40
40
|
encoder.encode(secret),
|
package/src/lib/cookie.ts
CHANGED
|
@@ -6,7 +6,41 @@ import {
|
|
|
6
6
|
|
|
7
7
|
import { sign, unsign } from './cookie-signing.ts'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Options for creating a cookie.
|
|
11
|
+
*/
|
|
12
|
+
export interface CookieOptions extends CookieProperties {
|
|
13
|
+
/**
|
|
14
|
+
* A function that decodes the cookie value. Decodes any URL-encoded sequences into their
|
|
15
|
+
* original characters.
|
|
16
|
+
*
|
|
17
|
+
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
18
|
+
*
|
|
19
|
+
* @default decodeURIComponent
|
|
20
|
+
*/
|
|
21
|
+
decode?: (value: string) => string
|
|
22
|
+
/**
|
|
23
|
+
* A function that encodes the cookie value. Percent-encodes all characters that are not allowed
|
|
24
|
+
* in a cookie value.
|
|
25
|
+
*
|
|
26
|
+
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
27
|
+
*
|
|
28
|
+
* @default encodeURIComponent
|
|
29
|
+
*/
|
|
30
|
+
encode?: (value: string) => string
|
|
31
|
+
/**
|
|
32
|
+
* An array of secrets that may be used to sign/unsign the value of a cookie.
|
|
33
|
+
*
|
|
34
|
+
* The array makes it easy to rotate secrets. New secrets should be added to
|
|
35
|
+
* the beginning of the array. `cookie.serialize()` will always use the first
|
|
36
|
+
* value in the array, but `cookie.parse()` may use any of them so that
|
|
37
|
+
* cookies that were signed with older secrets still work.
|
|
38
|
+
*/
|
|
39
|
+
secrets?: string[]
|
|
40
|
+
}
|
|
41
|
+
|
|
9
42
|
type SameSiteValue = 'Strict' | 'Lax' | 'None'
|
|
43
|
+
type Coder = (value: string) => string
|
|
10
44
|
|
|
11
45
|
/**
|
|
12
46
|
* Represents a HTTP cookie.
|
|
@@ -16,202 +50,213 @@ type SameSiteValue = 'Strict' | 'Lax' | 'None'
|
|
|
16
50
|
* Also supports cryptographic signing of the cookie value to ensure it's not tampered with, and
|
|
17
51
|
* secret rotation to easily rotate secrets without breaking existing cookies.
|
|
18
52
|
*/
|
|
19
|
-
export
|
|
53
|
+
export class Cookie implements CookieProperties {
|
|
54
|
+
#name: string
|
|
55
|
+
#decode: Coder
|
|
56
|
+
#encode: Coder
|
|
57
|
+
#secrets: string[]
|
|
58
|
+
#domain: string | undefined
|
|
59
|
+
#expires: Date | undefined
|
|
60
|
+
#httpOnly: boolean | undefined
|
|
61
|
+
#maxAge: number | undefined
|
|
62
|
+
#partitioned: boolean | undefined
|
|
63
|
+
#path: string
|
|
64
|
+
#sameSite: SameSiteValue
|
|
65
|
+
#secure: boolean | undefined
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param name The name of the cookie
|
|
69
|
+
* @param options Options for the cookie
|
|
70
|
+
*/
|
|
71
|
+
constructor(name: string, options?: CookieOptions) {
|
|
72
|
+
let {
|
|
73
|
+
decode = decodeURIComponent,
|
|
74
|
+
encode = encodeURIComponent,
|
|
75
|
+
secrets = [],
|
|
76
|
+
domain,
|
|
77
|
+
expires,
|
|
78
|
+
httpOnly,
|
|
79
|
+
maxAge,
|
|
80
|
+
path = '/',
|
|
81
|
+
partitioned,
|
|
82
|
+
secure,
|
|
83
|
+
sameSite = 'Lax',
|
|
84
|
+
} = options ?? {}
|
|
85
|
+
|
|
86
|
+
if (partitioned === true) {
|
|
87
|
+
// Partitioned cookies must be set with Secure
|
|
88
|
+
// See https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies
|
|
89
|
+
secure = true
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.#name = name
|
|
93
|
+
this.#decode = decode
|
|
94
|
+
this.#encode = encode
|
|
95
|
+
this.#secrets = secrets
|
|
96
|
+
this.#domain = domain
|
|
97
|
+
this.#expires = expires
|
|
98
|
+
this.#httpOnly = httpOnly
|
|
99
|
+
this.#maxAge = maxAge
|
|
100
|
+
this.#partitioned = partitioned
|
|
101
|
+
this.#path = path
|
|
102
|
+
this.#sameSite = sameSite
|
|
103
|
+
this.#secure = secure
|
|
104
|
+
}
|
|
105
|
+
|
|
20
106
|
/**
|
|
21
107
|
* The domain of the cookie.
|
|
22
108
|
*
|
|
23
109
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#domaindomain-value)
|
|
24
110
|
*/
|
|
25
|
-
|
|
111
|
+
get domain(): string | undefined {
|
|
112
|
+
return this.#domain
|
|
113
|
+
}
|
|
114
|
+
|
|
26
115
|
/**
|
|
27
116
|
* The expiration date of the cookie.
|
|
28
117
|
*
|
|
29
118
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#expiresdate)
|
|
30
119
|
*/
|
|
31
|
-
|
|
120
|
+
get expires(): Date | undefined {
|
|
121
|
+
return this.#expires
|
|
122
|
+
}
|
|
123
|
+
|
|
32
124
|
/**
|
|
33
125
|
* True if the cookie is HTTP-only.
|
|
34
126
|
*
|
|
35
127
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#httponly)
|
|
128
|
+
*
|
|
129
|
+
* @default false
|
|
36
130
|
*/
|
|
37
|
-
|
|
131
|
+
get httpOnly(): boolean {
|
|
132
|
+
return this.#httpOnly ?? false
|
|
133
|
+
}
|
|
134
|
+
|
|
38
135
|
/**
|
|
39
136
|
* The maximum age of the cookie in seconds.
|
|
40
137
|
*
|
|
41
138
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#max-agenumber)
|
|
42
139
|
*/
|
|
43
|
-
|
|
140
|
+
get maxAge(): number | undefined {
|
|
141
|
+
return this.#maxAge
|
|
142
|
+
}
|
|
143
|
+
|
|
44
144
|
/**
|
|
45
145
|
* The name of the cookie.
|
|
46
146
|
*
|
|
47
147
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#cookie-namecookie-value)
|
|
48
148
|
*/
|
|
49
|
-
|
|
149
|
+
get name(): string {
|
|
150
|
+
return this.#name
|
|
151
|
+
}
|
|
152
|
+
|
|
50
153
|
/**
|
|
51
154
|
* Extracts the value of this cookie from a `Cookie` header value.
|
|
155
|
+
*
|
|
52
156
|
* @param headerValue The `Cookie` header to parse
|
|
53
157
|
* @returns The value of this cookie, or `null` if it's not present
|
|
54
158
|
*/
|
|
55
|
-
parse(headerValue: string | null): Promise<string | null>
|
|
159
|
+
async parse(headerValue: string | null): Promise<string | null> {
|
|
160
|
+
if (!headerValue) return null
|
|
161
|
+
|
|
162
|
+
let header = new CookieHeader(headerValue)
|
|
163
|
+
if (!header.has(this.#name)) return null
|
|
164
|
+
|
|
165
|
+
let value = header.get(this.#name)!
|
|
166
|
+
if (value === '') return ''
|
|
167
|
+
|
|
168
|
+
let decoded = await decodeCookieValue(value, this.#secrets, this.#decode)
|
|
169
|
+
return decoded
|
|
170
|
+
}
|
|
171
|
+
|
|
56
172
|
/**
|
|
57
173
|
* True if the cookie is partitioned.
|
|
58
174
|
*
|
|
59
175
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#partitioned)
|
|
176
|
+
*
|
|
177
|
+
* @default false
|
|
60
178
|
*/
|
|
61
|
-
|
|
179
|
+
get partitioned(): boolean {
|
|
180
|
+
return this.#partitioned ?? false
|
|
181
|
+
}
|
|
182
|
+
|
|
62
183
|
/**
|
|
63
|
-
* The path of the cookie.
|
|
184
|
+
* The path of the cookie.
|
|
64
185
|
*
|
|
65
186
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)
|
|
187
|
+
*
|
|
188
|
+
* @default '/'
|
|
66
189
|
*/
|
|
67
|
-
|
|
190
|
+
get path(): string {
|
|
191
|
+
return this.#path
|
|
192
|
+
}
|
|
193
|
+
|
|
68
194
|
/**
|
|
69
|
-
* The `SameSite` attribute of the cookie.
|
|
195
|
+
* The `SameSite` attribute of the cookie.
|
|
70
196
|
*
|
|
71
197
|
* [MDN Reference](https://developer.mozilla.org/en-US/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)
|
|
198
|
+
*
|
|
199
|
+
* @default 'Lax'
|
|
72
200
|
*/
|
|
73
|
-
|
|
201
|
+
get sameSite(): SameSiteValue {
|
|
202
|
+
return this.#sameSite
|
|
203
|
+
}
|
|
204
|
+
|
|
74
205
|
/**
|
|
75
206
|
* True if the cookie is secure (only sent over HTTPS).
|
|
76
207
|
*
|
|
77
208
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)
|
|
209
|
+
*
|
|
210
|
+
* @default false
|
|
78
211
|
*/
|
|
79
|
-
|
|
212
|
+
get secure(): boolean {
|
|
213
|
+
return this.#secure ?? false
|
|
214
|
+
}
|
|
215
|
+
|
|
80
216
|
/**
|
|
81
217
|
* Returns the value to use in a `Set-Cookie` header for this cookie.
|
|
218
|
+
*
|
|
82
219
|
* @param value The value to serialize
|
|
83
|
-
* @param props
|
|
84
|
-
* @returns The `Set-Cookie` header for this cookie
|
|
85
|
-
*/
|
|
86
|
-
serialize(value: string, props?: CookieProperties): Promise<string>
|
|
87
|
-
/**
|
|
88
|
-
* True if this cookie uses one or more secrets for verification.
|
|
220
|
+
* @param props Additional properties to use when serializing the cookie
|
|
221
|
+
* @returns The `Set-Cookie` header value for this cookie
|
|
89
222
|
*/
|
|
90
|
-
|
|
91
|
-
|
|
223
|
+
async serialize(value: string, props?: CookieProperties): Promise<string> {
|
|
224
|
+
let header = new SetCookieHeader({
|
|
225
|
+
name: this.#name,
|
|
226
|
+
value: value === '' ? '' : await encodeCookieValue(value, this.#secrets, this.#encode),
|
|
227
|
+
domain: this.#domain,
|
|
228
|
+
expires: this.#expires,
|
|
229
|
+
httpOnly: this.#httpOnly,
|
|
230
|
+
maxAge: this.#maxAge,
|
|
231
|
+
partitioned: this.#partitioned,
|
|
232
|
+
path: this.#path,
|
|
233
|
+
sameSite: this.#sameSite,
|
|
234
|
+
secure: this.#secure,
|
|
235
|
+
...props,
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
return header.toString()
|
|
239
|
+
}
|
|
92
240
|
|
|
93
|
-
export interface CookieOptions extends CookieProperties {
|
|
94
|
-
/**
|
|
95
|
-
* A function that decodes the cookie value.
|
|
96
|
-
*
|
|
97
|
-
* Defaults to `decodeURIComponent`, which decodes any URL-encoded sequences into their original
|
|
98
|
-
* characters.
|
|
99
|
-
*
|
|
100
|
-
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
101
|
-
*/
|
|
102
|
-
decode?: (value: string) => string
|
|
103
|
-
/**
|
|
104
|
-
* A function that encodes the cookie value.
|
|
105
|
-
*
|
|
106
|
-
* Defaults to `encodeURIComponent`, which percent-encodes all characters that are not allowed
|
|
107
|
-
* in a cookie value.
|
|
108
|
-
*
|
|
109
|
-
* See [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1) for more details.
|
|
110
|
-
*/
|
|
111
|
-
encode?: (value: string) => string
|
|
112
241
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* The array makes it easy to rotate secrets. New secrets should be added to
|
|
116
|
-
* the beginning of the array. `cookie.serialize()` will always use the first
|
|
117
|
-
* value in the array, but `cookie.parse()` may use any of them so that
|
|
118
|
-
* cookies that were signed with older secrets still work.
|
|
242
|
+
* True if this cookie uses one or more secrets for verification.
|
|
119
243
|
*/
|
|
120
|
-
|
|
244
|
+
get signed(): boolean {
|
|
245
|
+
return this.#secrets.length > 0
|
|
246
|
+
}
|
|
121
247
|
}
|
|
122
248
|
|
|
123
249
|
/**
|
|
124
250
|
* Creates a new cookie object.
|
|
251
|
+
*
|
|
125
252
|
* @param name The name of the cookie
|
|
126
|
-
* @param options
|
|
127
|
-
* @returns A
|
|
253
|
+
* @param options Options for the cookie
|
|
254
|
+
* @returns A new `Cookie` object
|
|
128
255
|
*/
|
|
129
256
|
export function createCookie(name: string, options?: CookieOptions): Cookie {
|
|
130
|
-
|
|
131
|
-
decode = decodeURIComponent,
|
|
132
|
-
encode = encodeURIComponent,
|
|
133
|
-
secrets = [],
|
|
134
|
-
domain,
|
|
135
|
-
expires,
|
|
136
|
-
httpOnly,
|
|
137
|
-
maxAge,
|
|
138
|
-
path = '/',
|
|
139
|
-
partitioned,
|
|
140
|
-
secure,
|
|
141
|
-
sameSite = 'Lax',
|
|
142
|
-
} = options ?? {}
|
|
143
|
-
|
|
144
|
-
if (partitioned === true) {
|
|
145
|
-
// Partitioned cookies must be set with Secure
|
|
146
|
-
// See https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies
|
|
147
|
-
secure = true
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
get domain() {
|
|
152
|
-
return domain
|
|
153
|
-
},
|
|
154
|
-
get expires() {
|
|
155
|
-
return expires
|
|
156
|
-
},
|
|
157
|
-
get httpOnly() {
|
|
158
|
-
return httpOnly ?? false
|
|
159
|
-
},
|
|
160
|
-
get maxAge() {
|
|
161
|
-
return maxAge
|
|
162
|
-
},
|
|
163
|
-
get name() {
|
|
164
|
-
return name
|
|
165
|
-
},
|
|
166
|
-
async parse(headerValue: string | null): Promise<string | null> {
|
|
167
|
-
if (!headerValue) return null
|
|
168
|
-
|
|
169
|
-
let header = new CookieHeader(headerValue)
|
|
170
|
-
if (!header.has(name)) return null
|
|
171
|
-
|
|
172
|
-
let value = header.get(name)!
|
|
173
|
-
if (value === '') return ''
|
|
174
|
-
|
|
175
|
-
let decoded = await decodeCookieValue(value, secrets, decode)
|
|
176
|
-
return decoded
|
|
177
|
-
},
|
|
178
|
-
get partitioned() {
|
|
179
|
-
return partitioned ?? false
|
|
180
|
-
},
|
|
181
|
-
get path() {
|
|
182
|
-
return path
|
|
183
|
-
},
|
|
184
|
-
get sameSite() {
|
|
185
|
-
return sameSite
|
|
186
|
-
},
|
|
187
|
-
get secure() {
|
|
188
|
-
return secure ?? false
|
|
189
|
-
},
|
|
190
|
-
async serialize(value: string, props?: CookieProperties): Promise<string> {
|
|
191
|
-
let header = new SetCookieHeader({
|
|
192
|
-
name: name,
|
|
193
|
-
value: value === '' ? '' : await encodeCookieValue(value, secrets, encode),
|
|
194
|
-
domain,
|
|
195
|
-
expires,
|
|
196
|
-
httpOnly,
|
|
197
|
-
maxAge,
|
|
198
|
-
partitioned,
|
|
199
|
-
path,
|
|
200
|
-
sameSite,
|
|
201
|
-
secure,
|
|
202
|
-
...props,
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
return header.toString()
|
|
206
|
-
},
|
|
207
|
-
get signed() {
|
|
208
|
-
return secrets.length > 0
|
|
209
|
-
},
|
|
210
|
-
}
|
|
257
|
+
return new Cookie(name, options)
|
|
211
258
|
}
|
|
212
259
|
|
|
213
|
-
type Coder = (value: string) => string
|
|
214
|
-
|
|
215
260
|
async function decodeCookieValue(
|
|
216
261
|
value: string,
|
|
217
262
|
secrets: string[],
|