diff --git a/apps/indexer/src/rpc.ts b/apps/indexer/src/rpc.ts index c3981ff..17df081 100644 --- a/apps/indexer/src/rpc.ts +++ b/apps/indexer/src/rpc.ts @@ -8,6 +8,60 @@ type JsonRpcEnvelope = { }; }; +function escapeControlCharactersInStrings(payload: string): string { + let result = ""; + let inString = false; + let escaping = false; + + for (let index = 0; index < payload.length; index += 1) { + const char = payload[index]; + + if (!inString) { + if (char === "\"") { + inString = true; + } + result += char; + continue; + } + + if (escaping) { + result += char; + escaping = false; + continue; + } + + if (char === "\\") { + result += char; + escaping = true; + continue; + } + + if (char === "\"") { + result += char; + inString = false; + continue; + } + + const code = char.charCodeAt(0); + if (code <= 0x1f) { + result += `\\u${code.toString(16).padStart(4, "0")}`; + continue; + } + + result += char; + } + + return result; +} + +function parseRpcPayload(payload: string): T { + try { + return JSON.parse(payload) as T; + } catch { + return JSON.parse(escapeControlCharactersInStrings(payload)) as T; + } +} + export type RpcBlockHeader = { hash: string; height: number; @@ -94,7 +148,7 @@ export class PeyaRpcClient { throw new Error(`RPC ${method} failed with HTTP ${response.status}`); } - const payload = (await response.json()) as JsonRpcEnvelope; + const payload = parseRpcPayload>(await response.text()); if (payload.error) { throw new Error(`RPC ${method} failed: ${payload.error.code} ${payload.error.message}`); } @@ -109,7 +163,7 @@ export class PeyaRpcClient { if (!response.ok) { throw new Error(`GET /getheight failed with HTTP ${response.status}`); } - return (await response.json()) as RpcGetHeightResult; + return parseRpcPayload(await response.text()); } async getBlock(height: number): Promise { @@ -135,7 +189,7 @@ export class PeyaRpcClient { if (!response.ok) { throw new Error(`POST /gettransactions failed with HTTP ${response.status}`); } - return (await response.json()) as RpcGetTransactionsResult; + return parseRpcPayload(await response.text()); } async getYieldInfo(fromHeight: number, toHeight: number): Promise {