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

reactive-resume-api-client-js

v1.0.1

Published

Unofficial TypeScript/JavaScript API client (SDK) for Reactive Resume v4

Downloads

112

Readme

reactive-resume-api-client-js

npm version Node.js Version TypeScript Zero Dependencies License: MIT CI

TypeScript and JavaScript SDK for the Reactive Resume v4 API.

Built with zero runtime dependencies on standard fetch. Works across Node.js (20+), Bun, Deno, Cloudflare Workers, and modern browsers, with dual ESM and CommonJS exports and strict TypeScript declarations.


Installation

npm install reactive-resume-api-client-js
# Alternative package managers
pnpm add reactive-resume-api-client-js
yarn add reactive-resume-api-client-js
bun add reactive-resume-api-client-js

Quick Start

import { RxResumeClient } from "reactive-resume-api-client-js";

const client = new RxResumeClient({
  baseUrl: process.env.RXRESUME_BASE_URL || "https://rxresu.me",
  apiKey: process.env.RXRESUME_API_KEY,
});

async function main() {
  // 1. List user resumes
  const resumes = await client.resumes.list();
  console.log(`Found ${resumes.length} resumes.`);

  // 2. Fetch a specific resume
  const resume = await client.resumes.get(resumes[0].id);
  console.log(`Resume: ${resume.name} (Slug: ${resume.slug})`);

  // 3. Download compiled PDF bytes (Uint8Array)
  const pdfBytes = await client.resumes.downloadPdf(resume.id);
  console.log(`Downloaded ${pdfBytes.byteLength} bytes.`);
}

main().catch(console.error);

CommonJS Usage

const { RxResumeClient } = require("reactive-resume-api-client-js");

const client = new RxResumeClient({
  baseUrl: "https://rxresu.me",
  apiKey: process.env.RXRESUME_API_KEY,
});

Interactive Web Demo

An interactive browser-based dashboard demo is included under demo/web/, allowing you to explore the SDK features live in the browser with an interactive sandbox mode (no API key required) or connected to your live Reactive Resume instance.

  • GitHub Pages: Automatically deployed from demo/web via GitHub Actions
  • Run locally:
    npm run preview:demo
    Then open http://localhost:3000 in your browser.

Architecture

flowchart TB
    subgraph App["Application Layer"]
        Code["Node.js / Browser / Edge Runtime"]
    end

    subgraph SDK["RxResumeClient"]
        direction TB
        Auth["Authentication Manager<br/>(API Key / Bearer Token)"]
        Engine["Native Fetch Engine<br/>(Isomorphic · Timeout Signal · Error Mapping)"]

        subgraph Modules["Resource Modules"]
            Resumes["resumes<br/>CRUD · PDF Export · Versions"]
            Applications["applications<br/>Job Tracker · Pipelines · Tags"]
            AgentAI["agent & ai<br/>Assistant Threads · Document Parsing"]
            Telemetry["auth, statistics, flags<br/>Accounts · Metrics · Feature Flags"]
        end

        Auth --> Engine
        Engine --> Modules
    end

    subgraph API["Reactive Resume v4 Instance"]
        Endpoints["OpenAPI REST Endpoints<br/>(/api/openapi/*)"]
    end

    Code -->|Calls SDK API| SDK
    Modules -->|HTTP Requests| Endpoints

Client Configuration

RxResumeClient accepts the following configuration options:

interface RxResumeClientOptions {
  baseUrl: string;               // Base URL of your Reactive Resume instance
  apiKey?: string;              // 'x-api-key' header authentication
  token?: string;               // 'Authorization: Bearer <token>' authentication
  timeout?: number;             // Request timeout in milliseconds (default: 30000)
  fetch?: typeof fetch;         // Custom fetch implementation
  headers?: Record<string, string>; // Extra headers sent with every request
}

Dynamic Authentication

You can update authentication credentials at runtime without re-instantiating the client:

// Switch to a Bearer token (removes x-api-key)
client.setToken("jwt-token-string");

// Switch to an API key (removes Bearer token)
client.setApiKey("api-key-string");

Resource Modules

Resumes (client.resumes)

Complete management of resumes, versions, access control, and statistics.

// Listing and retrieval
const resumes = await client.resumes.list();
const resume = await client.resumes.get("resume-id");
const publicResume = await client.resumes.getPublicResume("username", "slug");

// Creation and import
const newResume = await client.resumes.create({
  title: "Software Engineer",
  basics: {
    name: "John Doe",
    email: "[email protected]",
  },
});

// Update (PATCH or PUT)
await client.resumes.update("resume-id", { name: "Updated Name" });
await client.resumes.updatePut("resume-id", fullResumeObject);

// Deletion
await client.resumes.delete("resume-id");

// Export & PDF
const pdfBytes = await client.resumes.downloadPdf("resume-id"); // Returns Uint8Array
const pdfUrl = client.resumes.getPdfUrl("resume-id");          // Direct URL string

// Password protection
await client.resumes.setPassword("resume-id", "secret");
const isValid = await client.resumes.verifyPassword("resume-id", "secret");
await client.resumes.removePassword("resume-id");

// Versions, duplication, locking
const versions = await client.resumes.getVersions("resume-id");
const duplicate = await client.resumes.duplicate("resume-id", "New Name", "new-slug");
await client.resumes.lock("resume-id", true);

// Statistics
const stats = await client.resumes.getStatistics("resume-id");
const dailyStats = await client.resumes.getDailyStatistics("resume-id", 30);
const tags = await client.resumes.tags();

Job Applications (client.applications)

Track and organize job applications, pipeline status, and tags.

// Create application entry
const app = await client.applications.create({
  company: "Acme Corp",
  position: "Senior Backend Engineer",
  stage: "Interviewing",
  summary: "Completed technical interview.",
  url: "https://acme.com/jobs/123",
});

// Query
const apps = await client.applications.list();
const appDetails = await client.applications.get(app.id);

// Pipeline statistics and tags
const stats = await client.applications.getPipelineStats();
const tags = await client.applications.listTags();

// Bulk import
await client.applications.bulkImport([
  { company: "Company A", position: "Lead Dev", stage: "Applied" },
  { company: "Company B", position: "Staff Dev", stage: "Offered" },
]);

// Delete
await client.applications.delete(app.id);

AI Agent (client.agent)

Interact with Reactive Resume's AI Assistant threads and streaming actions.

// Create a new thread
const thread = await client.agent.createThread({
  sourceResumeId: "resume-id",
});

// Send message
const response = await client.agent.sendMessage(
  thread.id,
  "Rewrite my work experience summary to highlight distributed systems."
);

// Manage attachments
await client.agent.createAttachment(
  thread.id,
  "portfolio.pdf",
  "application/pdf",
  base64Data
);

// Manage active runs
await client.agent.stopRun(thread.id);
await client.agent.archiveThread(thread.id);
await client.agent.deleteThread(thread.id);

AI Tools & Providers (client.ai, client.aiProviders)

Parse existing documents and configure custom AI provider connections.

// Parse PDF or DOCX resume into structured data
const parsedResume = await client.ai.parsePdf("cv.pdf", base64PdfData, "provider-id");
const parsedDocx = await client.ai.parseDocx("cv.docx", base64DocxData, "provider-id");

// Run AI analysis on an existing resume
const analysis = await client.ai.analyzeResume("resume-id", "provider-id");

// Configure AI Providers
const providers = await client.aiProviders.list();
const newProvider = await client.aiProviders.create({
  label: "Custom OpenAI",
  model: "gpt-4o",
  apiKey: process.env.OPENAI_API_KEY!,
});

// Test provider connection
const isWorking = await client.aiProviders.test(newProvider.id);

Statistics & Platform Flags (client.statistics, client.flags)

Global platform counters and server-side feature flags.

// Global metrics
const userCount = await client.statistics.getUsersCount();
const githubStars = await client.statistics.getGithubStars();
const resumeCount = await client.statistics.getResumesCount();

// Server feature flags
const flags = await client.flags.list();

Authentication & Account (client.auth)

const providers = await client.auth.listProviders();
const accountExport = await client.auth.exportAccount();
await client.auth.deleteAccount();

Error Handling

All HTTP errors are mapped to distinct, typed error classes inheriting from ReactiveResumeAPIError:

import {
  RxResumeClient,
  AuthenticationError,
  NotFoundError,
  ReactiveResumeAPIError,
  ReactiveResumeError,
} from "reactive-resume-api-client-js";

try {
  await client.resumes.get("invalid-id");
} catch (error) {
  if (error instanceof AuthenticationError) {
    // 401 or 403: Invalid API key or expired credentials
    console.error("Auth failed:", error.statusCode, error.message);
  } else if (error instanceof NotFoundError) {
    // 404: Resource does not exist
    console.error("Not found:", error.message);
  } else if (error instanceof ReactiveResumeAPIError) {
    // Other HTTP 4xx/5xx errors
    console.error("API Error:", error.statusCode, error.responseBody);
  } else if (error instanceof ReactiveResumeError) {
    // Network or connection failure
    console.error("Network failure:", error.message);
  }
}

Important Notes & Best Practices

  • Zero Polyfills in Modern Environments: This SDK relies exclusively on native fetch, AbortSignal, and Uint8Array. It does not import Axios or node-fetch.
  • Handling PDF Files:
    • In Node.js: The downloaded PDF is a Uint8Array. Save it directly using fs.promises.writeFile:
      import fs from "node:fs/promises";
      const pdfBytes = await client.resumes.downloadPdf("resume-id");
      await fs.writeFile("resume.pdf", pdfBytes);
    • In Browser / Client-side Apps: Convert the Uint8Array to a Blob URL for preview or download:
      const blob = new Blob([pdfBytes], { type: "application/pdf" });
      const previewUrl = URL.createObjectURL(blob);
      window.open(previewUrl);
  • Document Parsing with AI: When parsing PDFs or Word documents with client.ai.parsePdf or client.ai.parseDocx, supply the file contents as a base64-encoded string:
    import fs from "node:fs/promises";
    const buffer = await fs.readFile("resume.pdf");
    const base64Data = buffer.toString("base64");
    const parsed = await client.ai.parsePdf("resume.pdf", base64Data, "provider-id");
  • Self-Hosted Instances: Trailing slashes in baseUrl are automatically normalized (https://rx.mycompany.com/ becomes https://rx.mycompany.com).
  • Custom Environments & Proxies: If your environment requires a custom proxy agent, SSL overrides, or request logging, pass a custom fetch function into new RxResumeClient({ baseUrl, fetch: customFetch }).

Frequently Asked Questions (FAQ)

Log in to your Reactive Resume instance, go to Settings > API Keys (or your profile settings), and create a new API Key. Pass this value as apiKey to RxResumeClient.

Yes. If you have a Bearer token (such as a session JWT from Reactive Resume's auth endpoints), pass token: "your-jwt-token" in the constructor options or call client.setToken("your-jwt-token") at any time.

Yes. It is tested and verified for Node.js (20+), Bun, Deno, Cloudflare Workers, Next.js (Edge and Node runtimes), and standard browsers.

Every request respects a timeout (defaulting to 30 seconds, configurable via timeout). If a connection drops, times out, or DNS fails, a ReactiveResumeError is thrown with the message "Network or connection error occurred: ...".

Yes. All endpoints, parameters, and return types mirror reactive-resume-api-client-py. Python developers can use snake_case aliases directly (e.g., client.resumes.download_pdf).

Because the client accepts a fetch override, you can mock responses without external HTTP mocking libraries:

import { describe, it, expect, vi } from "vitest";
import { RxResumeClient } from "reactive-resume-api-client-js";

it("mocks resume fetching", async () => {
  const mockFetch = vi.fn().mockResolvedValue(
    new Response(JSON.stringify({ id: "mock-1", name: "Mock CV" }), {
      status: 200,
      headers: { "Content-Type": "application/json" },
    })
  );

  const client = new RxResumeClient({
    baseUrl: "https://rxresu.me",
    apiKey: "test",
    fetch: mockFetch,
  });

  const resume = await client.resumes.get("mock-1");
  expect(resume.name).toBe("Mock CV");
});

Contributing & Community

Contributions, feature requests, and issues are warmly welcomed!

  • Contributing Guide: Check out CONTRIBUTING.md for local setup, development commands, and PR guidelines.
  • Security Inquiries: Review our security and vulnerability disclosure policy in SECURITY.md.
  • Code of Conduct: Please follow our Code of Conduct in all community interactions.

License

MIT © Ata Can Yaymacı