From 1a5c7f1aa273c49b70918f8f1da560de0b4c72ab Mon Sep 17 00:00:00 2001 From: snekxs Date: Sat, 17 Oct 2026 01:42:01 -0600 Subject: [PATCH] feat(endgame): include granted HID collections in OT handshake errors Refs #237 Co-Authored-By: Claude Sonnet 5.5 --- src/drivers/endgame/egg-ot-hid.test.ts | 2 +- src/drivers/endgame/egg-ot-hid.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/drivers/endgame/egg-ot-hid.test.ts b/src/drivers/endgame/egg-ot-hid.test.ts index b2f9a7b4..0d664b58 100644 --- a/src/drivers/endgame/egg-ot-hid.test.ts +++ b/src/drivers/endgame/egg-ot-hid.test.ts @@ -306,6 +306,6 @@ test("a mouse that never sends the response packet reports the raw tx/rx trace", const client = new EggOtHidClient(fake.device); await assert.rejects( () => client.readStatus(), - /did not answer OT profile block 0\. Trace: tx 33 [0-9a-f ]+ \| rx 00 14 [0-9a-f ]+ \| rx 00 00 [0-9a-f ]+ x\d+/, + /did not answer OT profile block 0\. Trace: tx 33 [0-9a-f ]+ \| rx 00 14 [0-9a-f ]+ \| rx 00 00 [0-9a-f ]+ x\d+.*\. Collections: usage 0xff00:0x1 ยท feature 0x0/, ); }); diff --git a/src/drivers/endgame/egg-ot-hid.ts b/src/drivers/endgame/egg-ot-hid.ts index 5c10bbd4..bad4bfb5 100644 --- a/src/drivers/endgame/egg-ot-hid.ts +++ b/src/drivers/endgame/egg-ot-hid.ts @@ -381,9 +381,9 @@ export class EggOtHidClient { reply = await this.exchange(otEncodeQueryPacket(block, profileIndex), true); } catch (error) { const message = error instanceof Error ? error.message : String(error); - throw new Error(`OT profile block ${block} failed: ${message} Trace: ${this.describeTrace()}`); + throw new Error(`OT profile block ${block} failed: ${message} ${this.describeFailureContext()}`); } - if (!reply) throw new Error(`The mouse did not answer OT profile block ${block}. Trace: ${this.describeTrace()}`); + if (!reply) throw new Error(`The mouse did not answer OT profile block ${block}. ${this.describeFailureContext()}`); return reply.subarray(OT_PAYLOAD_INDEX); } @@ -392,6 +392,11 @@ export class EggOtHidClient { return this.trace.length > 0 ? this.trace.join(" | ") : "no packets"; } + /** Trace plus the granted HID collections, so a refused write shows which interface the browser handed us. */ + private describeFailureContext(): string { + return `Trace: ${this.describeTrace()}. Collections: ${this.describeCollections()}`; + } + private record(direction: "tx" | "rx" | "err", detail: Uint8Array | string): void { const text = typeof detail === "string" ? detail