import { gzipSync } from 'zlib';
let _cachedToken = null;
let _tokenExpiresAt = 0;
async function getAccessToken() {
const now = Math.floor(Date.now() / 1000);
if (_cachedToken && now < _tokenExpiresAt - 60) return _cachedToken;
const res = await fetch(TOKEN_URL, {
method: "POST",
headers: {
"Authorization": "Basic " + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64"),
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials&scope=billreview%3Awrite",
});
if (!res.ok) throw new Error(`Token request failed: ${res.status}`);
const data = await res.json();
_cachedToken = data.access_token;
_tokenExpiresAt = Math.floor(Date.now() / 1000) + (data.expires_in ?? 3600);
return _cachedToken;
}
async function reviewBill(billPayload) {
const compressed = gzipSync(Buffer.from(JSON.stringify(billPayload)));
const post = async (token) => fetch(`${API_ENDPOINT}/v1/review`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"x-api-key": API_KEY,
"Content-Type": "application/json",
"Content-Encoding": "gzip",
},
body: compressed,
});
let res = await post(await getAccessToken());
if (res.status === 401) {
_cachedToken = null; // invalidate and retry once
res = await post(await getAccessToken());
}
if (!res.ok) throw new Error(`Review failed: ${res.status}`);
return res.json();
}