(opts: {
sid: string;
lastSeq?: number;
clientId?: string;
log?: (label: string, value?: unknown) => void;
})
| 82 | } |
| 83 | |
| 84 | async function openSocketWithHello(opts: { |
| 85 | sid: string; |
| 86 | lastSeq?: number; |
| 87 | clientId?: string; |
| 88 | log?: (label: string, value?: unknown) => void; |
| 89 | }): Promise<HelloResult> { |
| 90 | const wsUrl = `${BASE_URL.replace(/^http/, 'ws')}${API_PREFIX}/ws`; |
| 91 | const ws = new WsClient({ url: wsUrl, wsImpl: WsWebSocket, logger: () => {} }); |
| 92 | opts.log?.('refresh ws open', { url: wsUrl, sid: opts.sid, last_seq: opts.lastSeq }); |
| 93 | await ws.open(); |
| 94 | |
| 95 | const arrivals: AnyFrame[] = []; |
| 96 | ws.onFrame((f) => arrivals.push(f)); |
| 97 | |
| 98 | const serverHello = await ws.waitForFrame((f) => f.type === 'server_hello', HANDSHAKE_TIMEOUT_MS); |
| 99 | opts.log?.('refresh ws server_hello', frameForLog(serverHello)); |
| 100 | |
| 101 | const helloId = `hello-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; |
| 102 | const payload: Record<string, unknown> = { |
| 103 | client_id: opts.clientId ?? `vitest-refresh-${process.pid}`, |
| 104 | subscriptions: [opts.sid], |
| 105 | }; |
| 106 | if (opts.lastSeq !== undefined) { |
| 107 | payload['cursors'] = { [opts.sid]: { seq: opts.lastSeq } }; |
| 108 | } |
| 109 | opts.log?.('refresh ws client_hello', { id: helloId, payload }); |
| 110 | ws.send({ type: 'client_hello', id: helloId, payload }); |
| 111 | |
| 112 | const ack = await ws.waitForFrame( |
| 113 | (f) => f.type === 'ack' && f.id === helloId, |
| 114 | HANDSHAKE_TIMEOUT_MS, |
| 115 | ); |
| 116 | opts.log?.('refresh ws ack', frameForLog(ack)); |
| 117 | |
| 118 | const replayed = arrivals.filter( |
| 119 | (f) => |
| 120 | f.type !== 'server_hello' && |
| 121 | f.type !== 'ack' && |
| 122 | f.type !== 'ping' && |
| 123 | f.type !== 'resync_required' && |
| 124 | f.type !== 'error' && |
| 125 | typeof f.seq === 'number' && |
| 126 | f.session_id === opts.sid && |
| 127 | (opts.lastSeq === undefined || f.seq > opts.lastSeq), |
| 128 | ); |
| 129 | opts.log?.('refresh ws replayed', { |
| 130 | count: replayed.length, |
| 131 | frames: replayed.map(frameForLog), |
| 132 | }); |
| 133 | |
| 134 | return { ws, ack, replayed }; |
| 135 | } |
| 136 | |
| 137 | const reachable = await daemonReachable(); |
| 138 | const describeLive = reachable ? describe : describe.skip; |
no test coverage detected