mirror of
https://github.com/block/buzz.git
synced 2026-10-31 14:31:02 +00:00
## Summary - buffer native WebSocket frames until `plugin:websocket|connect` returns the socket ID and the NIP-42 auth waiter is installed - drain those frames in order before normal inbound handling begins - add a deterministic E2E seam and regression for an AUTH challenge delivered before connect resolves ## Root cause The native WebSocket task starts forwarding relay frames before the connect command returns its socket ID. Buzz relay sends the NIP-42 AUTH challenge immediately on connection, so Desktop could process that challenge while `wsId` and `authRequest` were still unset. The challenge was discarded, the cold connection failed authentication, and the first plain-text send failed. Channel history still appeared because it loads through the Tauri channel-window command rather than this frontend WebSocket. ## Verification - deterministic regression is red before the fix (`connecting` after 5s) and green after it - `pnpm test`: 3,721 passed - `pnpm build:e2e`: passed - focused early-AUTH E2E: passed - existing failed-initial-dial E2E: passed - `pnpm typecheck`: passed - Biome + file-size pre-commit checks: passed The complete 7-test relay-reconnect file passed once before the final line-count-only compaction. After that compaction, two full-file reruns each had the same unrelated startup-seam flake in the existing initial-dial test; both the new test and that existing test pass independently at the committed HEAD. --------- Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz> Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz> Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz> Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
37 lines
1011 B
TypeScript
37 lines
1011 B
TypeScript
export const MAX_PENDING_RELAY_FRAMES = 256;
|
|
|
|
export function createRelayInboundBuffer(
|
|
handle: (message: unknown) => Promise<void>,
|
|
onError: (error: unknown) => void,
|
|
) {
|
|
let pending: unknown[] | null | undefined = [];
|
|
let rejectOverflow = (_error: Error) => {};
|
|
const overflow = new Promise<never>((_resolve, reject) => {
|
|
rejectOverflow = reject;
|
|
});
|
|
void overflow.catch(() => {});
|
|
|
|
return {
|
|
overflow,
|
|
receive(message: unknown) {
|
|
if (pending === null) {
|
|
void handle(message).catch(onError);
|
|
return;
|
|
}
|
|
if (pending === undefined) return;
|
|
if (pending.length >= MAX_PENDING_RELAY_FRAMES) {
|
|
pending = undefined;
|
|
const error = new Error("Relay sent too many frames while connecting.");
|
|
rejectOverflow(error);
|
|
onError(error);
|
|
return;
|
|
}
|
|
pending.push(message);
|
|
},
|
|
async drain() {
|
|
while (pending?.length) await handle(pending.shift());
|
|
if (pending) pending = null;
|
|
},
|
|
};
|
|
}
|