-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
/
Copy pathworkersKVStorage.ts
78 lines (70 loc) · 2.08 KB
/
workersKVStorage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import type {
SessionStorage,
SessionIdStorageStrategy,
SessionData,
} from "react-router";
import { createSessionStorage } from "react-router";
interface WorkersKVSessionStorageOptions {
/**
* The Cookie used to store the session id on the client, or options used
* to automatically create one.
*/
cookie?: SessionIdStorageStrategy["cookie"];
/**
* The KVNamespace used to store the sessions.
*/
kv: KVNamespace;
}
/**
* Creates a SessionStorage that stores session data in the Clouldflare KV Store.
*
* The advantage of using this instead of cookie session storage is that
* KV Store may contain much more data than cookies.
*/
export function createWorkersKVSessionStorage<
Data = SessionData,
FlashData = Data
>({
cookie,
kv,
}: WorkersKVSessionStorageOptions): SessionStorage<Data, FlashData> {
return createSessionStorage({
cookie,
async createData(data, expires) {
while (true) {
let randomBytes = crypto.getRandomValues(new Uint8Array(8));
// This storage manages an id space of 2^64 ids, which is far greater
// than the maximum number of files allowed on an NTFS or ext4 volume
// (2^32). However, the larger id space should help to avoid collisions
// with existing ids when creating new sessions, which speeds things up.
let id = [...randomBytes]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
if (await kv.get(id, "json")) {
continue;
}
await kv.put(id, JSON.stringify(data), {
expiration: expires
? Math.round(expires.getTime() / 1000)
: undefined,
});
return id;
}
},
async readData(id) {
let session = await kv.get(id);
if (!session) {
return null;
}
return JSON.parse(session);
},
async updateData(id, data, expires) {
await kv.put(id, JSON.stringify(data), {
expiration: expires ? Math.round(expires.getTime() / 1000) : undefined,
});
},
async deleteData(id) {
await kv.delete(id);
},
});
}