Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,35 +178,48 @@ interface SoloditResponse {
async function callSoloditAPI(body: SoloditRequest): Promise<SoloditResponse> {
await rateLimiter.waitIfNeeded();

const res = await fetch(`${API_BASE}/findings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Cyfrin-API-Key": API_KEY!,
},
body: JSON.stringify(body),
});

rateLimiter.update(res.headers);

if (!res.ok) {
const errBody = await res.text();
if (res.status === 401) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000); // 30s timeout

try {
const res = await fetch(`${API_BASE}/findings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Cyfrin-API-Key": API_KEY!,
},
body: JSON.stringify(body),
signal: controller.signal,
});

clearTimeout(timeoutId);
rateLimiter.update(res.headers);

if (!res.ok) {
const errBody = await res.text();
if (res.status === 401) {
throw new Error(
`Invalid API key. Get a new one at: https://solodit.cyfrin.io → Profile → API Keys`
);
}
if (res.status === 429) {
throw new Error(
`Rate limited. Limit resets at ${new Date(rateLimiter.status().resetAt).toISOString()}. Try again shortly.`
);
}
throw new Error(
`Invalid API key. Get a new one at: https://solodit.cyfrin.io → Profile → API Keys`
`Solodit API error (${res.status}): ${errBody.slice(0, 200)}`
);
}
if (res.status === 429) {
throw new Error(
`Rate limited. Limit resets at ${new Date(rateLimiter.status().resetAt).toISOString()}. Try again shortly.`
);

return (await res.json()) as SoloditResponse;
} catch (error: any) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('Request timeout - Solodit API did not respond within 30 seconds');
}
throw new Error(
`Solodit API error (${res.status}): ${errBody.slice(0, 200)}`
);
throw error;
}

return (await res.json()) as SoloditResponse;
}

// ── Formatters ──────────────────────────────────────────────────────────────
Expand Down