fix: harden resume and SSE replay

This commit is contained in:
User
2026-07-15 00:06:00 +02:00
parent e5366d14a6
commit 2b4797f133
18 changed files with 871 additions and 102 deletions
+8 -8
View File
@@ -1,27 +1,27 @@
export class FakeEventSource {
static instances: FakeEventSource[] = [];
onmessage: ((e: { data: string }) => void) | null = null;
onmessage: ((e: { data: string; lastEventId: string }) => void) | null = null;
onopen: (() => void) | null = null;
onerror: (() => void) | null = null;
closed = false;
private listeners = new Map<string, Set<(e: { data: string }) => void>>();
private listeners = new Map<string, Set<(e: { data: string; lastEventId: string }) => void>>();
constructor(public url: string) {
FakeEventSource.instances.push(this);
}
/** Dispatch to the default onmessage handler (unnamed `event: message`). */
emit(obj: unknown) {
this.onmessage?.({ data: JSON.stringify(obj) });
emit(obj: unknown, lastEventId = "") {
this.onmessage?.({ data: JSON.stringify(obj), lastEventId });
}
/** Dispatch to handlers registered for a NAMED event (e.g. "ui_request"). */
emitNamed(type: string, obj: unknown) {
emitNamed(type: string, obj: unknown, lastEventId = "") {
const data = JSON.stringify(obj);
for (const h of this.listeners.get(type) ?? []) h({ data });
for (const h of this.listeners.get(type) ?? []) h({ data, lastEventId });
}
addEventListener(type: string, handler: (e: { data: string }) => void) {
addEventListener(type: string, handler: (e: { data: string; lastEventId: string }) => void) {
if (!this.listeners.has(type)) this.listeners.set(type, new Set());
this.listeners.get(type)!.add(handler);
}
removeEventListener(type: string, handler: (e: { data: string }) => void) {
removeEventListener(type: string, handler: (e: { data: string; lastEventId: string }) => void) {
this.listeners.get(type)?.delete(handler);
}
close() {