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

pii-guard-node-mini

v1.0.1

Published

Single-file Node.js/TypeScript PII masking engine (detect + mask + optional tokenization)

Downloads

290

Readme

PII Masker (single-file TypeScript utility)

A self-contained, dependency-free (runtime) PII/secret detection + masking engine designed to be copied directly into other Node.js/TypeScript projects.

What this is for

  • Mask PII before sending text to LLMs, logs, telemetry, or analytics.
  • Detect and transform common PII/secrets using regex + lightweight validation/heuristics.
  • Provide configurable masking strategies per PII type.
  • Optionally use tokenization for same-instance reversible masking (useful for round-tripping LLM responses).

Install / Add to your project

This asset is intentionally shipped as a single file.

Option A — copy the file

  1. Copy pii-masker.ts into your project (e.g. src/utils/pii-masker.ts).

  2. If your project uses TypeScript, make sure Node types are available:

npm i -D @types/node

This file uses Node APIs (crypto, Buffer). It’s meant for Node.js runtimes (or bundlers configured to polyfill Node APIs).

Option B — install from npm

npm i pii-guard-node-mini

If you copied the file instead of installing from npm, replace import paths like "pii-guard-node-mini" with your local path (e.g. "./utils/pii-masker").


Quick start

import createPIIMasker, { PIIType, MaskingStrategy } from "pii-guard-node-mini";

const masker = createPIIMasker({
  preset: "balanced",
  logLevel: "silent",
  strategies: {
    [PIIType.CREDIT_CARD]: MaskingStrategy.REDACT,
  },
});

const input = "Email me at [email protected]. Card: 4111 1111 1111 1111";
const { maskedText, entities } = masker.mask(input);

console.log(maskedText);
console.log(entities);

API overview

createPIIMasker(userConfig?) returns an object with:

  • mask(text){ maskedText, entities, maskMap } (may also include warnings / truncated)
  • maskObject(obj, fieldPaths?){ masked, entities, maskMap } (may include warnings)
  • detect(text)DetectedEntity[]
  • unmask(text)string (only meaningful with tokenization + reversibility enabled)
  • addDetector(type, fn) → register custom detector
  • addStrategy(name, fn) → register custom strategy
  • updateConfig(partial) → hot-update instance config
  • getReport() → basic usage metrics
  • clearVault() → clears token vault (affects unmask)
  • resetReport() → clears counters
  • getConfig() → resolved config snapshot

Presets

Presets pre-configure detectors + defaults.

const strict = createPIIMasker({ preset: "strict" });
const balanced = createPIIMasker({ preset: "balanced" });
const minimal = createPIIMasker({ preset: "minimal" });
const hipaa = createPIIMasker({ preset: "hipaa" });
const pci = createPIIMasker({ preset: "pci-dss" });

Notes:

  • Preset values can still be overridden by passing your own config fields.
  • “HIPAA” / “PCI-DSS” preset names are practical bundles; you should still validate your usage for your environment.

Configuration (EngineConfig)

You pass a Partial<EngineConfig> to createPIIMasker().

Common knobs:

Production/enterprise recommended defaults

By default, results include entities (with original values) and maskMap (original → masked). In production pipelines this can accidentally re-introduce sensitive data into logs.

Recommended configuration:

import createPIIMasker, { MaskingStrategy } from "pii-guard-node-mini";

const masker = createPIIMasker({
  preset: "balanced",

  // Output controls (recommended for production)
  includeMaskMap: false,
  includeEntities: true,
  entityValueMode: "none", // don't return raw matches
  includeMaskedValueInEntities: true, // safe to include the replacement

  // Safety limits
  maxTextLength: 200_000,
  maxEntities: 2_000,
  onLimitExceeded: "truncate", // or "throw" if you prefer hard-fail

  // Recommended for LLM flows
  defaultStrategy: MaskingStrategy.REDACT,
});

Notes:

  • If you set entityValueMode: "none", DetectedEntity.value becomes an empty string.
  • If you need original values for debugging, enable them only in dev/test.

Output controls (data minimization)

These options are designed to prevent accidental re-introduction of sensitive data via outputs.

  • includeMaskMap: if true, maskMap contains original → masked mappings.
  • includeEntities: if false, entities will be an empty list.
  • entityValueMode:
    • "original" (default): DetectedEntity.value is the raw match.
    • "masked": DetectedEntity.value becomes the replacement value.
    • "none": DetectedEntity.value becomes an empty string.
  • includeMaskedValueInEntities: includes DetectedEntity.masked (the replacement) in the entity.

Example (mask safely, keep entity locations/types only):

const masker = createPIIMasker({
  includeMaskMap: false,
  includeEntities: true,
  entityValueMode: "none",
  includeMaskedValueInEntities: false,
});

confidenceThreshold

Higher means fewer matches (less false positives), lower means more aggressive masking.

const masker = createPIIMasker({ confidenceThreshold: 0.7 });

defaultStrategy and strategies

Set the global default masking behavior, and override per type.

import { MaskingStrategy, PIIType } from "pii-guard-node-mini";

const masker = createPIIMasker({
  defaultStrategy: MaskingStrategy.PARTIAL_MASK,
  strategies: {
    [PIIType.SSN]: MaskingStrategy.REDACT,
    [PIIType.CREDIT_CARD]: MaskingStrategy.REDACT,
    [PIIType.API_KEY]: MaskingStrategy.REDACT,
  },
});

allowList

Values that should not be masked even if they look like PII.

const masker = createPIIMasker({
  allowList: ["example.com", "localhost"],
});

denyList

Terms that must always be masked.

const masker = createPIIMasker({
  denyList: [
    { term: "ProjectX", type: "CUSTOM" },
    { term: "InternalCodeWord", type: "CUSTOM" },
  ],
});

detectorsEnabled

Run only a subset of detectors.

import { PIIType } from "pii-guard-node-mini";

const masker = createPIIMasker({
  detectorsEnabled: new Set([PIIType.EMAIL, PIIType.PHONE]),
});

locale

Affects some patterns/heuristics.

const maskerUS = createPIIMasker({ locale: "US" });
const maskerUK = createPIIMasker({ locale: "UK" });
const maskerIN = createPIIMasker({ locale: "IN" });

hashSalt

Only used by HASH strategy.

const masker = createPIIMasker({
  defaultStrategy: "HASH",
  hashSalt: "your-app-specific-salt",
});

Limits: maxTextLength, maxEntities, onLimitExceeded

These controls are designed for untrusted inputs (logs, user text, LLM output) to prevent worst-case performance.

const masker = createPIIMasker({
  maxTextLength: 100_000,
  maxEntities: 1_000,
  onLimitExceeded: "truncate", // or "throw"
});

const res = masker.mask(veryLargeText);
if (res.warnings?.length) {
  // handle warnings in your telemetry
}

Output controls: includeMaskMap, includeEntities, entityValueMode

const masker = createPIIMasker({
  includeMaskMap: false,
  includeEntities: true,
  entityValueMode: "masked", // or "none" in production
  includeMaskedValueInEntities: true,
});

logLevel

const masker = createPIIMasker({ logLevel: "warn" });

Masking strategies

Available MaskingStrategy values:

  • REDACT[REDACTED_<TYPE>]
  • PARTIAL_MASK → keep some structure (e.g., last 4 digits)
  • HASH → stable salted hash token like [HASH:abcd1234...]
  • TOKENIZE<<PII_deadbeef>> + store mapping in memory vault
  • REPLACE_FAKE → replace with realistic fake values (best for demos)
  • CUSTOM_FN → call a registered custom function

Custom detectors

Add your own detector for domain-specific identifiers.

import { createPIIMasker, type DetectedEntity } from "pii-guard-node-mini";

const masker = createPIIMasker({});

masker.addDetector("EMPLOYEE_ID", (text) => {
  const m = /E-\d{4,}/g.exec(text);
  if (!m) return [];

  const entity: DetectedEntity = {
    type: "EMPLOYEE_ID",
    value: m[0],
    start: m.index,
    end: m.index + m[0].length,
    confidence: 1,
  };

  return [entity];
});

masker.updateConfig({
  strategies: { EMPLOYEE_ID: "REDACT" },
});

Custom strategies

Register a named strategy and assign it per type.

import { createPIIMasker } from "pii-guard-node-mini";

const masker = createPIIMasker({});

masker.addStrategy("KEEP_LAST_2", (entity) =>
  entity.value.replace(/.(?=.{2})/g, "*"),
);

masker.updateConfig({
  strategies: {
    API_KEY: "KEEP_LAST_2",
  },
});

Masking objects (maskObject) and fieldPaths

By default, maskObject() deep-traverses and masks all string values.

If you pass fieldPaths, only matching paths are masked.

  • Exact: user.email
  • Wildcard segment: users.*.email
const input = {
  users: [
    { email: "[email protected]", note: "keep this" },
    { email: "[email protected]", note: "keep this" },
  ],
};

const out = masker.maskObject(input, ["users.*.email"]);

Reversible masking (tokenization + unmask)

If you want to restore original values (e.g., when an LLM responds with tokens), use TOKENIZE and set enableReversibility: true.

import { createPIIMasker, MaskingStrategy } from "pii-guard-node-mini";

const masker = createPIIMasker({
  enableReversibility: true,
  defaultStrategy: MaskingStrategy.TOKENIZE,
});

const masked = masker.mask("Call me at +1 555 123 4567").maskedText;
const restored = masker.unmask(masked);

Important:

  • Reversal only works for values tokenized by the same masker instance.
  • If you call clearVault(), those mappings are lost.

Tokenization behavior note:

  • If enableReversibility: false, the engine will still produce token-looking placeholders, but it will not store mappings (so unmask() cannot restore, and tokens may not be deterministic).
  • If you need deterministic tokens, enable reversibility and keep the instance alive for the conversation/session.

Determinism: tokenizationDeterministic

tokenizationDeterministic: true means the same original value becomes the same token within the same instance.

Notes:

  • Determinism requires storing mappings, so it only applies when enableReversibility: true.
  • If you disable reversibility, tokens are generated but not stored.

Built-in detectors (high level)

This library uses pattern-based detectors. Built-in coverage includes:

  • Email, phone, SSN, credit card (Luhn), IP, DOB, US address
  • Person names (heuristic), passport (US/UK), IBAN
  • AWS keys/secrets (heuristic), generic API keys (entropy), JWT, URLs with auth, MAC
  • Bank account / routing (conservative: requires context and routing checksum where possible)

Reporting

const masker = createPIIMasker({ preset: "balanced" });
masker.mask("Email: [email protected]");
masker.mask("Card: 4111 1111 1111 1111");

console.log(masker.getReport());

License

MIT License — see LICENSE.