import { writeFile } from 'node:fs/promises';
const BASE = 'https://api-demo.scoutworks.app/api/v1';
// The sandbox key reads a demo group. Set SCOUTWORKS_API_KEY to use your own.
const API_KEY =
process.env.SCOUTWORKS_API_KEY ??
'sw_live_473adcc6c7236916021f0f24559db36576a53bab071d0f0c08a025adb510b6ab';
/** GET one page. Waits and tries again if the rate limit is reached. */
async function get(url) {
for (;;) {
const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
const body = await res.json();
if (res.status === 429) {
await new Promise((resolve) => setTimeout(resolve, (body.retryAfter ?? 30) * 1000));
continue;
}
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
return body;
}
}
/** Every item in a list, following nextCursor to the last page. */
async function readAll(path, filters = {}) {
const url = new URL(BASE + path);
url.search = new URLSearchParams({ limit: '200', ...filters }).toString();
const items = [];
for (;;) {
const page = await get(url);
items.push(...page.data);
if (page.nextCursor === null) return items;
url.searchParams.set('cursor', page.nextCursor);
}
}
/** One CSV cell. Stops a spreadsheet running a cell that starts with = + - or @. */
function cell(value) {
let text = String(value ?? '');
if (/^\s*[=+\-@]/.test(text)) text = `'${text}`;
return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
}
const entries = await readAll('/waiting-list', { status: 'received' });
const rows = [
['First name', 'Last name', 'Section', 'Position', 'Applied'],
...entries.map((w) => [
w.firstName,
w.lastName,
w.targetSection?.name,
w.position,
w.appliedAt.slice(0, 10),
]),
];
await writeFile('waiting-list.csv', rows.map((r) => r.map(cell).join(',')).join('\r\n') + '\r\n');
console.log(`Saved ${entries.length} applications to waiting-list.csv`);