@log10/everest-sdk
v0.1.0
Published
TypeScript SDK for the Everest API
Readme
@log10/everest-sdk
TypeScript SDK for the Everest API. Provides first-class support for uploading input documents and downloading report exports — the two operations that are most painful to do directly against the raw GraphQL API.
Requirements
- Node.js 18+ (uses native
fetchandFormData) - A service account API key (starts with
sk_live_)
Installation
npm install @log10/everest-sdk
# or
pnpm add @log10/everest-sdkQuick start
import { EverestClient } from '@log10/everest-sdk';
import { readFile, writeFile } from 'fs/promises';
const client = new EverestClient({
apiKey: process.env.EVEREST_API_KEY!,
workspaceId: process.env.EVEREST_WORKSPACE_ID!,
});
// Upload a file
const buf = await readFile('./data.pdf');
const [doc] = await client.files.upload([{ name: 'data.pdf', content: buf, type: 'application/pdf' }]);
console.log('Uploaded:', doc.id);
// Download a report as PDF
const reports = await client.reports.list();
const latest = reports[0];
const gen = latest.latestGeneration!;
// You need both the generation ID and a revision ID.
// Revisions are listed via the full report query — see "Advanced" below.
const pdf = await client.reports.download(gen.id, '<revision-id>', { format: 'pdf' });
await writeFile('./report.pdf', pdf);Authentication
Create a service account in the Everest workspace settings and copy its API key. Store the key in an environment variable — never hard-code it.
const client = new EverestClient({
apiKey: process.env.EVEREST_API_KEY!, // sk_live_...
workspaceId: process.env.EVEREST_WORKSPACE_ID!,
});Files
Upload
Upload one or more files. Returns the created InputDocument records.
// From a Buffer (Node.js)
import { readFile } from 'fs/promises';
const buf = await readFile('./report.pdf');
const [doc] = await client.files.upload([
{ name: 'report.pdf', content: buf, type: 'application/pdf' },
]);
// Multiple files at once
const docs = await client.files.upload([
{ name: 'q1.pdf', content: q1Buf },
{ name: 'q2.pdf', content: q2Buf },
]);
// From a browser File object
const [doc] = await client.files.upload([fileInputElement.files[0]]);
// Attach tags on upload
const [doc] = await client.files.upload([{ name: 'data.csv', content: buf }], {
tagIds: ['tag_abc'],
});List
// All files
const files = await client.files.list();
// Filter by name
const reports = await client.files.list({ name: 'Q4' });
// Sort
const newest = await client.files.list({ sort: 'createdAt', order: 'desc' });Download
// Get a short-lived signed URL (valid for 10 minutes)
const url = await client.files.getDownloadUrl('doc_abc');
// Or download directly to a Uint8Array
const bytes = await client.files.download('doc_abc');
await writeFile('./downloaded.pdf', bytes);Delete
await client.files.delete(['doc_abc', 'doc_def']);Reports
List
const reports = await client.reports.list();
// Search by name
const q4 = await client.reports.list({ search: 'Q4 2024' });
// Filter by template
const filtered = await client.reports.list({ templateIds: ['tmpl_abc'] });Download as PDF or Markdown
getDownloadUrl returns a 10-minute signed URL. download fetches it and
returns a Uint8Array.
// Get a signed URL
const url = await client.reports.getDownloadUrl(generationId, revisionId, { format: 'pdf' });
// Download directly
const pdfBytes = await client.reports.download(generationId, revisionId, { format: 'pdf' });
const mdBytes = await client.reports.download(generationId, revisionId, { format: 'md' });
await writeFile('./report.pdf', pdfBytes);Export as DOCX
DOCX export is an asynchronous server-side render job. The SDK starts the job, polls until it completes, and returns the file bytes.
You must supply the report content as Markdown. The easiest way is to download
it first with format: 'md':
// 1. Get the markdown content of the revision
const mdUrl = await client.reports.getDownloadUrl(generationId, revisionId, { format: 'md' });
const markdown = await fetch(mdUrl).then((r) => r.text());
// 2. Export as DOCX (SDK handles polling automatically)
const docxBytes = await client.reports.exportAsDocx(generationId, markdown);
await writeFile('./report.docx', docxBytes);Optional formatting options:
const docxBytes = await client.reports.exportAsDocx(generationId, markdown, {
includeToc: true, // table of contents
includeTof: true, // table of figures
includeTot: true, // table of tables
autoNumberHeadings: true, // 1.1, 1.2, ...
stripHeadingNumbering: false,
sectionCaptions: true,
tabCaptionSeparator: true,
styleTemplateOverrideId: 'style_xyz',
});Advanced: finding revision IDs
The download and getDownloadUrl methods require a reportGenerationRevisionId.
Revisions are nested under report generations. Until the SDK exposes a dedicated
query for this, you can reach them via a raw GraphQL query:
// This is a workaround until a first-class revisions API is added.
// Fetch the full report with its revisions and pick the latest.
const reports = await client.reports.list();
// latestGeneration is included, but revisions require a deeper query.
// For now, store revision IDs from the Everest UI or use the revisions
// returned by your report generation workflow.The SDK will add a client.reports.getRevisions(generationId) helper in a
future release.
Error handling
All methods throw EverestAPIError for GraphQL-level errors:
import { EverestAPIError } from '@log10/everest-sdk';
try {
await client.files.upload([{ name: 'data.pdf', content: buf }]);
} catch (err) {
if (err instanceof EverestAPIError) {
console.error('API error:', err.message);
console.error('Details:', err.errors);
}
}Configuration
const client = new EverestClient({
apiKey: 'sk_live_...',
workspaceId: 'ws_...',
// Optional
baseUrl: 'https://api.log10.io', // defaults to production
exportTimeoutMs: 300_000, // 5 min — how long to wait for DOCX exports
exportPollIntervalMs: 2_000, // 2 s — how often to poll for export status
});Complete example: upload → export
import { EverestClient } from '@log10/everest-sdk';
import { readFile, writeFile } from 'fs/promises';
const client = new EverestClient({
apiKey: process.env.EVEREST_API_KEY!,
workspaceId: process.env.EVEREST_WORKSPACE_ID!,
});
async function main() {
// 1. Upload source documents
const rawData = await readFile('./raw-data.pdf');
const [uploadedDoc] = await client.files.upload([
{ name: 'raw-data.pdf', content: rawData, type: 'application/pdf' },
]);
console.log(`Uploaded: ${uploadedDoc.id}`);
// 2. List reports and find the one we want to export
const reports = await client.reports.list({ search: 'Monthly Report' });
const report = reports[0];
if (!report?.latestGeneration?.completedAt) {
throw new Error('No completed generation found');
}
const generationId = report.latestGeneration.id;
// revisionId comes from your report generation workflow
const revisionId = '<revision-id>';
// 3. Download as PDF
const pdf = await client.reports.download(generationId, revisionId, { format: 'pdf' });
await writeFile('./report.pdf', pdf);
console.log('PDF saved.');
// 4. Export as DOCX
const mdUrl = await client.reports.getDownloadUrl(generationId, revisionId, { format: 'md' });
const markdown = await fetch(mdUrl).then((r) => r.text());
const docx = await client.reports.exportAsDocx(generationId, markdown, { includeToc: true });
await writeFile('./report.docx', docx);
console.log('DOCX saved.');
}
main().catch(console.error);