purgo
Version:
Zero-config PHI-scrubber for browser and Node.js
325 lines (238 loc) • 9.38 kB
Markdown
# Purgo
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Olow304/purgo/main/dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Olow304/purgo/main/light.svg">
<img alt="Purgo Logo" src="https://raw.githubusercontent.com/Olow304/purgo/main/dark.svg" width="500" height="200">
</picture>
</p>
[](https://www.npmjs.com/package/purgo)
[](https://bundlephobia.com/package/purgo)
[](https://github.com/Olow304/purgo/actions)
[](https://github.com/Olow304/purgo/actions/workflows/ci.yml)
[](https://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
[](https://www.npmjs.com/package/purgo)
**Purgo** is a zero-config, client-side log-scrubbing library that prevents Protected Health Information (PHI) from leaking into browser consoles, DevTools, and network debuggers.
- 🔒 **HIPAA-Friendly**: Automatically redacts PHI from logs and network requests
- 🪶 **Lightweight**: < 7 kB gzip
- ⚡ **Fast**: < 3% runtime overhead
- 🔌 **Zero-Config**: Works out-of-the-box with React, Next.js, Vue, and vanilla JS
- 🧩 **Extensible**: Add custom patterns and redaction strategies
## Installation
```bash
npm install purgo
# or
yarn add purgo
# or
pnpm add purgo
```
## Quick Start
### Browser (Zero-Config)
```js
// Just import it - that's it!
import 'purgo';
// Now all console logs and network requests will be automatically scrubbed
console.log('Patient email: patient@example.com'); // Outputs: "Patient email: ***"
```
### Custom Configuration
```js
import { purgo } from 'purgo';
purgo({
targets: ['console', 'fetch', 'xhr'],
patterns: ['email', 'ssn', /\b\d{7,8}-[A-Z]{2}\b/], // Built-in + custom patterns
censor: (match) => '[REDACTED]' + match.slice(-2) // Custom redaction
});
```
### Direct Redaction Helper
```js
import { redact } from 'purgo';
const patientData = {
name: 'John Doe',
email: 'john.doe@example.com',
ssn: '123-45-6789'
};
const safeData = redact(patientData);
// Result: { name: 'John Doe', email: '***', ssn: '***' }
```
### Core Module (No Auto-Patching)
If you want just the redaction functionality without any automatic patching of global objects:
```js
import { redact, initRedactionEngine } from 'purgo/core';
// Optional: customize the redaction engine
initRedactionEngine({
patterns: ['email', 'phone', 'ssn', /\b[A-Z]{2}-\d{6}\b/g],
censor: (match) => `[REDACTED-${match.slice(-2)}]`
});
// Explicitly redact values
const email = "patient@example.com";
console.log(redact(email)); // Outputs: "[REDACTED-om]"
```
### Node.js Support
```js
// Auto-patch process.stdout
import 'purgo/node';
// Direct use with console.log or process.stdout.write
console.log('Patient email: patient@example.com'); // Outputs: "Patient email: ***"
process.stdout.write('SSN: 123-45-6789\n'); // Outputs: "SSN: ***"
```
#### Node.js with Custom Configuration
For more control, you can combine the auto-patching with custom configuration:
```js
// Use the Node.js module for auto-patching
import 'purgo/node';
// Import the core module for custom configuration
import { initRedactionEngine } from 'purgo/core';
// Configure the redaction engine with custom patterns and redaction style
initRedactionEngine({
patterns: ['email', 'ssn', /\b\d{7,8}-[A-Z]{2}\b/], // Built-in + custom patterns
censor: (match) => '[REDACTED]' + match.slice(-2) // Custom redaction style
});
// Test with various sensitive data
const email = 'test@test.com';
const ssn = '123456789';
console.log("Email: ", email); // Outputs: "Email: [REDACTED]om"
console.log("SSN: ", ssn); // Outputs: "SSN: [REDACTED]89"
```
### Express Integration
```js
// app.js
import express from 'express';
import 'purgo/node';
import { initRedactionEngine } from 'purgo/core';
// Configure Purgo with custom patterns and redaction
initRedactionEngine({
patterns: ['email', 'ssn', 'phone', /\b\d{7,8}-[A-Z]{2}\b/],
censor: (match) => '[REDACTED]' + match.slice(-2)
});
const app = express();
app.use(express.json());
// Example route that handles PHI
app.post('/api/patient', (req, res) => {
// PHI in request body will be automatically redacted in logs
console.log('Received patient data:', req.body);
// Process the data (using the original, unredacted data)
const patientId = savePatient(req.body);
// Log with PHI (will be automatically redacted)
console.log(`Created patient with email ${req.body.email}`);
res.json({ success: true, patientId });
});
// Server logs will show:
// Received patient data: { name: 'Jane Doe', email: '[REDACTED]om', ssn: '[REDACTED]21' }
// Created patient with email [REDACTED]om
```
### Pino Logger Integration
[Pino](https://github.com/pinojs/pino) is a popular structured logger for Node.js that's commonly used in healthcare applications. Purgo provides a dedicated integration:
```js
import { pinoRedactor } from 'purgo/node';
import pino from 'pino';
const logger = pino({
redact: pinoRedactor({
paths: ['req.body.ssn', 'req.body.email', 'patient.mrn']
})
});
// Logs will have PHI automatically redacted
logger.info({
req: { body: { email: 'patient@example.com' } }
});
```
## Framework Integration Examples
### React
```jsx
// In your entry file (e.g., main.jsx or index.jsx)
import 'purgo';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
```
### Next.js 14
```jsx
// app/layout.tsx
import 'purgo';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
```
Purgo v0.1.2+ includes special handling for Next.js environments to ensure compatibility with the App Router and Server Components architecture.
### Vue 3
```js
// main.js
import 'purgo';
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
```
### Vanilla JS (via script tag)
```html
<script src="https://unpkg.com/purgo/dist/index.global.js"></script>
<script>
// Purgo is automatically initialized
console.log('Patient SSN: 123-45-6789'); // Outputs: "Patient SSN: ***"
</script>
```
## API Reference
### `purgo(options?)`
Initializes Purgo with custom options.
```ts
interface PurgoOptions {
targets?: Array<'console' | 'fetch' | 'xhr'>;
patterns?: Array<RegExp | string>;
censor?: (match: string) => string;
hashMode?: boolean;
}
```
> **Note**: When using ES modules, we recommend using the auto-patching import (`import 'purgo'`) or the combined approach with `import 'purgo/node'` and `import { initRedactionEngine } from 'purgo/core'` rather than the named import (`import { purgo } from 'purgo'`), which may cause issues in some environments.
- **targets**: Array of targets to patch (default: `['console', 'fetch', 'xhr']`)
- **patterns**: Array of built-in pattern names or custom RegExp objects (default: `['email', 'phone', 'ssn', 'mrn', 'icd10']`)
- **censor**: Function to transform matched content (default: `() => '***'`)
- **hashMode**: Enable SHA-256 hashing of censored tokens for correlation (default: `false`)
### Built-in Patterns
- **email**: Email addresses
- **phone**: Phone numbers in various formats
- **ssn**: Social Security Numbers
- **mrn**: Medical Record Numbers
- **icd10**: ICD-10 diagnosis codes
### `redact(value)`
Redacts PHI from any value while preserving structure.
```ts
function redact<T>(value: T): T;
```
### Core Module: `import from 'purgo/core'`
The core module provides just the redaction functionality without any automatic patching of global objects.
```ts
import { redact, initRedactionEngine } from 'purgo/core';
```
This is useful when:
- You want more control over what gets redacted
- You want to avoid patching global objects
- You're using a framework that doesn't work well with patched globals
- You need to customize the redaction behavior extensively
As of v0.1.2, all modules include full TypeScript declarations for improved developer experience.
### Node.js: `pinoRedactor(options)`
Creates a redactor for use with Pino logger.
```ts
interface PinoRedactorOptions {
paths: string[];
additionalPatterns?: Array<RegExp | string>;
censor?: (match: string) => string;
}
```
## Performance
Purgo is designed to be lightweight and fast:
- **Bundle Size**: < 7 kB gzip
- **Runtime Overhead**: < 3% compared to raw operations
- **Redaction Speed**: ≤ 40 µs to redact a 5 kB string on M1 2.8 GHz
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for details on how to contribute to this project.
## License
MIT License - see [LICENSE](./LICENSE) for details.
A ready-to-sign Business Associate Agreement (BAA) template is available in the [legal](./legal) directory.