/** * Regenerates src/endpoints.ts from the live Clarizen API docs. * Requires CLARIZEN_API_KEY (or API_KEY_AW) in .env for Accept: text/html. */ import { writeFileSync } from "node:fs"; import { resolve } from "node:path"; const baseUrl = process.env.CLARIZEN_BASE_URL ?? "https://api.clarizen.com"; const apiKey = process.env.CLARIZEN_API_KEY ?? process.env.API_KEY_AW; if (!apiKey) { console.error("Set CLARIZEN_API_KEY or API_KEY_AW"); process.exit(1); } const indexRes = await fetch(`${baseUrl}/V2.0/services/`, { headers: { Authorization: `ApiKey ${apiKey}`, Accept: "text/html", }, }); const html = await indexRes.text(); const linkRe = /href="(\/V2\.0\/services\/[^"]+)"/g; const paths = [...new Set([...html.matchAll(linkRe)].map((m) => m[1]))].filter( (p) => !p.endsWith("/objects"), ); const endpoints: Array<{ namespace: string; operation: string; path: string; httpMethods: string[]; description: string; }> = []; for (const docPath of paths) { const res = await fetch(`${baseUrl}${docPath}`, { headers: { Authorization: `ApiKey ${apiKey}`, Accept: "text/html", }, }); const page = await res.text(); const parts = docPath.split("/"); const namespace = parts[3] ?? ""; const operation = parts[4] ?? ""; const pathMatch = page.match(/([^<]+)<\/samp>/); const methodMatch = page.match( /
HTTP Method<\/dt>\s*
([^<]+)<\/code>/, ); const descMatch = page.match(/
Description<\/dt>\s*
([^<]+)/); endpoints.push({ namespace, operation, path: pathMatch?.[1] ?? docPath, httpMethods: (methodMatch?.[1] ?? "POST") .split(",") .map((m) => m.trim().toUpperCase()), description: (descMatch?.[1] ?? "") .replace(/\u00a0/g, " ") .trim(), }); } const namespaces = [...new Set(endpoints.map((e) => e.namespace))]; const out = `import type { EndpointDefinition } from "./types.js"; /** Auto-generated from ${baseUrl}/V2.0/services/ — run: npm run scrape */ export const ENDPOINTS: EndpointDefinition[] = ${JSON.stringify(endpoints, null, 2)}; export const NAMESPACES = ${JSON.stringify(namespaces, null, 2)} as const; export type ClarizenNamespace = (typeof NAMESPACES)[number]; `; const target = resolve(import.meta.dirname, "../src/endpoints.ts"); writeFileSync(target, out); console.log(`Wrote ${endpoints.length} endpoints to ${target}`);