@stll/anonymize
v2.0.1
Published
Multi-layer PII detection and anonymization pipeline with regex, NER, deny lists, and coreference resolution
Maintainers
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-dataThe 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 buildconst 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.stlanonpkgimport { 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.enableNameCorpusalso controls whether first names, surnames, and titles are injected into deny-list matching whenenableDenyListis enabled.- The optional
@stll/anonymize-datapackage carries the published dictionary and trigger data used when building prepared packages. customDenyListandcustomRegexesare 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
