npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 fetch and FormData)
  • A service account API key (starts with sk_live_)

Installation

npm install @log10/everest-sdk
# or
pnpm add @log10/everest-sdk

Quick 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);