nvm use # Node 24 LTS (.nvmrc)
npm install
npm run build
npm test
npm run lint && npm run typecheckEval kit (Python 3.12, gitignored from npm publish): cd packages/eval && python3.12 -m venv .venv && pip install -e ".[presidio]". See packages/eval/README.md.
Non-negotiable — PRs that violate these will not be merged.
- ML-first detection, regex as post-pass. GLiNER is the primary detector; recognizers run after, never replace.
- No cloud calls for detection.
- No
console.login library code — usedebugnamespaced loggers (counts/ids only, never PII values). - No
any. TS strict mode +exactOptionalPropertyTypes. - No global mutable state.
- No circular imports.
npm run circular-checkin CI + pre-commit. - Defaults centralised in
src/defaults.ts.process.envonly via typed helpers insrc/config.ts. - Apache-2.0 / MIT / BSD / ISC / CC0 deps only.
npm run license-checkin CI.
- TDD — tests before implementation.
- Public function = happy path + edge case + error case.
- Coverage thresholds (CI-enforced): 85% lines, 80% branches.
- Hardware-gated tests (CUDA/MPS) auto-skip when probe fails.
The default npm test mocks OrtBackend + GlinerTokenizer so CI stays ONNX-free. The opt-in E2E suite under test/e2e/ loads the real GLiNER model and asserts representative fixtures produce representative spans — catches regressions in ScatterND clamping, decoder index math, chunk-boundary dedupe, recognizer/ML reconciliation, and the base64 layer.
# Point at a local model directory containing model.onnx + tokenizer.json
# + gliner_config.json + tokenizer_config.json.
NULLPII_MODEL_DIR=/path/to/model npm run test:e2etest/e2e/*.test.ts are excluded from the default vitest run; the test:e2e script sets NULLPII_E2E=1 so the same vitest.config.ts swaps include/exclude lists.
In CI the e2e-onnx job (.github/workflows/ci.yml) downloads the ONNX model from HuggingFace and runs the same suite. Opt-in via the repo variable NULLPII_E2E_ENABLED=true — flip it once lBroth/nullpii on HuggingFace is fully public (anonymous fetch must return 200). Optional repo variables NULLPII_E2E_HF_REPO and NULLPII_E2E_HF_REVISION override the default (lBroth/nullpii@main) — pin the revision to a 40-char commit SHA for reproducibility.
Conventional Commits (feat, fix, docs, chore, refactor, perf, test).
PR gate: lint, typecheck, test, build, license-check, circular-check, sbom — all must pass. New public API needs JSDoc (@param, @returns, @throws, @example).
Open an issue with: minimal repro, platform / Node version, nullpii version, redacted input. Do not attach raw PII.
See SECURITY.md. Use the GitHub Security Advisory channel — do not open a public issue.
Before tagging a new version:
- Version bump.
package.json.versionmatches the topmost section ofCHANGELOG.md. Bump SemVer per breaking / feature / fix. - Clean build.
npm run clean && npm run build(theprebuildhook runscleanautomatically). Confirms no orphandist/*.jsfrom deletedsrc/files. - Pack inspection.
npm pack --dry-run. Verify every shipped file is intentional:- Only
dist/,src/,README.md,LICENSE,NOTICE,bin/, and three asset paths (assets/logo.png,assets/claude-code-demo.m4v,assets/claude-code-demo-thumb.png) are listed (thepackage.json:fileswhitelist). dist/backend/contains onlybackend.{js,d.ts,*.map}.- No orphan compiled outputs in
dist/from modules that no longer exist insrc/. tarball sizeunder 16 MB (sanity — model weights ship via HF, demo video is ~13 MB).
- Only
- Full quality bar.
npm run lint && npm run typecheck && npm test && npm run license-check && npm run circular-check. All must pass on the release commit. - SBOM refresh.
npm run sbomregeneratesbom.jsonwith the current dep tree + timestamp. - Bench refresh. If the runtime pipeline changed (recognizer pack, normalize, base64 decoder, dedupe, vault), rerun
packages/eval/scripts/bench_full.pywith the canonical tool set and copy the matrix/confusion intopackages/eval/published-bench/. Update the README headline F1 if the number moved. - Tag + publish.
git tag vX.Y.Zthennpm publish --provenance(thepublishConfig.provenance: trueinpackage.jsonrequires running from a supported CI provider).