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

@stll/anonymize

v2.0.1

Published

Multi-layer PII detection and anonymization pipeline with regex, NER, deny lists, and coreference resolution

Readme

@stll/anonymize

Runtime package for multi-layer PII detection and anonymization.

It combines regex detectors, trigger phrases, deny-list matching, coreference handling, and NER into a single pipeline that works in native Node.js and in browser builds through the WASM entrypoint.

Install

bun add @stll/anonymize
# Optional data bundle for deny lists and dictionaries
bun add @stll/anonymize-data

The Node.js package is Rust-native. Browser/WASM support is maintained through @stll/anonymize-wasm, which wraps the same native core.

Usage: Node.js native SDK

import {
  availableDefaultNativePipelineLanguages,
  getDefaultNativePipeline,
} from "@stll/anonymize/native-node";

const languages = availableDefaultNativePipelineLanguages();
const anonymizer = getDefaultNativePipeline(
  languages.includes("en") ? { language: "en" } : {},
);
const result = anonymizer.redact_text(text);

console.log(result.redaction.redactedText);

Call getDefaultNativePipeline() once during service startup and reuse the returned anonymizer. The package ships with a prepared native package, so the normal request path avoids rebuilding search automata. Use preloadDefaultNativePipeline() or preloadDefaultNativePipelineAsync() when the first document should not pay lazy regex warm-up.

If your deployment knows the document language up front, select a scoped package at startup. The build emits en, cs, and de scoped packages by default, and STELLA_ANONYMIZE_NATIVE_PACKAGE_LANGUAGES can replace that list or be set to an empty value to build only the all-language package:

STELLA_ANONYMIZE_NATIVE_PACKAGE_LANGUAGES=en,cs,fr bun run build
const anonymizer = getDefaultNativePipeline({ language: "en" });

Regional codes use the exact package when present and otherwise fall back to the base language package, so en-US can use the shipped en artifact.

For build-time generated packages or caller-owned data, prepare the package before runtime and load the bytes in the process that handles documents.

bunx stella-anonymize-build-native-package \
  --config ./anonymize-native-config.mjs \
  --out ./dist/anonymize.stlanonpkg
import { load_prepared_package_file } from "@stll/anonymize/native-node";

const anonymizer = load_prepared_package_file("./dist/anonymize.stlanonpkg");
anonymizer.warmLazyRegex();
const warmDiagnosticsJson = anonymizer.warmLazyRegexDiagnosticsJson();
const result = anonymizer.redact_text(text, { redactString: "***" });

The config module may export a PipelineConfig directly or { config, gazetteerEntries }. Include @stll/anonymize-data dictionaries there if your runtime config uses the deny-list or name-corpus layers; keep the corresponding layers enabled for caller-owned customDenyList, customRegexes, and gazetteers. Those inputs are part of the prepared package and should be regenerated when they change.

Python SDK

import stella_anonymize as anonymize

languages = anonymize.available_default_native_pipeline_languages()
prepared = anonymize.preload_default_native_pipeline(
    language="en" if "en" in languages else None
)
result = prepared.redact_text(text, redact_string="***")

print(result.redaction.redacted_text)

The Python SDK uses the same Rust core and prepared-package contract as the Node SDK. Prefer get_default_native_pipeline(), preload_default_native_pipeline(), load_prepared_package(), or load_prepared_package_file() for repeated calls; top-level redact_text() and redact_text_json() prepare from config on each call.

Caller-Owned Deny Lists and Regexes

Use customDenyList for exact terms and variants that you control. Use customRegexes for deterministic patterns that are not built into the package. Caller-owned data is part of the prepared package, so build or load a package from that config before serving documents.

import {
  createNativePipelineFromConfig,
  loadNativeAnonymizeBinding,
} from "@stll/anonymize/native-node";

const binding = loadNativeAnonymizeBinding();
const pipeline = await createNativePipelineFromConfig({
  binding,
  config: {
    ...baseConfig,
    enableDenyList: true,
    enableRegex: true,
    customDenyList: [
      {
        value: "Project Nebula",
        variants: ["Nebula Programme"],
        label: "organization",
      },
    ],
    customRegexes: [
      {
        pattern: "\\bSTLL-[0-9]{4}\\b",
        label: "matter reference",
        score: 1,
      },
    ],
  },
  gazetteerEntries: [],
});

const result = pipeline.redactText(text);

Browser setup

If you use Vite with the WASM build, exclude the bundle from dependency pre-bundling:

import stllWasm from "@stll/anonymize-wasm/vite";

export default {
  plugins: [stllWasm()],
};

Notes

  • Native architecture and extension guidance: ARCHITECTURE.md.
  • labels: [] disables deterministic label filtering; when NER is enabled it falls back to the default label set.
  • enableNameCorpus also controls whether first names, surnames, and titles are injected into deny-list matching when enableDenyList is enabled.
  • The optional @stll/anonymize-data package carries the published dictionary and trigger data used when building prepared packages.
  • customDenyList and customRegexes are part of the prepared package input and should be regenerated when they change.
  • The old TypeScript pipeline is kept only as temporary internal migration/test scaffolding under src/legacy.ts; it is not the product runtime.

Built on

  • @stll/text-search
  • @stll/stdnum
  • @stll/anonymize-data