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

@vegacap/node

v0.1.0

Published

VegaCap Node.js SDK — typed server-side client for the VegaCap Platform API

Readme

@vegacap/node

Typed TypeScript server SDK for the VegaCap Platform API.

Create assessment sessions, fetch results, manage webhook endpoints, download PDF reports, and verify incoming webhook signatures — all with end-to-end types and typed errors.

  • Native fetch, no axios. Node.js 18 or newer.
  • Typed errors — every error code has its own instanceof-friendly class.
  • Automatic retries — 5xx retried once, 429 honours Retry-After.
  • Webhook verification without spinning up a client instance.

Install

npm install @vegacap/node
# or
bun add @vegacap/node
# or
pnpm add @vegacap/node

Quickstart

import { VegaCap } from '@vegacap/node';

const vc = new VegaCap({
  apiKey: process.env.VEGACAP_SECRET_KEY!, // vegacap_sk_live_...
});

const session = await vc.sessions.create({
  assessmentType: 'disc',
  candidate: {
    externalId: 'user_42',
    email: '[email protected]',
    name: 'Alice',
  },
  metadata: { campaign: 'Q2-hiring' },
});

// Redirect your candidate to this URL to take the assessment.
console.log(session.assessmentUrl);

Configuration

new VegaCap({
  apiKey: process.env.VEGACAP_SECRET_KEY!,
  baseUrl: 'https://vegacapltd.com/api/v1', // default
  timeout: 30_000,                          // ms, default 30s
  fetch: myFetchOverride,                   // optional (testing/proxies)
});

The SDK emits User-Agent: @vegacap/node/<version> on every request.


Resources

Sessions

// Create a session (returns an `assessmentUrl` you redirect candidates to).
const session = await vc.sessions.create(
  {
    assessmentType: 'disc',
    candidate: { externalId: 'user_42', email: '[email protected]' },
    metadata: { campaign: 'Q2-hiring' },
  },
  { idempotencyKey: 'req_create_user_42_disc' },
);

// Retrieve a session by ID (includes results + signed reportUrl once complete).
const result = await vc.sessions.retrieve(session.id);
if (result.status === 'completed') {
  console.log(result.results);
  console.log(result.reportUrl); // short-lived signed URL
}

// List sessions, newest first. `cursor` is a numeric offset.
const page1 = await vc.sessions.list({
  status: 'completed',
  assessmentType: 'disc',
  limit: 20,
});

const page2 = await vc.sessions.list({
  limit: 20,
  cursor: page1.offset + page1.data.length,
});

// Server-to-server submissions (embed iframe submits on its own).
await vc.sessions.submit(session.id, {
  responses: { /* per-assessment payload */ },
  language: 'en',
});

// Cancel before completion.
await vc.sessions.cancel(session.id);

About cursor: the API is currently offset-based. The SDK accepts cursor as a number or numeric string for forward compatibility and passes it as offset on the wire. Read the returned offset/total/limit to paginate.

Organization

// Returns the org tied to your API key, including license counts.
const me = await vc.organizations.me();
console.log(me.slug, me.assessments);

Webhook endpoints

// Create an endpoint. The `secret` is returned ONCE — store it securely.
const endpoint = await vc.webhooks.endpoints.create({
  url: 'https://hooks.acme.com/vegacap',
  events: ['session.completed', 'session.failed'],
  description: 'Prod webhook',
});

console.log(endpoint.secret); // whsec_...

// List, retrieve, update, delete.
const { data } = await vc.webhooks.endpoints.list();
const single    = await vc.webhooks.endpoints.retrieve(endpoint.id);
await vc.webhooks.endpoints.delete(endpoint.id);

Reports

import { createWriteStream } from 'node:fs';
import { Writable } from 'node:stream';

const stream = await vc.reports.downloadPdf(session.id); // ReadableStream<Uint8Array>

// Pipe straight to disk without buffering the whole PDF.
await stream.pipeTo(Writable.toWeb(createWriteStream('./report.pdf')));

The method returns a native ReadableStream<Uint8Array> so you can pipe it to a file, an HTTP response, or an S3 upload without ever materialising the full PDF in memory.


Webhook signature verification

Every delivery from VegaCap includes an X-VegaCap-Signature header of the form sha256=<hex>, computed as HMAC_SHA256(webhook_secret, raw_body).

VegaCap.webhooks.verify(...) is static — no client instance required.

import express from 'express';
import { VegaCap } from '@vegacap/node';

const app = express();

// IMPORTANT: the verifier operates on the RAW body, so capture bytes BEFORE
// any JSON parser touches them.
app.post(
  '/webhooks/vegacap',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.header('x-vegacap-signature') ?? '';
    const valid = VegaCap.webhooks.verify(
      req.body as Buffer,           // raw bytes
      signature,
      process.env.VEGACAP_WEBHOOK_SECRET!,
    );
    if (!valid) return res.status(400).send('invalid signature');

    const event = JSON.parse((req.body as Buffer).toString('utf8'));
    // Handle `session.completed`, `session.failed`, etc.
    res.status(200).send('ok');
  },
);

Next.js Route Handler example:

// app/api/webhooks/vegacap/route.ts
import { VegaCap } from '@vegacap/node';

export async function POST(req: Request): Promise<Response> {
  const raw = await req.text(); // raw string, unparsed
  const signature = req.headers.get('x-vegacap-signature') ?? '';

  const valid = VegaCap.webhooks.verify(
    raw,
    signature,
    process.env.VEGACAP_WEBHOOK_SECRET!,
  );
  if (!valid) return new Response('invalid signature', { status: 400 });

  const event = JSON.parse(raw);
  // ...
  return new Response('ok');
}

Errors

Every non-2xx response throws a subclass of VegaCapError:

import {
  VegaCap,
  VegaCapError,
  NoAvailableLicensesError,
  RateLimitedError,
  ValidationError,
} from '@vegacap/node';

try {
  await vc.sessions.create({ /* ... */ });
} catch (err) {
  if (err instanceof NoAvailableLicensesError) {
    // Nudge billing, surface a friendly UI message, etc.
    return;
  }
  if (err instanceof RateLimitedError) {
    console.log(`retry after ${err.retryAfter}s`);
    return;
  }
  if (err instanceof ValidationError) {
    console.log('details:', err.details);
    return;
  }
  if (err instanceof VegaCapError) {
    console.log(err.code, err.status, err.requestId);
  }
  throw err;
}

Each error carries:

| Field | Description | |--------------|-------------------------------------------------------| | code | Machine-readable code (e.g. "invalid_api_key"). | | status | HTTP status. | | message | Human-readable message from the API. | | details | Per-field validation issues (when present). | | requestId | X-Request-Id echoed by the API, useful in support. | | docUrl | Link to the matching docs entry. | | retryAfter | Seconds (429 only). |

Available subclasses:

InvalidApiKeyError, ExpiredApiKeyError, RevokedApiKeyError, InsufficientPermissionsError, InvalidSessionTokenError, SessionNotFoundError, SessionExpiredError, SessionAlreadyCompletedError, InvalidAssessmentTypeError, AssessmentNotEnabledError, NoAvailableLicensesError, WebhookNotFoundError, InvalidWebhookUrlError, RateLimitedError, ValidationError, IdempotencyConflictError, InternalServerError, NotImplementedError, ScoringError, PdfGenerationFailedError.

All codes are also exported as API_ERROR_CODES for when you want to branch on a string instead of an instanceof check.


Retries

  • 5xx: one retry after 500 ms.
  • 429: one retry after the server's Retry-After header (capped at 60 s).
  • 4xx: never retried.

If the retry also fails, the final response is thrown as usual.


Idempotency

Pass an Idempotency-Key to sessions.create to make retries safe:

await vc.sessions.create(params, { idempotencyKey: 'order_42:disc' });

Retrying with the same key returns the original session; retrying with a different body returns IdempotencyConflictError.


TypeScript

The SDK ships with full types — including shared request/response shapes, assessment types, webhook events, session statuses, and the error catalog. Import them directly:

import type {
  AssessmentType,
  WebhookEvent,
  SessionStatus,
  SessionResponse,
  SessionResultResponse,
  CreateSessionParams,
} from '@vegacap/node';

License

Apache-2.0