@remix-run/cookie 0.1.0 → 0.3.0
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/README.md +1 -1
- 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.d.ts +13 -3
- package/dist/lib/cookie.d.ts.map +1 -1
- package/dist/lib/cookie.js +34 -18
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/lib/cookie.ts +53 -29
- package/src/lib/crypto.ts +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cookie
|
|
2
2
|
|
|
3
3
|
Simplify HTTP cookie management in JavaScript with type-safe, secure cookie handling. `@remix-run/cookie` provides a clean, intuitive API for creating, parsing, and serializing HTTP cookies with built-in support for signing, secret rotation, and comprehensive cookie attribute management.
|
|
4
4
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type CookieOptions, Cookie } from './lib/cookie.ts';
|
|
1
|
+
export { createCookie, type CookieOptions, Cookie } 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,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Cookie } from "./lib/cookie.js";
|
|
1
|
+
export { createCookie, Cookie } from "./lib/cookie.js";
|
package/dist/lib/cookie.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type CookieProperties } from '@remix-run/headers';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new `Cookie` object.
|
|
4
|
+
* @param name The name of the cookie
|
|
5
|
+
* @param options The options for the cookie
|
|
6
|
+
* @returns A new cookie instance
|
|
7
|
+
*/
|
|
8
|
+
export declare function createCookie(name: string, options?: CookieOptions): Cookie;
|
|
9
|
+
export interface CookieOptions extends CookieProperties {
|
|
3
10
|
/**
|
|
4
11
|
* A function that decodes the cookie value.
|
|
5
12
|
*
|
|
@@ -34,12 +41,15 @@ export interface CookieOptions {
|
|
|
34
41
|
*/
|
|
35
42
|
export declare class Cookie {
|
|
36
43
|
#private;
|
|
37
|
-
readonly name: string;
|
|
38
44
|
constructor(name: string, options?: CookieOptions);
|
|
45
|
+
/**
|
|
46
|
+
* The name of the cookie.
|
|
47
|
+
*/
|
|
48
|
+
readonly name: string;
|
|
39
49
|
/**
|
|
40
50
|
* True if this cookie uses one or more secrets for verification.
|
|
41
51
|
*/
|
|
42
|
-
get
|
|
52
|
+
get signed(): boolean;
|
|
43
53
|
/**
|
|
44
54
|
* Extracts the value of this cookie from a `Cookie` header value.
|
|
45
55
|
* @param headerValue The value of the `Cookie` header to parse
|
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,MAAM,
|
|
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;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAE1E;AAED,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;;;GAGG;AACH,qBAAa,MAAM;;gBACL,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAejD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAOrB;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;;;OAIG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa/D;;;;;OAKG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAa1E"}
|
package/dist/lib/cookie.js
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import { Cookie as CookieHeader, SetCookie as SetCookieHeader, } from '@remix-run/headers';
|
|
2
2
|
import { sign, unsign } from "./crypto.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a new `Cookie` object.
|
|
5
|
+
* @param name The name of the cookie
|
|
6
|
+
* @param options The options for the cookie
|
|
7
|
+
* @returns A new cookie instance
|
|
8
|
+
*/
|
|
9
|
+
export function createCookie(name, options) {
|
|
10
|
+
return new Cookie(name, options);
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* A container for metadata about a HTTP cookie; its name and secrets that may be used
|
|
5
14
|
* to sign/unsign the value of the cookie to ensure it's not tampered with.
|
|
6
15
|
*/
|
|
7
16
|
export class Cookie {
|
|
17
|
+
constructor(name, options) {
|
|
18
|
+
let { decode = decodeURIComponent, encode = encodeURIComponent, secrets = [], ...props } = options ?? {};
|
|
19
|
+
this.name = name;
|
|
20
|
+
this.#decode = decode;
|
|
21
|
+
this.#encode = encode;
|
|
22
|
+
this.#secrets = secrets;
|
|
23
|
+
this.#props = props;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The name of the cookie.
|
|
27
|
+
*/
|
|
8
28
|
name;
|
|
9
29
|
#decode;
|
|
10
30
|
#encode;
|
|
11
31
|
#secrets;
|
|
12
|
-
|
|
13
|
-
this.name = name;
|
|
14
|
-
this.#decode = options?.decode;
|
|
15
|
-
this.#encode = options?.encode;
|
|
16
|
-
this.#secrets = options?.secrets ?? [];
|
|
17
|
-
}
|
|
32
|
+
#props;
|
|
18
33
|
/**
|
|
19
34
|
* True if this cookie uses one or more secrets for verification.
|
|
20
35
|
*/
|
|
21
|
-
get
|
|
36
|
+
get signed() {
|
|
22
37
|
return this.#secrets.length > 0;
|
|
23
38
|
}
|
|
24
39
|
/**
|
|
@@ -51,22 +66,13 @@ export class Cookie {
|
|
|
51
66
|
// sane defaults
|
|
52
67
|
path: '/',
|
|
53
68
|
sameSite: 'Lax',
|
|
69
|
+
...this.#props,
|
|
54
70
|
...props,
|
|
55
71
|
});
|
|
56
72
|
return header.toString();
|
|
57
73
|
}
|
|
58
74
|
}
|
|
59
|
-
async function
|
|
60
|
-
let encoded = encodeValue(value, encode);
|
|
61
|
-
if (secrets.length > 0) {
|
|
62
|
-
encoded = await sign(encoded, secrets[0]);
|
|
63
|
-
}
|
|
64
|
-
return encoded;
|
|
65
|
-
}
|
|
66
|
-
function encodeValue(value, encode) {
|
|
67
|
-
return btoa(myUnescape(encode(value)));
|
|
68
|
-
}
|
|
69
|
-
async function decodeCookieValue(value, secrets, decode = decodeURIComponent) {
|
|
75
|
+
async function decodeCookieValue(value, secrets, decode) {
|
|
70
76
|
if (secrets.length > 0) {
|
|
71
77
|
for (let secret of secrets) {
|
|
72
78
|
let unsignedValue = await unsign(value, secret);
|
|
@@ -115,6 +121,16 @@ function hex(code, length) {
|
|
|
115
121
|
result = '0' + result;
|
|
116
122
|
return result;
|
|
117
123
|
}
|
|
124
|
+
async function encodeCookieValue(value, secrets, encode) {
|
|
125
|
+
let encoded = encodeValue(value, encode);
|
|
126
|
+
if (secrets.length > 0) {
|
|
127
|
+
encoded = await sign(encoded, secrets[0]);
|
|
128
|
+
}
|
|
129
|
+
return encoded;
|
|
130
|
+
}
|
|
131
|
+
function encodeValue(value, encode) {
|
|
132
|
+
return btoa(myUnescape(encode(value)));
|
|
133
|
+
}
|
|
118
134
|
// See: https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.unescape.js
|
|
119
135
|
function myUnescape(value) {
|
|
120
136
|
let str = value.toString();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/cookie",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A toolkit for working with cookies in JavaScript",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@types/node": "^24.6.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@remix-run/headers": "0.
|
|
32
|
+
"@remix-run/headers": "^0.16.0"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"http",
|
package/src/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { type CookieOptions, Cookie } from './lib/cookie.ts'
|
|
1
|
+
export { createCookie, type CookieOptions, Cookie } from './lib/cookie.ts'
|
package/src/lib/cookie.ts
CHANGED
|
@@ -6,7 +6,17 @@ import {
|
|
|
6
6
|
|
|
7
7
|
import { sign, unsign } from './crypto.ts'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new `Cookie` object.
|
|
11
|
+
* @param name The name of the cookie
|
|
12
|
+
* @param options The options for the cookie
|
|
13
|
+
* @returns A new cookie instance
|
|
14
|
+
*/
|
|
15
|
+
export function createCookie(name: string, options?: CookieOptions): Cookie {
|
|
16
|
+
return new Cookie(name, options)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CookieOptions extends CookieProperties {
|
|
10
20
|
/**
|
|
11
21
|
* A function that decodes the cookie value.
|
|
12
22
|
*
|
|
@@ -41,22 +51,35 @@ export interface CookieOptions {
|
|
|
41
51
|
* to sign/unsign the value of the cookie to ensure it's not tampered with.
|
|
42
52
|
*/
|
|
43
53
|
export class Cookie {
|
|
44
|
-
readonly name: string
|
|
45
|
-
readonly #decode?: (value: string) => string
|
|
46
|
-
readonly #encode?: (value: string) => string
|
|
47
|
-
readonly #secrets: string[]
|
|
48
|
-
|
|
49
54
|
constructor(name: string, options?: CookieOptions) {
|
|
55
|
+
let {
|
|
56
|
+
decode = decodeURIComponent,
|
|
57
|
+
encode = encodeURIComponent,
|
|
58
|
+
secrets = [],
|
|
59
|
+
...props
|
|
60
|
+
} = options ?? {}
|
|
61
|
+
|
|
50
62
|
this.name = name
|
|
51
|
-
this.#decode =
|
|
52
|
-
this.#encode =
|
|
53
|
-
this.#secrets =
|
|
63
|
+
this.#decode = decode
|
|
64
|
+
this.#encode = encode
|
|
65
|
+
this.#secrets = secrets
|
|
66
|
+
this.#props = props
|
|
54
67
|
}
|
|
55
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The name of the cookie.
|
|
71
|
+
*/
|
|
72
|
+
readonly name: string
|
|
73
|
+
|
|
74
|
+
readonly #decode: (value: string) => string
|
|
75
|
+
readonly #encode: (value: string) => string
|
|
76
|
+
readonly #secrets: string[]
|
|
77
|
+
readonly #props: CookieProperties
|
|
78
|
+
|
|
56
79
|
/**
|
|
57
80
|
* True if this cookie uses one or more secrets for verification.
|
|
58
81
|
*/
|
|
59
|
-
get
|
|
82
|
+
get signed(): boolean {
|
|
60
83
|
return this.#secrets.length > 0
|
|
61
84
|
}
|
|
62
85
|
|
|
@@ -91,6 +114,7 @@ export class Cookie {
|
|
|
91
114
|
// sane defaults
|
|
92
115
|
path: '/',
|
|
93
116
|
sameSite: 'Lax',
|
|
117
|
+
...this.#props,
|
|
94
118
|
...props,
|
|
95
119
|
})
|
|
96
120
|
|
|
@@ -98,28 +122,10 @@ export class Cookie {
|
|
|
98
122
|
}
|
|
99
123
|
}
|
|
100
124
|
|
|
101
|
-
async function encodeCookieValue(
|
|
102
|
-
value: string,
|
|
103
|
-
secrets: string[],
|
|
104
|
-
encode: (value: string) => string = encodeURIComponent,
|
|
105
|
-
): Promise<string> {
|
|
106
|
-
let encoded = encodeValue(value, encode)
|
|
107
|
-
|
|
108
|
-
if (secrets.length > 0) {
|
|
109
|
-
encoded = await sign(encoded, secrets[0])
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return encoded
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function encodeValue(value: string, encode: (value: string) => string): string {
|
|
116
|
-
return btoa(myUnescape(encode(value)))
|
|
117
|
-
}
|
|
118
|
-
|
|
119
125
|
async function decodeCookieValue(
|
|
120
126
|
value: string,
|
|
121
127
|
secrets: string[],
|
|
122
|
-
decode: (value: string) => string
|
|
128
|
+
decode: (value: string) => string,
|
|
123
129
|
): Promise<string | null> {
|
|
124
130
|
if (secrets.length > 0) {
|
|
125
131
|
for (let secret of secrets) {
|
|
@@ -171,6 +177,24 @@ function hex(code: number, length: number): string {
|
|
|
171
177
|
return result
|
|
172
178
|
}
|
|
173
179
|
|
|
180
|
+
async function encodeCookieValue(
|
|
181
|
+
value: string,
|
|
182
|
+
secrets: string[],
|
|
183
|
+
encode: (value: string) => string,
|
|
184
|
+
): Promise<string> {
|
|
185
|
+
let encoded = encodeValue(value, encode)
|
|
186
|
+
|
|
187
|
+
if (secrets.length > 0) {
|
|
188
|
+
encoded = await sign(encoded, secrets[0])
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return encoded
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function encodeValue(value: string, encode: (value: string) => string): string {
|
|
195
|
+
return btoa(myUnescape(encode(value)))
|
|
196
|
+
}
|
|
197
|
+
|
|
174
198
|
// See: https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.unescape.js
|
|
175
199
|
function myUnescape(value: string): string {
|
|
176
200
|
let str = value.toString()
|
package/src/lib/crypto.ts
CHANGED
|
@@ -40,7 +40,7 @@ async function createKey(secret: string, usages: CryptoKey['usages']): Promise<C
|
|
|
40
40
|
)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function byteStringToUint8Array(byteString: string): Uint8Array {
|
|
43
|
+
function byteStringToUint8Array(byteString: string): Uint8Array<ArrayBuffer> {
|
|
44
44
|
let array = new Uint8Array(byteString.length)
|
|
45
45
|
|
|
46
46
|
for (let i = 0; i < byteString.length; i++) {
|