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

@expunct/sdk

v0.1.1

Published

Node.js SDK for the Expunct PII redaction API

Downloads

28

Readme

@expunct/sdk

Privacy infrastructure for modern applications. Detect and redact PII, secrets, and sensitive data before it reaches AI, logs, or external APIs.

npm version TypeScript License: MIT

Installation

npm install @expunct/sdk
# or
yarn add @expunct/sdk

Get your API key at expunct.ai — free tier includes 1M tokens/month, no credit card required.

Quick Start

import { Expunct } from "@expunct/sdk";

const client = new Expunct({ apiKey: "your-api-key" });

const redacted = await client.sanitizeText(
  "Hi, I'm Jane Doe. Reach me at [email protected] or (555) 867-5309."
);

console.log(redacted);
// Output: Hi, I'm PERSON_1. Reach me at EMAIL_ADDRESS_1 or PHONE_NUMBER_1.

Usage

Text redaction

sanitizeText is the simplest path: pass a string, get back a redacted string. It handles file upload, job polling, and result download automatically.

import { Expunct } from "@expunct/sdk";

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

const result = await client.sanitizeText(
  "SSN: 123-45-6789, card: 4111 1111 1111 1111"
);
console.log(result);
// SSN: US_SSN_1, card: CREDIT_CARD_1

File redaction

sanitizeFile accepts a Blob or Node.js Buffer and returns the redacted content as raw bytes. Useful for PDFs, DOCX files, or any binary format supported by the API.

import { Expunct } from "@expunct/sdk";
import { readFileSync, writeFileSync } from "fs";

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

const inputBuffer = readFileSync("./document.pdf");
const redactedBytes = await client.sanitizeFile(inputBuffer, {
  filename: "document.pdf",
});

writeFileSync("./document-redacted.pdf", redactedBytes);

URI redaction

sanitizeUri submits a remote file by URI (e.g. a signed S3 URL), polls until the job completes, and returns the full JobDetailResponse including all detected findings.

import { Expunct } from "@expunct/sdk";

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

const job = await client.sanitizeUri(
  "https://my-bucket.s3.amazonaws.com/sensitive-report.txt?..."
);

console.log(`Found ${job.findings_count} PII entities`);
console.log(job.findings);
// [{ entity_type: "EMAIL_ADDRESS", entity_value: "[email protected]", confidence: 0.99 }, ...]

Batch URI redaction

Submit multiple URIs in one call. Returns a BatchJobResponse with individual job IDs you can track separately.

import { Expunct } from "@expunct/sdk";

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

const batch = await client.redact.batch([
  "s3://bucket/file1.txt",
  "s3://bucket/file2.txt",
  "s3://bucket/file3.txt",
]);

console.log(`Batch ${batch.id}: ${batch.total_jobs} jobs submitted`);
// Poll individual jobs via batch.job_ids

Environment variable

If EXPUNCT_API_KEY is set in your environment, you can pass it directly:

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

Custom redaction config

Pass a config object to any sanitize* method to control which entity types to detect and how to redact them:

const result = await client.sanitizeText(
  "Dr. Smith at UCSF called: (415) 555-0100",
  {
    config: {
      pii_types: ["PERSON", "PHONE_NUMBER"],
      redaction_method: "replace",   // "replace" | "mask" | "hash"
      confidence_threshold: 0.7,
      preserve_labels: true,
    },
  }
);

Custom policy

Policies let you save and reuse redaction configurations. Create a policy once and reference it by ID:

// Create a policy
const policy = await client.policies.create({
  name: "strict-hipaa",
  pii_types: ["PERSON", "EMAIL_ADDRESS", "PHONE_NUMBER", "US_SSN", "DATE_TIME"],
  redaction_method: "replace",
  confidence_threshold: 0.6,
  is_default: false,
});

// Use the policy by ID in redaction calls
const result = await client.sanitizeText(
  "Patient John Doe, DOB 01/15/1980, SSN 123-45-6789",
  { policy_id: policy.id }
);

Manual job control

For fine-grained control, use the redact and jobs resources directly:

import { Expunct } from "@expunct/sdk";

const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });

// Submit a file upload job
const job = await client.redact.file(fileBlob, {
  filename: "report.txt",
  language: "en",
});

console.log(`Job ${job.id} submitted, status: ${job.status}`);

// Poll until complete
const completed = await client.waitForJob(job.id, {
  interval: 1000,   // poll every 1s
  timeout: 60_000,  // give up after 60s
});

// Download the redacted bytes
const bytes = await client.jobs.download(completed.id);

// Or get the full redaction report
const report = await client.jobs.report(completed.id);

List and inspect jobs

// List recent jobs (paginated)
const { jobs, total } = await client.jobs.list({
  page: 1,
  page_size: 20,
  status: "completed",
});

// Get a specific job
const job = await client.jobs.get("job-uuid-here");
console.log(job.findings);

Audit logs

const logs = await client.audit.list({
  event_type: "redact",
  page: 1,
  page_size: 50,
});

API key management

// List all keys
const keys = await client.apiKeys.list();

// Create a new key
const newKey = await client.apiKeys.create({ name: "ci-pipeline" });
console.log(newKey.key); // plaintext — only shown once

// Revoke a key
await client.apiKeys.revoke(newKey.id);

Error handling

All errors extend ApiError. Import the specific classes you need:

import {
  Expunct,
  AuthenticationError,
  RateLimitError,
  ValidationError,
  NotFoundError,
  PollingTimeoutError,
} from "@expunct/sdk";

try {
  const result = await client.sanitizeText("...");
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error("Invalid API key");
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${err.retryAfter}s`);
  } else if (err instanceof PollingTimeoutError) {
    console.error(`Job ${err.jobId} timed out after ${err.timeout}ms`);
  } else if (err instanceof ValidationError) {
    console.error("Bad request:", err.message);
  }
}

Client configuration

const client = new Expunct({
  apiKey: "your-api-key",       // required
  baseUrl: "https://api.expunct.ai",  // optional, default shown
  tenantId: "your-tenant-id",   // optional, for multi-tenant setups
  timeout: 30_000,              // optional, request timeout in ms (default 30s)
  maxRetries: 3,                // optional, retries on network errors + 429s (default 3)
});

Detected Entity Types

The following entity types are detected by default (and can be targeted individually via pii_types):

| Type | Description | |------|-------------| | PERSON | Full names | | EMAIL_ADDRESS | Email addresses | | PHONE_NUMBER | Phone numbers | | LOCATION | Physical addresses, cities, countries | | DATE_TIME | Dates and times | | US_SSN | US Social Security numbers | | CREDIT_CARD | Credit/debit card numbers | | IP_ADDRESS | IPv4 and IPv6 addresses | | URL | Web URLs | | ORGANIZATION | Company and organization names | | IBAN_CODE | International bank account numbers | | US_PASSPORT | US passport numbers | | US_DRIVER_LICENSE | US driver's license numbers | | CRYPTO | Cryptocurrency wallet addresses | | MEDICAL_LICENSE | Medical license numbers | | NRP | Nationality, religion, political affiliation |

Redaction Methods

| Method | Description | Example | |--------|-------------|---------| | replace | Replace with labeled placeholder (default) | PERSON_1 | | mask | Replace characters with * | **** | | hash | Replace with a SHA-256 hash | a3f2c1... |

Requirements

  • Node.js 18+
  • Zero runtime dependencies

Links

License

MIT