From 52d710dbb5732f7ab8cccbb030df86f5a8eab5e4 Mon Sep 17 00:00:00 2001 From: Jakob Notland Date: Tue, 21 Apr 2026 14:19:42 +0200 Subject: [PATCH] Lint - also gonna leave this branch and probably drop it. Dagur has a design plan. --- packages/core/src/chunk-assembler.test.ts | 104 ++++++++++++++++--- packages/core/src/chunk-assembler.ts | 25 ++++- packages/core/src/relay-client.ts | 20 +++- packages/dapp/src/dapp-connection-manager.ts | 4 +- packages/test-cli/src/dapp.ts | 58 +++++++++-- packages/test-cli/src/wallet.ts | 7 +- 6 files changed, 179 insertions(+), 39 deletions(-) diff --git a/packages/core/src/chunk-assembler.test.ts b/packages/core/src/chunk-assembler.test.ts index f2576a2..0882b42 100644 --- a/packages/core/src/chunk-assembler.test.ts +++ b/packages/core/src/chunk-assembler.test.ts @@ -4,7 +4,10 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { ChunkAssembler, CHUNK_TIMEOUT_MS } from "./chunk-assembler.js"; -import { type ChunkRelayMessage, RelayMsgAction } from "./protocols/hdwalletv1.js"; +import { + type ChunkRelayMessage, + RelayMsgAction, +} from "./protocols/hdwalletv1.js"; function makeChunk( chunk_id: string, @@ -22,12 +25,23 @@ function makeChunk( }; } -function splitMessage(message: object, chunkSize: number, chunk_id: string): ChunkRelayMessage[] { +function splitMessage( + message: object, + chunkSize: number, + chunk_id: string, +): ChunkRelayMessage[] { const json = JSON.stringify(message); const chunks: ChunkRelayMessage[] = []; const total = Math.ceil(json.length / chunkSize); for (let i = 0; i < total; i++) { - chunks.push(makeChunk(chunk_id, i, total, json.slice(i * chunkSize, (i + 1) * chunkSize))); + chunks.push( + makeChunk( + chunk_id, + i, + total, + json.slice(i * chunkSize, (i + 1) * chunkSize), + ), + ); } return chunks; } @@ -46,7 +60,11 @@ describe("ChunkAssembler", () => { describe("single-fragment messages", () => { it("reassembles a single-fragment message immediately", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const [chunk] = splitMessage(original, 10000, "id1"); const result = assembler.addChunk(chunk); @@ -55,7 +73,11 @@ describe("ChunkAssembler", () => { }); it("clears the pending buffer after assembly", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const [chunk] = splitMessage(original, 10000, "id1"); assembler.addChunk(chunk); @@ -66,7 +88,11 @@ describe("ChunkAssembler", () => { describe("multi-fragment messages", () => { it("returns null for each fragment until the last", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 7, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 7, + time: 1000, + }; const chunks = splitMessage(original, 5, "id2"); expect(chunks.length).toBeGreaterThan(1); @@ -76,7 +102,11 @@ describe("ChunkAssembler", () => { }); it("returns the reassembled message on the last fragment", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 7, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 7, + time: 1000, + }; const chunks = splitMessage(original, 5, "id3"); let result = null; @@ -88,7 +118,11 @@ describe("ChunkAssembler", () => { }); it("reassembles correctly when fragments arrive out of order", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 42, time: 2000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 42, + time: 2000, + }; const chunks = splitMessage(original, 3, "id4"); expect(chunks.length).toBeGreaterThan(1); @@ -146,8 +180,16 @@ describe("ChunkAssembler", () => { describe("independent chunk_ids", () => { it("tracks multiple concurrent assemblies independently", () => { - const msgA = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; - const msgB = { action: RelayMsgAction.SignCancel, sequence: 2, time: 2000 }; + const msgA = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; + const msgB = { + action: RelayMsgAction.SignCancel, + sequence: 2, + time: 2000, + }; const chunksA = splitMessage(msgA, 5, "idA"); const chunksB = splitMessage(msgB, 5, "idB"); @@ -165,8 +207,16 @@ describe("ChunkAssembler", () => { }); it("completing one assembly does not affect pending assemblies", () => { - const msgA = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; - const msgB = { action: RelayMsgAction.SignCancel, sequence: 2, time: 2000 }; + const msgA = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; + const msgB = { + action: RelayMsgAction.SignCancel, + sequence: 2, + time: 2000, + }; const [chunkA] = splitMessage(msgA, 10000, "idA"); const chunksB = splitMessage(msgB, 5, "idB"); @@ -224,7 +274,11 @@ describe("ChunkAssembler", () => { describe("timeout cleanup", () => { it("discards incomplete assembly after timeout", () => { - const msgA = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const msgA = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const chunks = splitMessage(msgA, 5, "idTimeout"); expect(chunks.length).toBeGreaterThan(1); @@ -240,7 +294,11 @@ describe("ChunkAssembler", () => { }); it("does not timeout before CHUNK_TIMEOUT_MS", () => { - const msgA = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const msgA = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const chunks = splitMessage(msgA, 5, "idTimeout2"); for (let i = 0; i < chunks.length - 1; i++) { @@ -253,7 +311,11 @@ describe("ChunkAssembler", () => { }); it("clears timeout when assembly completes before timeout", () => { - const msgA = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const msgA = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const chunks = splitMessage(msgA, 5, "idTimeout3"); for (const chunk of chunks) { @@ -266,7 +328,11 @@ describe("ChunkAssembler", () => { }); it("after timeout, late arriving fragments start a fresh assembly", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const chunks = splitMessage(original, 5, "idReuse"); // Send first fragment, let it time out @@ -285,7 +351,11 @@ describe("ChunkAssembler", () => { describe("duplicate fragment index", () => { it("last write wins for duplicate index — still assembles correctly if content is the same", () => { - const original = { action: RelayMsgAction.SignCancel, sequence: 1, time: 1000 }; + const original = { + action: RelayMsgAction.SignCancel, + sequence: 1, + time: 1000, + }; const chunks = splitMessage(original, 5, "idDup"); expect(chunks.length).toBeGreaterThan(1); diff --git a/packages/core/src/chunk-assembler.ts b/packages/core/src/chunk-assembler.ts index 837f292..fc71974 100644 --- a/packages/core/src/chunk-assembler.ts +++ b/packages/core/src/chunk-assembler.ts @@ -39,7 +39,10 @@ export class ChunkAssembler { const { chunk_id, chunk_index, chunk_total, chunk_data } = chunk; if (chunk_total < 1) { - logError(Scope.Relay, `Invalid chunk_total ${chunk_total} for chunk_id ${chunk_id}`); + logError( + Scope.Relay, + `Invalid chunk_total ${chunk_total} for chunk_id ${chunk_id}`, + ); return null; } @@ -81,14 +84,20 @@ export class ChunkAssembler { return this.pending.size; } - private assemble(chunk_id: string, assembly: PendingAssembly): ProtocolMessage | null { + private assemble( + chunk_id: string, + assembly: PendingAssembly, + ): ProtocolMessage | null { this.discard(chunk_id); const parts: string[] = []; for (let i = 0; i < assembly.total; i++) { const part = assembly.fragments.get(i); if (part === undefined) { - logError(Scope.Relay, `Missing fragment index ${i} for chunk_id ${chunk_id}`); + logError( + Scope.Relay, + `Missing fragment index ${i} for chunk_id ${chunk_id}`, + ); return null; } parts.push(part); @@ -99,12 +108,18 @@ export class ChunkAssembler { try { parsed = JSON.parse(json); } catch { - logError(Scope.Relay, `Failed to parse assembled message for chunk_id ${chunk_id}`); + logError( + Scope.Relay, + `Failed to parse assembled message for chunk_id ${chunk_id}`, + ); return null; } if (!isProtocolMessage(parsed)) { - logError(Scope.Relay, `Assembled message for chunk_id ${chunk_id} is not a ProtocolMessage`); + logError( + Scope.Relay, + `Assembled message for chunk_id ${chunk_id} is not a ProtocolMessage`, + ); return null; } diff --git a/packages/core/src/relay-client.ts b/packages/core/src/relay-client.ts index dade7b6..a465956 100644 --- a/packages/core/src/relay-client.ts +++ b/packages/core/src/relay-client.ts @@ -259,7 +259,10 @@ export class RelayClient extends EventEmitter { } const messageJson = JSON.stringify(message); - if (messageJson.length > MAX_SAFE_MESSAGE_SIZE && this.peerSupportsChunking) { + if ( + messageJson.length > MAX_SAFE_MESSAGE_SIZE && + this.peerSupportsChunking + ) { return this.relayChunked(message.action, messageJson); } @@ -270,12 +273,18 @@ export class RelayClient extends EventEmitter { return this.publishMessage(message); } - private async relayChunked(originalAction: string, messageJson: string): Promise { + private async relayChunked( + originalAction: string, + messageJson: string, + ): Promise { const chunkId = Math.random().toString(36).slice(2, 14); const chunkTotal = Math.ceil(messageJson.length / CHUNK_SIZE); const now = Math.floor(Date.now() / 1000); - debug(Scope.Relay, `Chunking ${originalAction} into ${chunkTotal} fragments (${messageJson.length} chars)`); + debug( + Scope.Relay, + `Chunking ${originalAction} into ${chunkTotal} fragments (${messageJson.length} chars)`, + ); for (let i = 0; i < chunkTotal; i++) { const chunk: ChunkRelayMessage = { @@ -457,7 +466,10 @@ export class RelayClient extends EventEmitter { if (isChunkRelayMessage(message)) { const assembled = this.chunkAssembler.addChunk(message); if (assembled !== null) { - this.netlog("recv", `${assembled.action} [reassembled from ${message.chunk_total} chunks]`); + this.netlog( + "recv", + `${assembled.action} [reassembled from ${message.chunk_total} chunks]`, + ); this.emit("message", assembled); } return; diff --git a/packages/dapp/src/dapp-connection-manager.ts b/packages/dapp/src/dapp-connection-manager.ts index 9f57b68..71ff911 100644 --- a/packages/dapp/src/dapp-connection-manager.ts +++ b/packages/dapp/src/dapp-connection-manager.ts @@ -474,7 +474,9 @@ export class DappConnectionManager extends EventEmitter p.name).join(",") ?? "none"; - const supportsChunking = hdwv1?.extensions?.[EXTENSION_CHUNKED_MESSAGES] !== undefined; + const supportsChunking = + hdwv1?.extensions?.[EXTENSION_CHUNKED_MESSAGES] !== undefined; if (supportsChunking) { client.setPeerSupportsChunking(true); @@ -210,7 +230,9 @@ function handleMessage( ` dapp_discovered=${msg.dapp_discovered}` + ` protocols=[${msg.supported_protocols.join(",")}]` + ` paths=[${pathsSummary}]` + - (supportsChunking ? chalk.cyan(" chunking=✓") : chalk.dim(" chunking=✗")), + (supportsChunking + ? chalk.cyan(" chunking=✓") + : chalk.dim(" chunking=✗")), ); if (!msg.dapp_discovered) { @@ -230,7 +252,9 @@ function handleMessage( if (sendLargeSign && state.walletReady) { console.log( - chalk.dim(" (--large-sign: scheduling large sign request in 500ms...)"), + chalk.dim( + " (--large-sign: scheduling large sign request in 500ms...)", + ), ); setTimeout(() => { sendLargeSignRequest(client, state).catch(() => {}); @@ -279,9 +303,17 @@ export async function runDappMode(options: { console.log(chalk.bold("\nwiz-test dapp mode")); console.log(chalk.dim(`relay: ${options.relay}`)); if (options.sign) - console.log(chalk.yellow("--sign: will send dummy sign request after wallet is ready")); + console.log( + chalk.yellow( + "--sign: will send dummy sign request after wallet is ready", + ), + ); if (options.largeSign) - console.log(chalk.yellow("--large-sign: will send 30-contract-input sign request (chunking smoke test)")); + console.log( + chalk.yellow( + "--large-sign: will send 30-contract-input sign request (chunking smoke test)", + ), + ); console.log(); let connected = false; @@ -361,7 +393,13 @@ export async function runDappMode(options: { // Register message handler client.on("message", (message: ProtocolMessage) => { - handleMessage(message, client, state, options.sign ?? false, options.largeSign ?? false); + handleMessage( + message, + client, + state, + options.sign ?? false, + options.largeSign ?? false, + ); }); // Send initial dapp_ready diff --git a/packages/test-cli/src/wallet.ts b/packages/test-cli/src/wallet.ts index d8048fb..fd756ef 100644 --- a/packages/test-cli/src/wallet.ts +++ b/packages/test-cli/src/wallet.ts @@ -120,11 +120,14 @@ export async function runWalletMode(options: { }); manager.on("pendingSignRequest", (request) => { - const sourceCount = (request.request.transaction as any)?.sourceOutputs?.length ?? "?"; + const sourceCount = + (request.request.transaction as any)?.sourceOutputs?.length ?? "?"; const jsonSize = JSON.stringify(request.request).length; console.log( chalk.yellow("← sign_request") + - chalk.dim(` conn=${request.connectionId} seq=${request.request.sequence}`) + + chalk.dim( + ` conn=${request.connectionId} seq=${request.request.sequence}`, + ) + chalk.dim(` ${jsonSize} chars sourceOutputs=${sourceCount}`), ); console.log(chalk.dim(" (auto-rejecting — test wallet does not sign)"));