/**
* JSON without losing ids.
*
* Bricks key partners by a 64-bit integer derived from a business key (`"bp_id": 45665172796086509`). JSON
* has only doubles, and `JSON.parse` rounds anything past 2^53 to the nearest double — 45665172796086509
* becomes 45665172796086510, a DIFFERENT partner, and the next request for it is a 404. Found building the CRM
* screens (2026-10-17): every bp_id the API returns is past 2^53.
*
* `quoteUnsafeIntegers` rewrites the text so every integer a double cannot hold exactly arrives as a string;
* everything else is untouched (strings are skipped, decimals and safe integers stay numbers). Use the
* value with `String(x)`, and it is exact whichever way it arrived.
*/
export function quoteUnsafeIntegers(text: string): string {
let out = "";
let i = 0;
const n = text.length;
while (i < n) {
const ch = text[i];
if (ch === '"') {
let j = i + 1;
while (j < n && text[j] !== '"') j += text[j] === "\\" ? 2 : 1;
out += text.slice(i, j + 1);
i = j + 1;
} else if (ch === "-" || (ch >= "0" && ch <= "9")) {
let j = i + 1;
while (j < n && /[0-9eE+\-.]/.test(text[j])) j++;
const token = text.slice(i, j);
out += /^-?\d+$/.test(token) && !Number.isSafeInteger(Number(token)) ? `"${token}"` : token;
i = j;
} else {
out += ch;
i++;
}
}
return out;
}
/** `JSON.parse`, with integers past 2^53 kept exactly (as strings). */
export function parseJsonLossless<T = unknown>(text: string): T {
return JSON.parse(quoteUnsafeIntegers(text)) as T;
}