blob: 5798fdba61f84a1ff1ba9cad0b7bf2bcb3a401e2 (
plain)
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
|
import type { PendingInput, PendingInputStorage } from "../pending-inputs";
export function createPendingInputStorage(
storage: Storage,
conversationId: string,
): PendingInputStorage {
const prefix = `dispatch.pending-inputs:${conversationId}:`;
let known = new Map<string, string>();
return {
load() {
const inputs: PendingInput[] = [];
const loaded = new Map<string, string>();
for (let i = 0; i < storage.length; i++) {
const key = storage.key(i);
if (key === null || !key.startsWith(prefix)) continue;
const raw = storage.getItem(key);
if (raw === null) continue;
const input = JSON.parse(raw);
if (
(input?.request?.type !== "chat.send" && input?.request?.type !== "chat.queue") ||
input.request.conversationId !== conversationId ||
typeof input.request.requestId !== "string" ||
key !== prefix + input.request.requestId ||
(input.request.type === "chat.send"
? typeof input.request.message !== "string"
: typeof input.request.text !== "string") ||
(input.rejection !== undefined && typeof input.rejection !== "string")
)
throw new Error("Invalid saved input");
inputs.push(input);
loaded.set(input.request.requestId, raw);
}
known = loaded;
return inputs;
},
save(inputs) {
// Per-request keys prevent another browser tab's send/receipt from overwriting ours.
// Quota/security failures reach the composer BEFORE it clears its staged input.
const next = new Map(inputs.map((input) => [input.request.requestId, JSON.stringify(input)]));
for (const [id, raw] of next) {
if (known.get(id) !== raw) storage.setItem(prefix + id, raw);
}
for (const id of known.keys()) {
if (!next.has(id)) storage.removeItem(prefix + id);
}
known = next;
},
};
}
|