@rohan9024/redact0 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,7 @@
1
+ # AGENTS.md — redact0
2
+
3
+ - This repository builds **redact0**, published identically on npm (`redact0`) and PyPI (`redact0`).
4
+ - **Hard invariant**: `package.json` `"dependencies"` and `python/pyproject.toml` `dependencies` MUST remain empty (`{}` / `[]`).
5
+ - Core TypeScript bundle (`dist/index.mjs` gzipped) MUST stay strictly under 30 KB (`npm run check:size`).
6
+ - Run `npm run typecheck && npm run build && npm test && npm run check:size` for TypeScript verification.
7
+ - Run `PYTHONPATH=python/src pytest python/tests` for Python verification.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 redact0 contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,110 @@
1
- # Temporary Holding Version
1
+ # redact0
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Zero-runtime-dependency reversible PII, secret, FHIR Safe Harbor and streaming redaction for JavaScript/TypeScript and Python.
4
+
5
+ > Security note: this package is a best-effort detector/redactor, not a compliance certification or a substitute for a privacy/security review. Validate it against your own data and regulatory requirements before production use.
6
+
7
+ ## Requirements
8
+
9
+ - Node.js 18+ for the npm package
10
+ - Python 3.10+ for the PyPI package
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install redact0
16
+ ```
17
+
18
+ ```bash
19
+ python -m pip install redact0
20
+ ```
21
+
22
+ ## JavaScript / TypeScript quick start
23
+
24
+ ```ts
25
+ import { createVault, redact } from 'redact0';
26
+
27
+ const safe = redact({
28
+ email: 'alice@example.com',
29
+ message: 'Contact alice@example.com',
30
+ });
31
+
32
+ const vault = createVault();
33
+ const scrubbed = vault.redact('Send the report to alice@example.com').value;
34
+ const restored = vault.restore(scrubbed);
35
+ ```
36
+
37
+ ## Python quick start
38
+
39
+ ```python
40
+ from redact0 import Vault, redact
41
+
42
+ safe = redact({"email": "alice@example.com"})
43
+ vault = Vault()
44
+ scrubbed = vault.redact("Contact alice@example.com").value
45
+ restored = vault.restore(scrubbed)
46
+ ```
47
+
48
+ ## Build and verify from this repository
49
+
50
+ ```bash
51
+ npm install
52
+ npm run typecheck
53
+ npm run build
54
+ npm test
55
+ npm run check:size
56
+ ```
57
+
58
+ Python checks (from the repository root):
59
+
60
+ ```bash
61
+ python -m venv .venv
62
+ # Windows PowerShell: .venv\Scripts\Activate.ps1
63
+ # macOS/Linux: source .venv/bin/activate
64
+ python -m pip install -e ./python
65
+ python -m pip install pytest
66
+ python -m pytest python/tests
67
+ ```
68
+
69
+ The Python package itself declares no runtime dependencies. `pytest` is only needed to run its tests.
70
+
71
+ ## CLI
72
+
73
+ After building the npm package:
74
+
75
+ ```bash
76
+ echo "email: alice@example.com" | node dist/cli.cjs
77
+ npx redact0 init
78
+ npx redact0 scan . --preset secrets
79
+ npx redact0 mcp
80
+ ```
81
+
82
+ For Python, after installation:
83
+
84
+ ```bash
85
+ echo "email: alice@example.com" | redact0
86
+ ```
87
+
88
+ ## Exports
89
+
90
+ The npm package defines these subpath exports:
91
+
92
+ - `redact0/stream`
93
+ - `redact0/fhir`
94
+ - `redact0/ai`
95
+ - `redact0/mcp`
96
+ - `redact0/logger`
97
+
98
+ The Python package includes `redact0.compat.llm_guard` for compatibility helpers.
99
+
100
+ ## Project layout
101
+
102
+ - `src/`: TypeScript implementation and adapters
103
+ - `tests/`: TypeScript tests
104
+ - `python/src/redact0/`: Python implementation
105
+ - `python/tests/`: Python tests
106
+ - `llms.txt`, `llms-full.txt`, `context7.json`, `AGENTS.md`: AI-agent and documentation discovery resources
107
+
108
+ ## License
109
+
110
+ MIT. See [LICENSE](LICENSE).
package/context7.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://context7.com/schema/context7.json",
3
+ "projectTitle": "redact0",
4
+ "description": "Zero-dependency reversible PII, secret, FHIR HIPAA Safe Harbor, and streaming SSE redactor for AI SDKs, MCP servers, Pino/Winston loggers, and Python (drop-in llm-guard migration).",
5
+ "folders": ["src", "python/src"],
6
+ "rules": [
7
+ "Always prefer zero-dependency redact0 subpaths: redact0/ai, redact0/mcp, redact0/logger, redact0/fhir, redact0/stream.",
8
+ "Use redactMiddleware() from redact0/ai with wrapLanguageModel() for Vercel AI SDK v5/v6/v7.",
9
+ "Use guardMcpServer() from redact0/mcp to scrub MCP tool outputs and rehydrate vault tokens inside trusted local tool arguments.",
10
+ "For Python teams migrating off archived llm-guard, use from redact0.compat.llm_guard import Anonymize, Deanonymize, Vault, scan_prompt, scan_output."
11
+ ]
12
+ }
package/dist/ai.cjs ADDED
@@ -0,0 +1,8 @@
1
+ 'use strict';var ct=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),ut=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),V=new TextEncoder;function A(i,t){return i>>>t|i<<32-t}function I(i){let t=i.length*8,n=Math.ceil((i.length+9)/64)*64,a=new Uint8Array(n);a.set(i),a[i.length]=128;let s=new DataView(a.buffer),r=Math.floor(t/4294967296),o=t>>>0;s.setUint32(n-8,r,false),s.setUint32(n-4,o,false);let e=new Uint32Array(ut),c=new Uint32Array(64);for(let l=0;l<n;l+=64){for(let b=0;b<16;b++)c[b]=s.getUint32(l+b*4,false);for(let b=16;b<64;b++){let E=c[b-15],S=c[b-2],C=A(E,7)^A(E,18)^E>>>3,D=A(S,17)^A(S,19)^S>>>10;c[b]=c[b-16]+C+c[b-7]+D>>>0;}let d=e[0],p=e[1],g=e[2],h=e[3],y=e[4],m=e[5],P=e[6],N=e[7];for(let b=0;b<64;b++){let E=A(y,6)^A(y,11)^A(y,25),S=y&m^~y&P,C=N+E+S+ct[b]+c[b]>>>0,D=A(d,2)^A(d,13)^A(d,22),at=d&p^d&g^p&g,ot=D+at>>>0;N=P,P=m,m=y,y=h+C>>>0,h=g,g=p,p=d,d=C+ot>>>0;}e[0]=e[0]+d>>>0,e[1]=e[1]+p>>>0,e[2]=e[2]+g>>>0,e[3]=e[3]+h>>>0,e[4]=e[4]+y>>>0,e[5]=e[5]+m>>>0,e[6]=e[6]+P>>>0,e[7]=e[7]+N>>>0;}let f=new Uint8Array(32),u=new DataView(f.buffer);for(let l=0;l<8;l++)u.setUint32(l*4,e[l],false);return f}function M(i,t,n=64){let a=V.encode(i),s=a.length>64?I(a):a,r=new Uint8Array(64);r.set(s);let o=new Uint8Array(64),e=new Uint8Array(64);for(let p=0;p<64;p++){let g=r[p];o[p]=g^92,e[p]=g^54;}let c=V.encode(t),f=new Uint8Array(64+c.length);f.set(e,0),f.set(c,64);let u=I(f),l=new Uint8Array(96);l.set(o,0),l.set(u,64);let d=I(l);return Z(d).slice(0,n)}function z(i,t=64){return Z(I(V.encode(i))).slice(0,t)}function Z(i){let t="";for(let n=0;n<i.length;n++)t+=i[n].toString(16).padStart(2,"0");return t}function U(i=8){let t=new Uint8Array(i);if(typeof globalThis.crypto?.getRandomValues=="function")globalThis.crypto.getRandomValues(t);else for(let n=0;n<i;n++)t[n]=Math.floor(Math.random()*256);return Z(t)}function R(i){return i.replace(/\D/g,"")}function j(i){let t=R(i);if(t.length<13||t.length>19||/^(\d)\1+$/.test(t))return false;let n=0,a=false;for(let s=t.length-1;s>=0;s--){let r=t.charCodeAt(s)-48;a&&(r*=2,r>9&&(r-=9)),n+=r,a=!a;}return n%10===0}function F(i){let t=R(i);if(!/^[12]\d{9}$/.test(t))return false;let n="80840"+t,a=0,s=false;for(let r=n.length-1;r>=0;r--){let o=n.charCodeAt(r)-48;s&&(o*=2,o>9&&(o-=9)),a+=o,s=!s;}return a%10===0}function L(i){let t=i.trim().toUpperCase();if(!/^[ABFGMPRX][A-Z9]\d{7}$/.test(t))return false;let n=o=>t.charCodeAt(2+o)-48,a=n(0)+n(2)+n(4),s=n(1)+n(3)+n(5);return (a+2*s)%10===n(6)}var _="ACDEFGHJKMNPQRTUVWXY",K="0123456789"+_;function $(i){let t=i.replace(/-/g,"").toUpperCase();if(t.length!==11)return false;let n=t.charCodeAt(0);return !(n<49||n>57||!_.includes(t[1])||!K.includes(t[2])||!/\d/.test(t[3])||!_.includes(t[4])||!K.includes(t[5])||!/\d/.test(t[6])||!_.includes(t[7])||!_.includes(t[8])||!/\d\d/.test(t.slice(9,11)))}var lt={AD:24,AE:23,AL:28,AT:20,AZ:28,BA:20,BE:16,BG:22,BH:22,BR:29,BY:28,CH:21,CR:22,CY:28,CZ:24,DE:22,DK:18,DO:28,EE:20,EG:29,ES:24,FI:18,FO:18,FR:27,GB:22,GE:22,GI:23,GL:18,GR:27,GT:28,HR:21,HU:28,IE:22,IL:23,IQ:23,IS:26,IT:27,JO:30,KW:30,KZ:20,LB:28,LC:32,LI:21,LT:20,LU:20,LV:21,MC:27,MD:24,ME:22,MK:19,MR:27,MT:31,MU:30,NL:18,NO:15,PK:24,PL:28,PS:29,PT:25,QA:29,RO:24,RS:22,SA:24,SE:24,SI:19,SK:24,SM:27,ST:25,SV:28,TL:23,TN:24,TR:26,UA:29,VA:22,VG:24,XK:20};function B(i){let t=i.replace(/[\s-]+/g,"").toUpperCase();if(!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(t))return false;let n=lt[t.slice(0,2)];if(n!==void 0&&t.length!==n)return false;let a=t.slice(4)+t.slice(0,4),s=0;for(let r=0;r<a.length;r++){let o=a.charCodeAt(r);if(o>=48&&o<=57)s=(s*10+(o-48))%97;else if(o>=65&&o<=90){let e=o-55;s=(s*100+e)%97;}else return false}return s===1}function H(i){let t=R(i);if(t.length!==10||/^(\d)\1+$/.test(t))return false;let n=0;for(let r=0;r<9;r++)n+=(t.charCodeAt(r)-48)*(10-r);let s=11-n%11;return s===11&&(s=0),s===10?false:s===t.charCodeAt(9)-48}function G(i,t){let n=i.trim(),a=/[-\s]/.test(n),s=R(n);if(s.length!==9)return false;let r=Number(s.slice(0,3)),o=Number(s.slice(3,5)),e=Number(s.slice(5,9));if(r===0||r===666||r>=900||o===0||e===0||/^(\d)\1+$/.test(s))return false;if(!a&&t){let c=t.fullText.slice(Math.max(0,t.start-36),t.start);return /\b(ssn|social[\s_-]?security|tin)\b/i.test(c)}return true}var ft=[[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],[9,8,7,6,5,4,3,2,1,0]],dt=[[0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]];function J(i){let t=R(i);if(!/^[2-9]\d{11}$/.test(t))return false;let n=0;for(let a=0;a<t.length;a++){let s=t.charCodeAt(t.length-1-a)-48;n=ft[n][dt[a%8][s]];}return n===0}function q(i){let t=R(i);if(!/^[1-9]\d{10}$/.test(t))return false;let n=new Array(10).fill(0);for(let e=0;e<10;e++)n[t.charCodeAt(e)-48]+=1;let a=n.filter(e=>e===2||e===3).length,s=Math.max(...n);if(a!==1||s>3)return false;let r=10;for(let e=0;e<10;e++){let c=(t.charCodeAt(e)-48+r)%10;c===0&&(c=10),r=c*2%11;}let o=11-r;return o===10&&(o=0),o===t.charCodeAt(10)-48}function Y(i){let t=i.split(".");if(t.length!==3)return false;let n=t[0];if(!n.startsWith("eyJ"))return false;try{let a=n.replace(/-/g,"+").replace(/_/g,"/"),s=(4-a.length%4)%4,r=atob(a+"=".repeat(s));return r.startsWith("{")&&r.includes('"')}catch{return false}}function W(i){let t=i.split(".").map(Number);if(t.length!==4)return false;let[n,a]=t;return n===void 0||a===void 0?false:n===10||n===127||n===0||n===192&&a===168||n===172&&a>=16&&a<=31||n===169&&a===254}function X(i){let t=i.split(".");if(t.length!==4)return false;for(let n of t){if(n.length===0||n.length>1&&n.startsWith("0"))return false;let a=Number(n);if(!Number.isInteger(a)||a<0||a>255)return false}return true}function Q(i){if(i.length===0)return 0;let t=new Map;for(let s=0;s<i.length;s++){let r=i.charCodeAt(s);t.set(r,(t.get(r)??0)+1);}let n=0,a=i.length;for(let s of t.values()){let r=s/a;n-=r*Math.log2(r);}return n}var x=["default","secrets","hipaa","gdpr","strict"],v=["default","hipaa","gdpr","strict"],O=["hipaa","strict"],pt=["gdpr","strict"],tt=[{id:"pem-private-key",category:"PRIVATE_KEY",priority:100,presets:x,pattern:/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----[\s\S]{16,8192}?-----END (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----/g},{id:"connection-uri-password",category:"CONNECTION_URI",priority:96,presets:x,captureGroup:1,pattern:/\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis(?:s)?|amqp(?:s)?|mssql|clickhouse|cockroachdb):\/\/[^:\s/@]+:([^@\s/]{3,256})@[^\s"'<>]+/gi},{id:"anthropic-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-ant-(?:api\d{2}|admin\d{2}|oat\d{2}|[a-z0-9]+)-[A-Za-z0-9_-]{24,}\b/g},{id:"openai-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{24,}\b|\bsk-[A-Za-z0-9]{16,}T3BlbkFJ[A-Za-z0-9]{16,}\b/g},{id:"github-token",category:"API_KEY",priority:95,presets:x,pattern:/\b(?:gh[pousr]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9]{22}_[A-Za-z0-9]{40,})\b/g},{id:"aws-access-key",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:AKIA|ASIA|AROA|AIDA)[0-9A-Z]{16}\b/g},{id:"stripe-secret",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:sk_live|rk_live|whsec)_[A-Za-z0-9]{20,}\b/g},{id:"google-api-key",category:"API_KEY",priority:93,presets:x,pattern:/\bAIza[0-9A-Za-z_-]{35}\b/g},{id:"slack-token",category:"TOKEN",priority:93,presets:x,pattern:/\bxox[baprs]-[0-9A-Za-z-]{14,}\b|https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g},{id:"discord-webhook",category:"SECRET",priority:92,presets:x,pattern:/https:\/\/discord(?:app)?\.com\/api\/webhooks\/\d{16,22}\/[A-Za-z0-9_-]{40,}/g},{id:"provider-prefixed-keys",category:"API_KEY",priority:92,presets:x,pattern:/\b(?:hf_[A-Za-z0-9]{30,}|gsk_[A-Za-z0-9]{36,}|xai-[A-Za-z0-9]{36,}|pplx-[A-Za-z0-9]{36,}|sbp_[A-Za-z0-9]{36,}|sb_secret_[A-Za-z0-9_-]{24,}|re_[A-Za-z0-9_]{24,}|npm_[A-Za-z0-9]{36}|pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}|SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b/g},{id:"jwt-token",category:"JWT",priority:90,presets:x,pattern:/\beyJ[A-Za-z0-9_-]{6,}\.eyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{8,}\b/g,validate:i=>Y(i)},{id:"bearer-auth-header",category:"TOKEN",priority:88,presets:x,captureGroup:1,pattern:/\b(?:Authorization|Proxy-Authorization)\s*[:=]\s*["']?(?:Bearer|Basic|Token)\s+([A-Za-z0-9._~+/=-]{12,})["']?/gi},{id:"contextual-secret-assignment",category:"SECRET",priority:72,presets:x,captureGroup:1,pattern:/\b(?:api[_-]?key|secret[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|client[_-]?secret|private[_-]?key|aws_secret_access_key|password|passwd|pwd|signing[_-]?secret)\b\s*[:=]\s*["']?([^\s"',;}{]{10,128})["']?/gi,validate:i=>!i.startsWith("[")&&!i.startsWith("<")&&Q(i)>=2.8},{id:"medicare-mbi",category:"MBI",priority:84,presets:O,pattern:/\b[1-9][AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y]{2}\d{2}\b/gi,validate:i=>$(i)},{id:"us-dea",category:"DEA",priority:83,presets:O,pattern:/\b[ABFGMPRX][A-Z9]\d{7}\b/g,validate:i=>L(i)},{id:"us-npi",category:"NPI",priority:80,presets:O,contextWindow:40,contextRegex:/\b(?:npi|provider|prescriber|practitioner|physician)\b/i,pattern:/\b[12]\d{9}\b/g,validate:i=>F(i)},{id:"uk-nhs-number",category:"NHS",priority:80,presets:["hipaa","gdpr","strict"],contextWindow:40,contextRegex:/\b(?:nhs|patient|health|care|medical)\b/i,pattern:/\b\d{3}[-\s]?\d{3}[-\s]?\d{4}\b/g,validate:i=>H(i)},{id:"medical-record-number",category:"MRN",priority:78,presets:O,captureGroup:1,pattern:/\b(?:mrn|medical[\s_-]?record(?:[\s_-]?number)?|patient[\s_-]?id)\s*[:=#]?\s*([A-Z0-9-]{5,20})\b/gi},{id:"iban",category:"IBAN",priority:84,presets:v,pattern:/\b[A-Z]{2}\d{2}(?:[\s-]?[A-Z0-9]){11,30}\b/g,validate:i=>B(i)},{id:"credit-card",category:"CREDIT_CARD",priority:82,presets:v,pattern:/\b(?:\d[ -]?){13,18}\d\b/g,validate:i=>{let t=i.replace(/\D/g,"");return /^(?:4\d{12}(?:\d{3})?(?:\d{3})?|5[1-5]\d{14}|2(?:2[2-9]|[3-6]\d|7[01]|720)\d{12}|3[47]\d{13}|6(?:011|5\d\d)\d{12}|3(?:0[0-5]|[68]\d)\d{11}|(?:2131|1800|35\d{3})\d{11})$/.test(t)&&j(t)}},{id:"us-ssn",category:"SSN",priority:81,presets:v,pattern:/\b\d{3}[-\s]\d{2}[-\s]\d{4}\b|\b\d{9}\b/g,validate:(i,t)=>G(i,t)},{id:"aadhaar-in",category:"AADHAAR",priority:76,presets:["gdpr","strict"],contextWindow:40,contextRegex:/\b(?:aadhaar|aadhar|uidai)\b/i,pattern:/\b[2-9]\d{3}[-\s]?\d{4}[-\s]?\d{4}\b/g,validate:i=>J(i)},{id:"de-tax-id",category:"TAX_ID",priority:76,presets:pt,contextWindow:45,contextRegex:/\b(?:steuer|tax|tin|idnr|identifikationsnummer)\b/i,pattern:/\b[1-9]\d{10}\b/g,validate:i=>q(i)},{id:"email",category:"EMAIL",priority:75,presets:v,pattern:/\b[A-Za-z0-9._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\.)+[A-Za-z]{2,24}\b/g},{id:"phone",category:"PHONE",priority:65,presets:v,pattern:/(?:\+\d{1,3}[-.\s]?)?(?:\(\d{2,4}\)[-.\s]?|\b\d{3}[-.\s])\d{3,4}[-.\s]\d{4}\b|\+\d{1,3}[-.\s]?\d{2,4}[-.\s]?\d{3,4}[-.\s]?\d{3,4}\b/g,validate:i=>{let t=i.replace(/\D/g,"");return t.length>=10&&t.length<=15&&!/^(\d)\1+$/.test(t)}},{id:"ipv4",category:"IP_ADDRESS",priority:60,presets:v,pattern:/\b(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}\b/g,validate:i=>X(i)},{id:"ipv6",category:"IP_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b/g},{id:"mac-address",category:"MAC_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g},{id:"labeled-person-name",category:"PERSON",priority:55,presets:["hipaa","strict"],captureGroup:1,pattern:/\b(?:Patient(?:\s+Name)?|Dr\.|Doctor|Clinician|Provider|Mr\.|Mrs\.|Ms\.|Full\s+Name|Beneficiary)\s*[:.]?\s*([A-Z][a-z]{1,24}(?:\s+[A-Z]\.?)?(?:\s+[A-Z][a-z]{1,24}){1,2})/g},{id:"dob-or-clinical-date",category:"DATE",priority:52,presets:O,contextWindow:40,contextRegex:/\b(?:dob|birth|born|admit(?:ted)?|discharg(?:e|ed)|visit|encounter|date)\b/i,pattern:/\b(?:\d{4}-\d{2}-\d{2}|(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g}];var gt=/^(?:password|passwd|pwd|passphrase|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|authorization|cookie|set-cookie|x-api-key|client[_-]?secret|private[_-]?key|ssn|social[_-]?security(?:[_-]?number)?|cvv|cvc|pin|iban|dob|birth[_-]?date|mrn)$/i,ht=/\[[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?\]|<[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?>/g;function et(i){let t=i.toLowerCase();return t.includes("ssn")||t.includes("social")?"SSN":t.includes("iban")?"IBAN":t.includes("mrn")?"MRN":t.includes("dob")||t.includes("birth")?"DATE":t.includes("password")||t.includes("passwd")||t.includes("secret")||t==="cvv"||t==="cvc"||t==="pin"?"SECRET":t.includes("token")||t==="authorization"||t==="cookie"||t==="set-cookie"?"TOKEN":t.includes("key")?"API_KEY":"CUSTOM"}function yt(i){let t=i.preset??"default",n=i.rules?[...i.rules]:tt.filter(r=>r.presets.includes(t)),s=[...(i.customRules??[]).map(r=>({id:r.id,category:r.category??"CUSTOM",pattern:r.pattern,captureGroup:r.captureGroup,priority:r.priority??85,presets:["default","secrets","hipaa","gdpr","strict"],validate:r.validate})),...n];if(i.categories?.length){let r=new Set(i.categories);s=s.filter(o=>r.has(o.category));}if(i.excludeCategories?.length){let r=new Set(i.excludeCategories);s=s.filter(o=>!r.has(o.category));}return s}function bt(i,t){let n=[];for(let a of t){if(!a||a.length<4)continue;let s=0;for(;;){let r=i.indexOf(a,s);if(r===-1)break;n.push({id:"literal-secret",category:"SECRET",priority:99,start:r,end:r+a.length,value:a}),s=r+a.length;}}return n}function rt(i,t,n){let a=[],s=n.allowlist?new Set(n.allowlist):void 0,r=n.redactPrivateIps??(n.preset==="strict"||n.preset==="hipaa");n.literals?.length&&a.push(...bt(i,n.literals));for(let e of t){let c=e.pattern.flags.includes("g")?e.pattern.flags:e.pattern.flags+"g",f=new RegExp(e.pattern.source,c),u;for(;(u=f.exec(i))!==null;){if(u[0].length===0){f.lastIndex+=1;continue}let l=u.index,d=u[0];if(e.captureGroup!==void 0&&u[e.captureGroup]!==void 0){let g=u[e.captureGroup],h=u[0].indexOf(g);h!==-1&&(l=u.index+h,d=g);}let p=l+d.length;if(!s?.has(d)&&!(e.id==="ipv4"&&!r&&W(d))){if(e.contextRegex){let g=e.contextWindow??40,h=i.slice(Math.max(0,l-g),l),y=i.slice(p,Math.min(i.length,p+g));if(!e.contextRegex.test(h)&&!e.contextRegex.test(y))continue}if(e.validate){let g={fullText:i,match:u,start:l,end:p,value:d};if(!e.validate(d,g))continue}a.push({id:e.id,category:e.category,priority:e.priority,start:l,end:p,value:d});}}}a.sort((e,c)=>{if(c.priority!==e.priority)return c.priority-e.priority;let f=c.end-c.start-(e.end-e.start);return f!==0?f:e.start-c.start});let o=[];for(let e of a){let c=false;for(let f of o)if(e.start<f.end&&e.end>f.start){c=true;break}c||o.push(e);}return o.sort((e,c)=>e.start-c.start),o}var w=class i{options;rules;tokenFormat;vaultKey;sensitiveKeyRe;forward=new Map;reverse=new Map;counters=new Map;reservedTokens=new Set;_version=0;constructor(t={}){this.options=t,this.rules=yt(t),this.tokenFormat=t.tokenFormat??"bracket",this.vaultKey=t.secret??U(16),this.sensitiveKeyRe=t.sensitiveKeys?.length?new RegExp(`^(?:${t.sensitiveKeys.map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})$`,"i"):gt;}get version(){return this._version}fingerprint(t){return M(this.vaultKey,t,12)}reserveExistingTokens(t){let n=new RegExp(ht.source,"g"),a;for(;(a=n.exec(t))!==null;)this.reverse.has(a[0])||this.reservedTokens.add(a[0]);}tokenize(t,n){let a=`${t}:${n}`,s=this.forward.get(a);if(s!==void 0)return s;if(this.tokenFormat==="mask")return (this.options.maskChar??"*").repeat(Math.min(Math.max(n.length,4),16));if(this.tokenFormat==="hash"){let e=M(this.vaultKey,a,8),c=`[${t}:${e}]`;return this.forward.set(a,c),this.reverse.set(c,{category:t,value:n}),this._version+=1,c}let r=this.counters.get(t)??0,o;do if(r+=1,this.tokenFormat==="angle")o=`<${t}_${r}>`;else if(this.tokenFormat==="signed"){let e=M(this.vaultKey,`${t}:${r}:${n}`,4);o=`[${t}_${r}#${e}]`;}else o=`[${t}_${r}]`;while(this.reservedTokens.has(o)||this.reverse.has(o));return this.counters.set(t,r),this.forward.set(a,o),this.reverse.set(o,{category:t,value:n}),this._version+=1,o}scan(t){return typeof t!="string"||t.length===0?[]:rt(t,this.rules,this.options).map(a=>({id:a.id,category:a.category,start:a.start,end:a.end,token:`[${a.category}]`,length:a.value.length,fingerprint:z(a.value,12)}))}redactText(t){if(typeof t!="string"||t.length===0)return {value:t,findings:[],count:0};this.reserveExistingTokens(t);let n=rt(t,this.rules,this.options);if(n.length===0)return {value:t,findings:[],count:0};let a="",s=0,r=[];for(let o of n){a+=t.slice(s,o.start);let e=this.tokenize(o.category,o.value);a+=e,s=o.end,r.push({id:o.id,category:o.category,start:o.start,end:o.end,token:e,length:o.value.length,fingerprint:this.fingerprint(o.value)});}return a+=t.slice(s),{value:a,findings:r,count:r.length}}redactObject(t){let n=[],a=this.options.maxDepth??32,s=new WeakMap,r=(e,c,f)=>{if(e==null)return e;if(typeof e=="string"){if(f&&this.sensitiveKeyRe.test(f)&&e.length>0&&!this.reverse.has(e)){let d=et(f),p=this.tokenize(d,e);return n.push({id:"sensitive-key",category:d,start:0,end:e.length,token:p,length:e.length,fingerprint:this.fingerprint(e)}),p}let l=this.redactText(e);return l.count>0&&n.push(...l.findings),l.value}if(typeof e!="object")return e;if(c>=a)return "[MAX_DEPTH_TRUNCATED]";if(s.has(e))return s.get(e);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e.source,e.flags);if(e instanceof URL){let l=new URL(e.toString());l.password&&(l.password=this.tokenize("SECRET",l.password));let d=[];l.searchParams.forEach((p,g)=>{d.push([g,p]);});for(let[p,g]of d)if(this.sensitiveKeyRe.test(p)&&g)l.searchParams.set(p,this.tokenize(et(p),g));else {let h=this.redactText(g);h.count>0&&(n.push(...h.findings),l.searchParams.set(p,h.value));}return l}if(typeof Headers<"u"&&e instanceof Headers){let l=new Headers;return e.forEach((d,p)=>{l.set(p,r(d,c+1,p));}),l}if(e instanceof Error){let l={name:e.name,message:this.options.redactErrors!==false?r(e.message,c+1):e.message};e.stack!==void 0&&(l.stack=this.options.redactErrors!==false?r(e.stack,c+1):e.stack),"cause"in e&&e.cause!==void 0&&(l.cause=r(e.cause,c+1));for(let d of Object.keys(e))l[d]=r(e[d],c+1,d);return l}if(Array.isArray(e)){let l=[];s.set(e,l);for(let d=0;d<e.length;d++)l.push(r(e[d],c+1,f));return l}if(e instanceof Map){let l=new Map;s.set(e,l);for(let[d,p]of e.entries()){let g=typeof d=="string"?d:void 0;l.set(r(d,c+1),r(p,c+1,g));}return l}if(e instanceof Set){let l=new Set;s.set(e,l);for(let d of e.values())l.add(r(d,c+1));return l}let u={};s.set(e,u);for(let[l,d]of Object.entries(e))u[l]=r(d,c+1,l);return u};return {value:r(t,0),findings:n,count:n.length}}redact(t){return typeof t=="string"?this.redactText(t):this.redactObject(t)}restore(t){if(typeof t!="string"||t.length===0||this.reverse.size===0)return t;let a=Array.from(this.reverse.keys()).sort((r,o)=>o.length-r.length).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),s=new RegExp(a.join("|"),"g");return t.replace(s,r=>this.reverse.get(r)?.value??r)}restoreObject(t){let n=new WeakMap,a=(s,r)=>{if(s==null)return s;if(typeof s=="string")return this.restore(s);if(typeof s!="object"||r>=32)return s;if(n.has(s))return n.get(s);if(Array.isArray(s)){let e=[];n.set(s,e);for(let c of s)e.push(a(c,r+1));return e}if(s instanceof Date||s instanceof RegExp||s instanceof URL)return s;let o={};n.set(s,o);for(let[e,c]of Object.entries(s))o[e]=a(c,r+1);return o};return a(t,0)}entries(){return Array.from(this.reverse.entries()).map(([t,n])=>({token:t,category:n.category,value:n.value}))}export(){let t={};for(let[n,a]of this.counters.entries())t[n]=a;return {version:1,tokenFormat:this.tokenFormat,counters:t,entries:this.entries()}}static fromJSON(t,n={}){let a=new i({...n,tokenFormat:t.tokenFormat});for(let[s,r]of Object.entries(t.counters))a.counters.set(s,r);for(let s of t.entries)a.forward.set(`${s.category}:${s.value}`,s.token),a.reverse.set(s.token,{category:s.category,value:s.value});return a._version+=1,a}clear(){this.forward.clear(),this.reverse.clear(),this.counters.clear(),this.reservedTokens.clear(),this._version+=1;}};function k(i){let t=-1,n=new Map,a=new Set,s=new Set,r=0,o=()=>{if(i.version!==t){t=i.version,n=new Map,a=new Set,s=new Set,r=0;for(let{token:f,value:u}of i.entries())if(f){n.set(f,u),s.add(f[0]),f.length>r&&(r=f.length);for(let l=1;l<f.length;l++)a.add(f.slice(0,l));}}},e="",c=f=>{if(o(),e.length===0)return "";if(n.size===0){let d=e;return e="",d}let u="",l=0;for(;l<e.length;){let d=e[l];if(!s.has(d)){u+=d,l+=1;continue}let p=e.slice(l);if(!f&&p.length<r&&a.has(p))break;let g=Math.min(r,p.length),h;for(let y=g;y>=1;y--){let m=p.slice(0,y);if(n.has(m)){h=m;break}}h!==void 0?(u+=n.get(h),l+=h.length):(u+=d,l+=1);}return e=e.slice(l),u};return {push(f){return f?(e+=f,c(false)):""},flush(){return c(true)},async*restoreIterable(f){for await(let l of f){let d=this.push(l);d.length>0&&(yield d);}let u=this.flush();u.length>0&&(yield u);},createTransformStream(){return new TransformStream({transform:(f,u)=>{let l=this.push(f);l.length>0&&u.enqueue(l);},flush:f=>{let u=this.flush();u.length>0&&f.enqueue(u);}})}}}function nt(i){let t=k(i),n="",a=(r,o=false)=>{let e=false;if(Array.isArray(r.choices)){for(let c of r.choices)if(c&&typeof c=="object"){let f=c.delta;f&&typeof f.content=="string"&&(f.content=t.push(f.content)+(o?t.flush():""),e=true);}}if(typeof r.delta=="string"&&(r.type==="text-delta"||r.type==="response.output_text.delta"||r.type==="reasoning-delta")&&(r.delta=t.push(r.delta)+(o?t.flush():""),e=true),r.delta&&typeof r.delta=="object"){let c=r.delta;typeof c.text=="string"&&(c.text=t.push(c.text)+(o?t.flush():""),e=true);}if(Array.isArray(r.candidates))for(let c of r.candidates){let f=c?.content?.parts;if(Array.isArray(f))for(let u of f)typeof u.text=="string"&&(u.text=t.push(u.text)+(o?t.flush():""),e=true);}return e},s=r=>{if(r.startsWith("0:"))try{let e=JSON.parse(r.slice(2));if(typeof e=="string")return "0:"+JSON.stringify(t.push(e))}catch{return r}if(!r.startsWith("data:"))return r;let o=r.slice(5).trim();if(o==="[DONE]"){let e=t.flush();return e.length>0?`data: ${JSON.stringify({choices:[{index:0,delta:{content:e}}]})}
2
+
3
+ `+r:r}try{let e=JSON.parse(o);if(a(e))return "data: "+JSON.stringify(e)}catch{return "data: "+t.push(o)}return r};return {push(r){n+=r;let o=n.split(`
4
+ `);return n=o.pop()??"",o.map(s).join(`
5
+ `)+(o.length>0?`
6
+ `:"")},flush(){let r="";n.length>0&&(r+=s(n),n="");let o=t.flush();return o.length>0&&(r+=`data: ${JSON.stringify({type:"text-delta",delta:o})}
7
+
8
+ `),r},createByteTransformStream(){let r=new TextDecoder,o=new TextEncoder;return new TransformStream({transform:(e,c)=>{let f=r.decode(e,{stream:true}),u=this.push(f);u.length>0&&c.enqueue(o.encode(u));},flush:e=>{let c=this.push(r.decode())+this.flush();c.length>0&&e.enqueue(o.encode(c));}})}}}var T=new WeakMap;function st(i,t){if(t.vault)return t.vault;let n=T.get(i);if(n)return n;if(i.prompt&&typeof i.prompt=="object"){let s=T.get(i.prompt);if(s)return s}let a=new w(t);return T.set(i,a),i.prompt&&typeof i.prompt=="object"&&T.set(i.prompt,a),a}function Ot(i={}){let t=i.restoreOutput??true,n=i.rehydrateToolCalls??true;return {specificationVersion:i.specificationVersion??"v3",async transformParams({params:s}){let r=i.vault??new w(i),o={...s};if(Array.isArray(s.prompt)){let e=r.redactObject(s.prompt).value;o.prompt=e,T.set(e,r);}return T.set(o,r),o},async wrapGenerate({doGenerate:s,params:r}){let o=st(r,i),e=await s();if(!t)return e;let c={...e};return typeof c.text=="string"&&(c.text=o.restore(c.text)),Array.isArray(c.content)&&(c.content=c.content.map(f=>{if(!f||typeof f!="object")return f;let u={...f};return (u.type==="text"||u.type==="reasoning")&&typeof u.text=="string"?u.text=o.restore(u.text):n&&u.type==="tool-call"&&(typeof u.input=="string"?u.input=o.restore(u.input):u.input&&typeof u.input=="object"&&(u.input=o.restoreObject(u.input)),typeof u.args=="string"?u.args=o.restore(u.args):u.args&&typeof u.args=="object"&&(u.args=o.restoreObject(u.args))),u})),c},async wrapStream({doStream:s,params:r}){let o=st(r,i),{stream:e,...c}=await s();if(!t)return {stream:e,...c};let f=k(o),u=k(o);return {stream:e.pipeThrough(new TransformStream({transform(d,p){if(!d||typeof d!="object"){p.enqueue(d);return}let g={...d};if(g.type==="text-delta"){if(typeof g.delta=="string"){let h=f.push(g.delta);h.length>0&&p.enqueue({...g,delta:h});return}if(typeof g.textDelta=="string"){let h=f.push(g.textDelta);h.length>0&&p.enqueue({...g,textDelta:h});return}}if(g.type==="reasoning-delta"&&typeof g.delta=="string"){let h=u.push(g.delta);h.length>0&&p.enqueue({...g,delta:h});return}if(n&&g.type==="tool-call"&&(typeof g.input=="string"&&(g.input=o.restore(g.input)),typeof g.args=="string"&&(g.args=o.restore(g.args))),g.type==="finish"||g.type==="text-end"){let h=f.flush();h.length>0&&p.enqueue({type:"text-delta",id:g.id??"0",delta:h,textDelta:h});let y=u.flush();y.length>0&&p.enqueue({type:"reasoning-delta",id:g.id??"0",delta:y});}p.enqueue(g);},flush(d){let p=f.flush();p.length>0&&d.enqueue({type:"text-delta",id:"0",delta:p,textDelta:p});}})),...c}}}}function Pt(i,t={}){let n=t.restoreOutput??true,a=(s,r)=>async(o,e)=>{let c=t.vault??new w(t),f=c.redactObject(o).value,u=await s.call(r,f,e);if(!n||!u)return u;if(typeof u[Symbol.asyncIterator]=="function"){let l=k(c);async function*d(){for await(let g of u){let h=it(g),y=h?.choices?.[0]?.delta;y&&typeof y.content=="string"?y.content=l.push(y.content):h?.type==="response.output_text.delta"&&typeof h.delta=="string"&&(h.delta=l.push(h.delta)),yield h;}let p=l.flush();p.length>0&&(yield {choices:[{index:0,delta:{content:p}}]});}return d()}return c.restoreObject(u)};return new Proxy(i,{get(s,r,o){return r==="chat"&&s.chat?.completions?.create?new Proxy(s.chat,{get(e,c){return c==="completions"?new Proxy(e.completions,{get(f,u){return u==="create"?a(f.create,f):Reflect.get(f,u)}}):Reflect.get(e,c)}}):r==="responses"&&s.responses?.create?new Proxy(s.responses,{get(e,c){return c==="create"?a(e.create,e):Reflect.get(e,c)}}):Reflect.get(s,r,o)}})}function Ct(i,t={}){let n=t.restoreOutput??true;return new Proxy(i,{get(a,s,r){return s==="messages"&&a.messages?.create?new Proxy(a.messages,{get(o,e){return e==="create"?async(c,f)=>{let u=t.vault??new w(t),l=u.redactObject(c).value,d=await o.create.call(o,l,f);if(!n||!d)return d;if(typeof d[Symbol.asyncIterator]=="function"){let p=k(u);async function*g(){for await(let h of d){let y=it(h);if(y?.type==="content_block_delta"&&y?.delta?.type==="text_delta"&&typeof y.delta.text=="string"&&(y.delta.text=p.push(y.delta.text)),y?.type==="message_stop"){let m=p.flush();m.length>0&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:m}});}yield y;}}return g()}return u.restoreObject(d)}:Reflect.get(o,e)}}):Reflect.get(a,s,r)}})}function It(i=globalThis.fetch,t={}){let n=t.restoreOutput??true;return async(a,s)=>{let r=t.vault??new w(t),o=s;if(s&&typeof s.body=="string")try{let f=JSON.parse(s.body),u=r.redactObject(f).value;o={...s,body:JSON.stringify(u)};}catch{o={...s,body:r.redactText(s.body).value};}let e=await i(a,o);if(!n)return e;let c=e.headers.get("content-type")??"";if(c.includes("text/event-stream")&&e.body){let f=nt(r),u=e.body.pipeThrough(f.createByteTransformStream());return new Response(u,{status:e.status,statusText:e.statusText,headers:e.headers})}if(c.includes("application/json")){let f=await e.text();try{let u=JSON.parse(f),l=r.restoreObject(u);return new Response(JSON.stringify(l),{status:e.status,statusText:e.statusText,headers:e.headers})}catch{return new Response(r.restore(f),{status:e.status,statusText:e.statusText,headers:e.headers})}}return e}}function it(i){try{return structuredClone(i)}catch{return JSON.parse(JSON.stringify(i))}}exports.redactMiddleware=Ot;exports.wrapAnthropic=Ct;exports.wrapFetch=It;exports.wrapOpenAI=Pt;
package/dist/ai.d.cts ADDED
@@ -0,0 +1,56 @@
1
+ import { V as Vault } from './engine-CBII6Rkn.cjs';
2
+ import { R as RedactOptions } from './types-DZbmtyhn.cjs';
3
+
4
+ interface AiAdapterOptions extends RedactOptions {
5
+ /** Shared vault instance across turns; if omitted, creates an isolated per-request vault. */
6
+ vault?: Vault;
7
+ /** Restore tokens inside generated text & streamed deltas (default true). */
8
+ restoreOutput?: boolean;
9
+ /** Restore tokens inside LLM-generated tool-call arguments before local execution (default true). */
10
+ rehydrateToolCalls?: boolean;
11
+ /** Vercel AI SDK middleware specification version ('v2' | 'v3' | 'v4'). Default 'v3'. */
12
+ specificationVersion?: 'v2' | 'v3' | 'v4';
13
+ }
14
+ /**
15
+ * Drop-in LanguageModelMiddleware compatible with Vercel AI SDK v5 (v2 spec),
16
+ * v6 (v3 spec), and v7 (v4 spec) via zero-dep structural typing.
17
+ *
18
+ * Usage:
19
+ * const model = wrapLanguageModel({ model: openai('gpt-4o'), middleware: redactMiddleware() });
20
+ */
21
+ declare function redactMiddleware(options?: AiAdapterOptions): {
22
+ specificationVersion: "v2" | "v3" | "v4";
23
+ transformParams({ params }: {
24
+ params: Record<string, unknown>;
25
+ }): Promise<{
26
+ [x: string]: unknown;
27
+ }>;
28
+ wrapGenerate({ doGenerate, params, }: {
29
+ doGenerate: () => Promise<Record<string, unknown>>;
30
+ params: Record<string, unknown>;
31
+ }): Promise<Record<string, unknown>>;
32
+ wrapStream({ doStream, params, }: {
33
+ doStream: () => Promise<{
34
+ stream: ReadableStream<Record<string, unknown>>;
35
+ } & Record<string, unknown>>;
36
+ params: Record<string, unknown>;
37
+ }): Promise<{
38
+ stream: ReadableStream<Record<string, unknown>>;
39
+ }>;
40
+ };
41
+ /**
42
+ * Wraps an OpenAI SDK client instance (`new OpenAI()`) to scrub messages/input
43
+ * and transparently restore responses & streaming async iterables.
44
+ */
45
+ declare function wrapOpenAI<T extends Record<string, any>>(client: T, options?: AiAdapterOptions): T;
46
+ /**
47
+ * Wraps an Anthropic SDK client instance (`new Anthropic()`) to scrub outgoing messages
48
+ * and restore non-streaming & streaming message responses.
49
+ */
50
+ declare function wrapAnthropic<T extends Record<string, any>>(client: T, options?: AiAdapterOptions): T;
51
+ /**
52
+ * Universal fetch() wrapper that scrubs JSON request payloads and restores JSON or SSE responses.
53
+ */
54
+ declare function wrapFetch(fetchFn?: typeof fetch, options?: AiAdapterOptions): typeof fetch;
55
+
56
+ export { type AiAdapterOptions, redactMiddleware, wrapAnthropic, wrapFetch, wrapOpenAI };
package/dist/ai.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { V as Vault } from './engine-DXYt06CR.js';
2
+ import { R as RedactOptions } from './types-DZbmtyhn.js';
3
+
4
+ interface AiAdapterOptions extends RedactOptions {
5
+ /** Shared vault instance across turns; if omitted, creates an isolated per-request vault. */
6
+ vault?: Vault;
7
+ /** Restore tokens inside generated text & streamed deltas (default true). */
8
+ restoreOutput?: boolean;
9
+ /** Restore tokens inside LLM-generated tool-call arguments before local execution (default true). */
10
+ rehydrateToolCalls?: boolean;
11
+ /** Vercel AI SDK middleware specification version ('v2' | 'v3' | 'v4'). Default 'v3'. */
12
+ specificationVersion?: 'v2' | 'v3' | 'v4';
13
+ }
14
+ /**
15
+ * Drop-in LanguageModelMiddleware compatible with Vercel AI SDK v5 (v2 spec),
16
+ * v6 (v3 spec), and v7 (v4 spec) via zero-dep structural typing.
17
+ *
18
+ * Usage:
19
+ * const model = wrapLanguageModel({ model: openai('gpt-4o'), middleware: redactMiddleware() });
20
+ */
21
+ declare function redactMiddleware(options?: AiAdapterOptions): {
22
+ specificationVersion: "v2" | "v3" | "v4";
23
+ transformParams({ params }: {
24
+ params: Record<string, unknown>;
25
+ }): Promise<{
26
+ [x: string]: unknown;
27
+ }>;
28
+ wrapGenerate({ doGenerate, params, }: {
29
+ doGenerate: () => Promise<Record<string, unknown>>;
30
+ params: Record<string, unknown>;
31
+ }): Promise<Record<string, unknown>>;
32
+ wrapStream({ doStream, params, }: {
33
+ doStream: () => Promise<{
34
+ stream: ReadableStream<Record<string, unknown>>;
35
+ } & Record<string, unknown>>;
36
+ params: Record<string, unknown>;
37
+ }): Promise<{
38
+ stream: ReadableStream<Record<string, unknown>>;
39
+ }>;
40
+ };
41
+ /**
42
+ * Wraps an OpenAI SDK client instance (`new OpenAI()`) to scrub messages/input
43
+ * and transparently restore responses & streaming async iterables.
44
+ */
45
+ declare function wrapOpenAI<T extends Record<string, any>>(client: T, options?: AiAdapterOptions): T;
46
+ /**
47
+ * Wraps an Anthropic SDK client instance (`new Anthropic()`) to scrub outgoing messages
48
+ * and restore non-streaming & streaming message responses.
49
+ */
50
+ declare function wrapAnthropic<T extends Record<string, any>>(client: T, options?: AiAdapterOptions): T;
51
+ /**
52
+ * Universal fetch() wrapper that scrubs JSON request payloads and restores JSON or SSE responses.
53
+ */
54
+ declare function wrapFetch(fetchFn?: typeof fetch, options?: AiAdapterOptions): typeof fetch;
55
+
56
+ export { type AiAdapterOptions, redactMiddleware, wrapAnthropic, wrapFetch, wrapOpenAI };
package/dist/ai.mjs ADDED
@@ -0,0 +1,8 @@
1
+ var ct=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),ut=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),V=new TextEncoder;function A(i,t){return i>>>t|i<<32-t}function I(i){let t=i.length*8,n=Math.ceil((i.length+9)/64)*64,a=new Uint8Array(n);a.set(i),a[i.length]=128;let s=new DataView(a.buffer),r=Math.floor(t/4294967296),o=t>>>0;s.setUint32(n-8,r,false),s.setUint32(n-4,o,false);let e=new Uint32Array(ut),c=new Uint32Array(64);for(let l=0;l<n;l+=64){for(let b=0;b<16;b++)c[b]=s.getUint32(l+b*4,false);for(let b=16;b<64;b++){let E=c[b-15],S=c[b-2],C=A(E,7)^A(E,18)^E>>>3,D=A(S,17)^A(S,19)^S>>>10;c[b]=c[b-16]+C+c[b-7]+D>>>0;}let d=e[0],p=e[1],g=e[2],h=e[3],y=e[4],m=e[5],P=e[6],N=e[7];for(let b=0;b<64;b++){let E=A(y,6)^A(y,11)^A(y,25),S=y&m^~y&P,C=N+E+S+ct[b]+c[b]>>>0,D=A(d,2)^A(d,13)^A(d,22),at=d&p^d&g^p&g,ot=D+at>>>0;N=P,P=m,m=y,y=h+C>>>0,h=g,g=p,p=d,d=C+ot>>>0;}e[0]=e[0]+d>>>0,e[1]=e[1]+p>>>0,e[2]=e[2]+g>>>0,e[3]=e[3]+h>>>0,e[4]=e[4]+y>>>0,e[5]=e[5]+m>>>0,e[6]=e[6]+P>>>0,e[7]=e[7]+N>>>0;}let f=new Uint8Array(32),u=new DataView(f.buffer);for(let l=0;l<8;l++)u.setUint32(l*4,e[l],false);return f}function M(i,t,n=64){let a=V.encode(i),s=a.length>64?I(a):a,r=new Uint8Array(64);r.set(s);let o=new Uint8Array(64),e=new Uint8Array(64);for(let p=0;p<64;p++){let g=r[p];o[p]=g^92,e[p]=g^54;}let c=V.encode(t),f=new Uint8Array(64+c.length);f.set(e,0),f.set(c,64);let u=I(f),l=new Uint8Array(96);l.set(o,0),l.set(u,64);let d=I(l);return Z(d).slice(0,n)}function z(i,t=64){return Z(I(V.encode(i))).slice(0,t)}function Z(i){let t="";for(let n=0;n<i.length;n++)t+=i[n].toString(16).padStart(2,"0");return t}function U(i=8){let t=new Uint8Array(i);if(typeof globalThis.crypto?.getRandomValues=="function")globalThis.crypto.getRandomValues(t);else for(let n=0;n<i;n++)t[n]=Math.floor(Math.random()*256);return Z(t)}function R(i){return i.replace(/\D/g,"")}function j(i){let t=R(i);if(t.length<13||t.length>19||/^(\d)\1+$/.test(t))return false;let n=0,a=false;for(let s=t.length-1;s>=0;s--){let r=t.charCodeAt(s)-48;a&&(r*=2,r>9&&(r-=9)),n+=r,a=!a;}return n%10===0}function F(i){let t=R(i);if(!/^[12]\d{9}$/.test(t))return false;let n="80840"+t,a=0,s=false;for(let r=n.length-1;r>=0;r--){let o=n.charCodeAt(r)-48;s&&(o*=2,o>9&&(o-=9)),a+=o,s=!s;}return a%10===0}function L(i){let t=i.trim().toUpperCase();if(!/^[ABFGMPRX][A-Z9]\d{7}$/.test(t))return false;let n=o=>t.charCodeAt(2+o)-48,a=n(0)+n(2)+n(4),s=n(1)+n(3)+n(5);return (a+2*s)%10===n(6)}var _="ACDEFGHJKMNPQRTUVWXY",K="0123456789"+_;function $(i){let t=i.replace(/-/g,"").toUpperCase();if(t.length!==11)return false;let n=t.charCodeAt(0);return !(n<49||n>57||!_.includes(t[1])||!K.includes(t[2])||!/\d/.test(t[3])||!_.includes(t[4])||!K.includes(t[5])||!/\d/.test(t[6])||!_.includes(t[7])||!_.includes(t[8])||!/\d\d/.test(t.slice(9,11)))}var lt={AD:24,AE:23,AL:28,AT:20,AZ:28,BA:20,BE:16,BG:22,BH:22,BR:29,BY:28,CH:21,CR:22,CY:28,CZ:24,DE:22,DK:18,DO:28,EE:20,EG:29,ES:24,FI:18,FO:18,FR:27,GB:22,GE:22,GI:23,GL:18,GR:27,GT:28,HR:21,HU:28,IE:22,IL:23,IQ:23,IS:26,IT:27,JO:30,KW:30,KZ:20,LB:28,LC:32,LI:21,LT:20,LU:20,LV:21,MC:27,MD:24,ME:22,MK:19,MR:27,MT:31,MU:30,NL:18,NO:15,PK:24,PL:28,PS:29,PT:25,QA:29,RO:24,RS:22,SA:24,SE:24,SI:19,SK:24,SM:27,ST:25,SV:28,TL:23,TN:24,TR:26,UA:29,VA:22,VG:24,XK:20};function B(i){let t=i.replace(/[\s-]+/g,"").toUpperCase();if(!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(t))return false;let n=lt[t.slice(0,2)];if(n!==void 0&&t.length!==n)return false;let a=t.slice(4)+t.slice(0,4),s=0;for(let r=0;r<a.length;r++){let o=a.charCodeAt(r);if(o>=48&&o<=57)s=(s*10+(o-48))%97;else if(o>=65&&o<=90){let e=o-55;s=(s*100+e)%97;}else return false}return s===1}function H(i){let t=R(i);if(t.length!==10||/^(\d)\1+$/.test(t))return false;let n=0;for(let r=0;r<9;r++)n+=(t.charCodeAt(r)-48)*(10-r);let s=11-n%11;return s===11&&(s=0),s===10?false:s===t.charCodeAt(9)-48}function G(i,t){let n=i.trim(),a=/[-\s]/.test(n),s=R(n);if(s.length!==9)return false;let r=Number(s.slice(0,3)),o=Number(s.slice(3,5)),e=Number(s.slice(5,9));if(r===0||r===666||r>=900||o===0||e===0||/^(\d)\1+$/.test(s))return false;if(!a&&t){let c=t.fullText.slice(Math.max(0,t.start-36),t.start);return /\b(ssn|social[\s_-]?security|tin)\b/i.test(c)}return true}var ft=[[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],[9,8,7,6,5,4,3,2,1,0]],dt=[[0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]];function J(i){let t=R(i);if(!/^[2-9]\d{11}$/.test(t))return false;let n=0;for(let a=0;a<t.length;a++){let s=t.charCodeAt(t.length-1-a)-48;n=ft[n][dt[a%8][s]];}return n===0}function q(i){let t=R(i);if(!/^[1-9]\d{10}$/.test(t))return false;let n=new Array(10).fill(0);for(let e=0;e<10;e++)n[t.charCodeAt(e)-48]+=1;let a=n.filter(e=>e===2||e===3).length,s=Math.max(...n);if(a!==1||s>3)return false;let r=10;for(let e=0;e<10;e++){let c=(t.charCodeAt(e)-48+r)%10;c===0&&(c=10),r=c*2%11;}let o=11-r;return o===10&&(o=0),o===t.charCodeAt(10)-48}function Y(i){let t=i.split(".");if(t.length!==3)return false;let n=t[0];if(!n.startsWith("eyJ"))return false;try{let a=n.replace(/-/g,"+").replace(/_/g,"/"),s=(4-a.length%4)%4,r=atob(a+"=".repeat(s));return r.startsWith("{")&&r.includes('"')}catch{return false}}function W(i){let t=i.split(".").map(Number);if(t.length!==4)return false;let[n,a]=t;return n===void 0||a===void 0?false:n===10||n===127||n===0||n===192&&a===168||n===172&&a>=16&&a<=31||n===169&&a===254}function X(i){let t=i.split(".");if(t.length!==4)return false;for(let n of t){if(n.length===0||n.length>1&&n.startsWith("0"))return false;let a=Number(n);if(!Number.isInteger(a)||a<0||a>255)return false}return true}function Q(i){if(i.length===0)return 0;let t=new Map;for(let s=0;s<i.length;s++){let r=i.charCodeAt(s);t.set(r,(t.get(r)??0)+1);}let n=0,a=i.length;for(let s of t.values()){let r=s/a;n-=r*Math.log2(r);}return n}var x=["default","secrets","hipaa","gdpr","strict"],v=["default","hipaa","gdpr","strict"],O=["hipaa","strict"],pt=["gdpr","strict"],tt=[{id:"pem-private-key",category:"PRIVATE_KEY",priority:100,presets:x,pattern:/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----[\s\S]{16,8192}?-----END (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----/g},{id:"connection-uri-password",category:"CONNECTION_URI",priority:96,presets:x,captureGroup:1,pattern:/\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis(?:s)?|amqp(?:s)?|mssql|clickhouse|cockroachdb):\/\/[^:\s/@]+:([^@\s/]{3,256})@[^\s"'<>]+/gi},{id:"anthropic-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-ant-(?:api\d{2}|admin\d{2}|oat\d{2}|[a-z0-9]+)-[A-Za-z0-9_-]{24,}\b/g},{id:"openai-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{24,}\b|\bsk-[A-Za-z0-9]{16,}T3BlbkFJ[A-Za-z0-9]{16,}\b/g},{id:"github-token",category:"API_KEY",priority:95,presets:x,pattern:/\b(?:gh[pousr]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9]{22}_[A-Za-z0-9]{40,})\b/g},{id:"aws-access-key",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:AKIA|ASIA|AROA|AIDA)[0-9A-Z]{16}\b/g},{id:"stripe-secret",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:sk_live|rk_live|whsec)_[A-Za-z0-9]{20,}\b/g},{id:"google-api-key",category:"API_KEY",priority:93,presets:x,pattern:/\bAIza[0-9A-Za-z_-]{35}\b/g},{id:"slack-token",category:"TOKEN",priority:93,presets:x,pattern:/\bxox[baprs]-[0-9A-Za-z-]{14,}\b|https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g},{id:"discord-webhook",category:"SECRET",priority:92,presets:x,pattern:/https:\/\/discord(?:app)?\.com\/api\/webhooks\/\d{16,22}\/[A-Za-z0-9_-]{40,}/g},{id:"provider-prefixed-keys",category:"API_KEY",priority:92,presets:x,pattern:/\b(?:hf_[A-Za-z0-9]{30,}|gsk_[A-Za-z0-9]{36,}|xai-[A-Za-z0-9]{36,}|pplx-[A-Za-z0-9]{36,}|sbp_[A-Za-z0-9]{36,}|sb_secret_[A-Za-z0-9_-]{24,}|re_[A-Za-z0-9_]{24,}|npm_[A-Za-z0-9]{36}|pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}|SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b/g},{id:"jwt-token",category:"JWT",priority:90,presets:x,pattern:/\beyJ[A-Za-z0-9_-]{6,}\.eyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{8,}\b/g,validate:i=>Y(i)},{id:"bearer-auth-header",category:"TOKEN",priority:88,presets:x,captureGroup:1,pattern:/\b(?:Authorization|Proxy-Authorization)\s*[:=]\s*["']?(?:Bearer|Basic|Token)\s+([A-Za-z0-9._~+/=-]{12,})["']?/gi},{id:"contextual-secret-assignment",category:"SECRET",priority:72,presets:x,captureGroup:1,pattern:/\b(?:api[_-]?key|secret[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|client[_-]?secret|private[_-]?key|aws_secret_access_key|password|passwd|pwd|signing[_-]?secret)\b\s*[:=]\s*["']?([^\s"',;}{]{10,128})["']?/gi,validate:i=>!i.startsWith("[")&&!i.startsWith("<")&&Q(i)>=2.8},{id:"medicare-mbi",category:"MBI",priority:84,presets:O,pattern:/\b[1-9][AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y]{2}\d{2}\b/gi,validate:i=>$(i)},{id:"us-dea",category:"DEA",priority:83,presets:O,pattern:/\b[ABFGMPRX][A-Z9]\d{7}\b/g,validate:i=>L(i)},{id:"us-npi",category:"NPI",priority:80,presets:O,contextWindow:40,contextRegex:/\b(?:npi|provider|prescriber|practitioner|physician)\b/i,pattern:/\b[12]\d{9}\b/g,validate:i=>F(i)},{id:"uk-nhs-number",category:"NHS",priority:80,presets:["hipaa","gdpr","strict"],contextWindow:40,contextRegex:/\b(?:nhs|patient|health|care|medical)\b/i,pattern:/\b\d{3}[-\s]?\d{3}[-\s]?\d{4}\b/g,validate:i=>H(i)},{id:"medical-record-number",category:"MRN",priority:78,presets:O,captureGroup:1,pattern:/\b(?:mrn|medical[\s_-]?record(?:[\s_-]?number)?|patient[\s_-]?id)\s*[:=#]?\s*([A-Z0-9-]{5,20})\b/gi},{id:"iban",category:"IBAN",priority:84,presets:v,pattern:/\b[A-Z]{2}\d{2}(?:[\s-]?[A-Z0-9]){11,30}\b/g,validate:i=>B(i)},{id:"credit-card",category:"CREDIT_CARD",priority:82,presets:v,pattern:/\b(?:\d[ -]?){13,18}\d\b/g,validate:i=>{let t=i.replace(/\D/g,"");return /^(?:4\d{12}(?:\d{3})?(?:\d{3})?|5[1-5]\d{14}|2(?:2[2-9]|[3-6]\d|7[01]|720)\d{12}|3[47]\d{13}|6(?:011|5\d\d)\d{12}|3(?:0[0-5]|[68]\d)\d{11}|(?:2131|1800|35\d{3})\d{11})$/.test(t)&&j(t)}},{id:"us-ssn",category:"SSN",priority:81,presets:v,pattern:/\b\d{3}[-\s]\d{2}[-\s]\d{4}\b|\b\d{9}\b/g,validate:(i,t)=>G(i,t)},{id:"aadhaar-in",category:"AADHAAR",priority:76,presets:["gdpr","strict"],contextWindow:40,contextRegex:/\b(?:aadhaar|aadhar|uidai)\b/i,pattern:/\b[2-9]\d{3}[-\s]?\d{4}[-\s]?\d{4}\b/g,validate:i=>J(i)},{id:"de-tax-id",category:"TAX_ID",priority:76,presets:pt,contextWindow:45,contextRegex:/\b(?:steuer|tax|tin|idnr|identifikationsnummer)\b/i,pattern:/\b[1-9]\d{10}\b/g,validate:i=>q(i)},{id:"email",category:"EMAIL",priority:75,presets:v,pattern:/\b[A-Za-z0-9._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\.)+[A-Za-z]{2,24}\b/g},{id:"phone",category:"PHONE",priority:65,presets:v,pattern:/(?:\+\d{1,3}[-.\s]?)?(?:\(\d{2,4}\)[-.\s]?|\b\d{3}[-.\s])\d{3,4}[-.\s]\d{4}\b|\+\d{1,3}[-.\s]?\d{2,4}[-.\s]?\d{3,4}[-.\s]?\d{3,4}\b/g,validate:i=>{let t=i.replace(/\D/g,"");return t.length>=10&&t.length<=15&&!/^(\d)\1+$/.test(t)}},{id:"ipv4",category:"IP_ADDRESS",priority:60,presets:v,pattern:/\b(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}\b/g,validate:i=>X(i)},{id:"ipv6",category:"IP_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b/g},{id:"mac-address",category:"MAC_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g},{id:"labeled-person-name",category:"PERSON",priority:55,presets:["hipaa","strict"],captureGroup:1,pattern:/\b(?:Patient(?:\s+Name)?|Dr\.|Doctor|Clinician|Provider|Mr\.|Mrs\.|Ms\.|Full\s+Name|Beneficiary)\s*[:.]?\s*([A-Z][a-z]{1,24}(?:\s+[A-Z]\.?)?(?:\s+[A-Z][a-z]{1,24}){1,2})/g},{id:"dob-or-clinical-date",category:"DATE",priority:52,presets:O,contextWindow:40,contextRegex:/\b(?:dob|birth|born|admit(?:ted)?|discharg(?:e|ed)|visit|encounter|date)\b/i,pattern:/\b(?:\d{4}-\d{2}-\d{2}|(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g}];var gt=/^(?:password|passwd|pwd|passphrase|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|authorization|cookie|set-cookie|x-api-key|client[_-]?secret|private[_-]?key|ssn|social[_-]?security(?:[_-]?number)?|cvv|cvc|pin|iban|dob|birth[_-]?date|mrn)$/i,ht=/\[[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?\]|<[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?>/g;function et(i){let t=i.toLowerCase();return t.includes("ssn")||t.includes("social")?"SSN":t.includes("iban")?"IBAN":t.includes("mrn")?"MRN":t.includes("dob")||t.includes("birth")?"DATE":t.includes("password")||t.includes("passwd")||t.includes("secret")||t==="cvv"||t==="cvc"||t==="pin"?"SECRET":t.includes("token")||t==="authorization"||t==="cookie"||t==="set-cookie"?"TOKEN":t.includes("key")?"API_KEY":"CUSTOM"}function yt(i){let t=i.preset??"default",n=i.rules?[...i.rules]:tt.filter(r=>r.presets.includes(t)),s=[...(i.customRules??[]).map(r=>({id:r.id,category:r.category??"CUSTOM",pattern:r.pattern,captureGroup:r.captureGroup,priority:r.priority??85,presets:["default","secrets","hipaa","gdpr","strict"],validate:r.validate})),...n];if(i.categories?.length){let r=new Set(i.categories);s=s.filter(o=>r.has(o.category));}if(i.excludeCategories?.length){let r=new Set(i.excludeCategories);s=s.filter(o=>!r.has(o.category));}return s}function bt(i,t){let n=[];for(let a of t){if(!a||a.length<4)continue;let s=0;for(;;){let r=i.indexOf(a,s);if(r===-1)break;n.push({id:"literal-secret",category:"SECRET",priority:99,start:r,end:r+a.length,value:a}),s=r+a.length;}}return n}function rt(i,t,n){let a=[],s=n.allowlist?new Set(n.allowlist):void 0,r=n.redactPrivateIps??(n.preset==="strict"||n.preset==="hipaa");n.literals?.length&&a.push(...bt(i,n.literals));for(let e of t){let c=e.pattern.flags.includes("g")?e.pattern.flags:e.pattern.flags+"g",f=new RegExp(e.pattern.source,c),u;for(;(u=f.exec(i))!==null;){if(u[0].length===0){f.lastIndex+=1;continue}let l=u.index,d=u[0];if(e.captureGroup!==void 0&&u[e.captureGroup]!==void 0){let g=u[e.captureGroup],h=u[0].indexOf(g);h!==-1&&(l=u.index+h,d=g);}let p=l+d.length;if(!s?.has(d)&&!(e.id==="ipv4"&&!r&&W(d))){if(e.contextRegex){let g=e.contextWindow??40,h=i.slice(Math.max(0,l-g),l),y=i.slice(p,Math.min(i.length,p+g));if(!e.contextRegex.test(h)&&!e.contextRegex.test(y))continue}if(e.validate){let g={fullText:i,match:u,start:l,end:p,value:d};if(!e.validate(d,g))continue}a.push({id:e.id,category:e.category,priority:e.priority,start:l,end:p,value:d});}}}a.sort((e,c)=>{if(c.priority!==e.priority)return c.priority-e.priority;let f=c.end-c.start-(e.end-e.start);return f!==0?f:e.start-c.start});let o=[];for(let e of a){let c=false;for(let f of o)if(e.start<f.end&&e.end>f.start){c=true;break}c||o.push(e);}return o.sort((e,c)=>e.start-c.start),o}var w=class i{options;rules;tokenFormat;vaultKey;sensitiveKeyRe;forward=new Map;reverse=new Map;counters=new Map;reservedTokens=new Set;_version=0;constructor(t={}){this.options=t,this.rules=yt(t),this.tokenFormat=t.tokenFormat??"bracket",this.vaultKey=t.secret??U(16),this.sensitiveKeyRe=t.sensitiveKeys?.length?new RegExp(`^(?:${t.sensitiveKeys.map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})$`,"i"):gt;}get version(){return this._version}fingerprint(t){return M(this.vaultKey,t,12)}reserveExistingTokens(t){let n=new RegExp(ht.source,"g"),a;for(;(a=n.exec(t))!==null;)this.reverse.has(a[0])||this.reservedTokens.add(a[0]);}tokenize(t,n){let a=`${t}:${n}`,s=this.forward.get(a);if(s!==void 0)return s;if(this.tokenFormat==="mask")return (this.options.maskChar??"*").repeat(Math.min(Math.max(n.length,4),16));if(this.tokenFormat==="hash"){let e=M(this.vaultKey,a,8),c=`[${t}:${e}]`;return this.forward.set(a,c),this.reverse.set(c,{category:t,value:n}),this._version+=1,c}let r=this.counters.get(t)??0,o;do if(r+=1,this.tokenFormat==="angle")o=`<${t}_${r}>`;else if(this.tokenFormat==="signed"){let e=M(this.vaultKey,`${t}:${r}:${n}`,4);o=`[${t}_${r}#${e}]`;}else o=`[${t}_${r}]`;while(this.reservedTokens.has(o)||this.reverse.has(o));return this.counters.set(t,r),this.forward.set(a,o),this.reverse.set(o,{category:t,value:n}),this._version+=1,o}scan(t){return typeof t!="string"||t.length===0?[]:rt(t,this.rules,this.options).map(a=>({id:a.id,category:a.category,start:a.start,end:a.end,token:`[${a.category}]`,length:a.value.length,fingerprint:z(a.value,12)}))}redactText(t){if(typeof t!="string"||t.length===0)return {value:t,findings:[],count:0};this.reserveExistingTokens(t);let n=rt(t,this.rules,this.options);if(n.length===0)return {value:t,findings:[],count:0};let a="",s=0,r=[];for(let o of n){a+=t.slice(s,o.start);let e=this.tokenize(o.category,o.value);a+=e,s=o.end,r.push({id:o.id,category:o.category,start:o.start,end:o.end,token:e,length:o.value.length,fingerprint:this.fingerprint(o.value)});}return a+=t.slice(s),{value:a,findings:r,count:r.length}}redactObject(t){let n=[],a=this.options.maxDepth??32,s=new WeakMap,r=(e,c,f)=>{if(e==null)return e;if(typeof e=="string"){if(f&&this.sensitiveKeyRe.test(f)&&e.length>0&&!this.reverse.has(e)){let d=et(f),p=this.tokenize(d,e);return n.push({id:"sensitive-key",category:d,start:0,end:e.length,token:p,length:e.length,fingerprint:this.fingerprint(e)}),p}let l=this.redactText(e);return l.count>0&&n.push(...l.findings),l.value}if(typeof e!="object")return e;if(c>=a)return "[MAX_DEPTH_TRUNCATED]";if(s.has(e))return s.get(e);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e.source,e.flags);if(e instanceof URL){let l=new URL(e.toString());l.password&&(l.password=this.tokenize("SECRET",l.password));let d=[];l.searchParams.forEach((p,g)=>{d.push([g,p]);});for(let[p,g]of d)if(this.sensitiveKeyRe.test(p)&&g)l.searchParams.set(p,this.tokenize(et(p),g));else {let h=this.redactText(g);h.count>0&&(n.push(...h.findings),l.searchParams.set(p,h.value));}return l}if(typeof Headers<"u"&&e instanceof Headers){let l=new Headers;return e.forEach((d,p)=>{l.set(p,r(d,c+1,p));}),l}if(e instanceof Error){let l={name:e.name,message:this.options.redactErrors!==false?r(e.message,c+1):e.message};e.stack!==void 0&&(l.stack=this.options.redactErrors!==false?r(e.stack,c+1):e.stack),"cause"in e&&e.cause!==void 0&&(l.cause=r(e.cause,c+1));for(let d of Object.keys(e))l[d]=r(e[d],c+1,d);return l}if(Array.isArray(e)){let l=[];s.set(e,l);for(let d=0;d<e.length;d++)l.push(r(e[d],c+1,f));return l}if(e instanceof Map){let l=new Map;s.set(e,l);for(let[d,p]of e.entries()){let g=typeof d=="string"?d:void 0;l.set(r(d,c+1),r(p,c+1,g));}return l}if(e instanceof Set){let l=new Set;s.set(e,l);for(let d of e.values())l.add(r(d,c+1));return l}let u={};s.set(e,u);for(let[l,d]of Object.entries(e))u[l]=r(d,c+1,l);return u};return {value:r(t,0),findings:n,count:n.length}}redact(t){return typeof t=="string"?this.redactText(t):this.redactObject(t)}restore(t){if(typeof t!="string"||t.length===0||this.reverse.size===0)return t;let a=Array.from(this.reverse.keys()).sort((r,o)=>o.length-r.length).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),s=new RegExp(a.join("|"),"g");return t.replace(s,r=>this.reverse.get(r)?.value??r)}restoreObject(t){let n=new WeakMap,a=(s,r)=>{if(s==null)return s;if(typeof s=="string")return this.restore(s);if(typeof s!="object"||r>=32)return s;if(n.has(s))return n.get(s);if(Array.isArray(s)){let e=[];n.set(s,e);for(let c of s)e.push(a(c,r+1));return e}if(s instanceof Date||s instanceof RegExp||s instanceof URL)return s;let o={};n.set(s,o);for(let[e,c]of Object.entries(s))o[e]=a(c,r+1);return o};return a(t,0)}entries(){return Array.from(this.reverse.entries()).map(([t,n])=>({token:t,category:n.category,value:n.value}))}export(){let t={};for(let[n,a]of this.counters.entries())t[n]=a;return {version:1,tokenFormat:this.tokenFormat,counters:t,entries:this.entries()}}static fromJSON(t,n={}){let a=new i({...n,tokenFormat:t.tokenFormat});for(let[s,r]of Object.entries(t.counters))a.counters.set(s,r);for(let s of t.entries)a.forward.set(`${s.category}:${s.value}`,s.token),a.reverse.set(s.token,{category:s.category,value:s.value});return a._version+=1,a}clear(){this.forward.clear(),this.reverse.clear(),this.counters.clear(),this.reservedTokens.clear(),this._version+=1;}};function k(i){let t=-1,n=new Map,a=new Set,s=new Set,r=0,o=()=>{if(i.version!==t){t=i.version,n=new Map,a=new Set,s=new Set,r=0;for(let{token:f,value:u}of i.entries())if(f){n.set(f,u),s.add(f[0]),f.length>r&&(r=f.length);for(let l=1;l<f.length;l++)a.add(f.slice(0,l));}}},e="",c=f=>{if(o(),e.length===0)return "";if(n.size===0){let d=e;return e="",d}let u="",l=0;for(;l<e.length;){let d=e[l];if(!s.has(d)){u+=d,l+=1;continue}let p=e.slice(l);if(!f&&p.length<r&&a.has(p))break;let g=Math.min(r,p.length),h;for(let y=g;y>=1;y--){let m=p.slice(0,y);if(n.has(m)){h=m;break}}h!==void 0?(u+=n.get(h),l+=h.length):(u+=d,l+=1);}return e=e.slice(l),u};return {push(f){return f?(e+=f,c(false)):""},flush(){return c(true)},async*restoreIterable(f){for await(let l of f){let d=this.push(l);d.length>0&&(yield d);}let u=this.flush();u.length>0&&(yield u);},createTransformStream(){return new TransformStream({transform:(f,u)=>{let l=this.push(f);l.length>0&&u.enqueue(l);},flush:f=>{let u=this.flush();u.length>0&&f.enqueue(u);}})}}}function nt(i){let t=k(i),n="",a=(r,o=false)=>{let e=false;if(Array.isArray(r.choices)){for(let c of r.choices)if(c&&typeof c=="object"){let f=c.delta;f&&typeof f.content=="string"&&(f.content=t.push(f.content)+(o?t.flush():""),e=true);}}if(typeof r.delta=="string"&&(r.type==="text-delta"||r.type==="response.output_text.delta"||r.type==="reasoning-delta")&&(r.delta=t.push(r.delta)+(o?t.flush():""),e=true),r.delta&&typeof r.delta=="object"){let c=r.delta;typeof c.text=="string"&&(c.text=t.push(c.text)+(o?t.flush():""),e=true);}if(Array.isArray(r.candidates))for(let c of r.candidates){let f=c?.content?.parts;if(Array.isArray(f))for(let u of f)typeof u.text=="string"&&(u.text=t.push(u.text)+(o?t.flush():""),e=true);}return e},s=r=>{if(r.startsWith("0:"))try{let e=JSON.parse(r.slice(2));if(typeof e=="string")return "0:"+JSON.stringify(t.push(e))}catch{return r}if(!r.startsWith("data:"))return r;let o=r.slice(5).trim();if(o==="[DONE]"){let e=t.flush();return e.length>0?`data: ${JSON.stringify({choices:[{index:0,delta:{content:e}}]})}
2
+
3
+ `+r:r}try{let e=JSON.parse(o);if(a(e))return "data: "+JSON.stringify(e)}catch{return "data: "+t.push(o)}return r};return {push(r){n+=r;let o=n.split(`
4
+ `);return n=o.pop()??"",o.map(s).join(`
5
+ `)+(o.length>0?`
6
+ `:"")},flush(){let r="";n.length>0&&(r+=s(n),n="");let o=t.flush();return o.length>0&&(r+=`data: ${JSON.stringify({type:"text-delta",delta:o})}
7
+
8
+ `),r},createByteTransformStream(){let r=new TextDecoder,o=new TextEncoder;return new TransformStream({transform:(e,c)=>{let f=r.decode(e,{stream:true}),u=this.push(f);u.length>0&&c.enqueue(o.encode(u));},flush:e=>{let c=this.push(r.decode())+this.flush();c.length>0&&e.enqueue(o.encode(c));}})}}}var T=new WeakMap;function st(i,t){if(t.vault)return t.vault;let n=T.get(i);if(n)return n;if(i.prompt&&typeof i.prompt=="object"){let s=T.get(i.prompt);if(s)return s}let a=new w(t);return T.set(i,a),i.prompt&&typeof i.prompt=="object"&&T.set(i.prompt,a),a}function Ot(i={}){let t=i.restoreOutput??true,n=i.rehydrateToolCalls??true;return {specificationVersion:i.specificationVersion??"v3",async transformParams({params:s}){let r=i.vault??new w(i),o={...s};if(Array.isArray(s.prompt)){let e=r.redactObject(s.prompt).value;o.prompt=e,T.set(e,r);}return T.set(o,r),o},async wrapGenerate({doGenerate:s,params:r}){let o=st(r,i),e=await s();if(!t)return e;let c={...e};return typeof c.text=="string"&&(c.text=o.restore(c.text)),Array.isArray(c.content)&&(c.content=c.content.map(f=>{if(!f||typeof f!="object")return f;let u={...f};return (u.type==="text"||u.type==="reasoning")&&typeof u.text=="string"?u.text=o.restore(u.text):n&&u.type==="tool-call"&&(typeof u.input=="string"?u.input=o.restore(u.input):u.input&&typeof u.input=="object"&&(u.input=o.restoreObject(u.input)),typeof u.args=="string"?u.args=o.restore(u.args):u.args&&typeof u.args=="object"&&(u.args=o.restoreObject(u.args))),u})),c},async wrapStream({doStream:s,params:r}){let o=st(r,i),{stream:e,...c}=await s();if(!t)return {stream:e,...c};let f=k(o),u=k(o);return {stream:e.pipeThrough(new TransformStream({transform(d,p){if(!d||typeof d!="object"){p.enqueue(d);return}let g={...d};if(g.type==="text-delta"){if(typeof g.delta=="string"){let h=f.push(g.delta);h.length>0&&p.enqueue({...g,delta:h});return}if(typeof g.textDelta=="string"){let h=f.push(g.textDelta);h.length>0&&p.enqueue({...g,textDelta:h});return}}if(g.type==="reasoning-delta"&&typeof g.delta=="string"){let h=u.push(g.delta);h.length>0&&p.enqueue({...g,delta:h});return}if(n&&g.type==="tool-call"&&(typeof g.input=="string"&&(g.input=o.restore(g.input)),typeof g.args=="string"&&(g.args=o.restore(g.args))),g.type==="finish"||g.type==="text-end"){let h=f.flush();h.length>0&&p.enqueue({type:"text-delta",id:g.id??"0",delta:h,textDelta:h});let y=u.flush();y.length>0&&p.enqueue({type:"reasoning-delta",id:g.id??"0",delta:y});}p.enqueue(g);},flush(d){let p=f.flush();p.length>0&&d.enqueue({type:"text-delta",id:"0",delta:p,textDelta:p});}})),...c}}}}function Pt(i,t={}){let n=t.restoreOutput??true,a=(s,r)=>async(o,e)=>{let c=t.vault??new w(t),f=c.redactObject(o).value,u=await s.call(r,f,e);if(!n||!u)return u;if(typeof u[Symbol.asyncIterator]=="function"){let l=k(c);async function*d(){for await(let g of u){let h=it(g),y=h?.choices?.[0]?.delta;y&&typeof y.content=="string"?y.content=l.push(y.content):h?.type==="response.output_text.delta"&&typeof h.delta=="string"&&(h.delta=l.push(h.delta)),yield h;}let p=l.flush();p.length>0&&(yield {choices:[{index:0,delta:{content:p}}]});}return d()}return c.restoreObject(u)};return new Proxy(i,{get(s,r,o){return r==="chat"&&s.chat?.completions?.create?new Proxy(s.chat,{get(e,c){return c==="completions"?new Proxy(e.completions,{get(f,u){return u==="create"?a(f.create,f):Reflect.get(f,u)}}):Reflect.get(e,c)}}):r==="responses"&&s.responses?.create?new Proxy(s.responses,{get(e,c){return c==="create"?a(e.create,e):Reflect.get(e,c)}}):Reflect.get(s,r,o)}})}function Ct(i,t={}){let n=t.restoreOutput??true;return new Proxy(i,{get(a,s,r){return s==="messages"&&a.messages?.create?new Proxy(a.messages,{get(o,e){return e==="create"?async(c,f)=>{let u=t.vault??new w(t),l=u.redactObject(c).value,d=await o.create.call(o,l,f);if(!n||!d)return d;if(typeof d[Symbol.asyncIterator]=="function"){let p=k(u);async function*g(){for await(let h of d){let y=it(h);if(y?.type==="content_block_delta"&&y?.delta?.type==="text_delta"&&typeof y.delta.text=="string"&&(y.delta.text=p.push(y.delta.text)),y?.type==="message_stop"){let m=p.flush();m.length>0&&(yield {type:"content_block_delta",index:0,delta:{type:"text_delta",text:m}});}yield y;}}return g()}return u.restoreObject(d)}:Reflect.get(o,e)}}):Reflect.get(a,s,r)}})}function It(i=globalThis.fetch,t={}){let n=t.restoreOutput??true;return async(a,s)=>{let r=t.vault??new w(t),o=s;if(s&&typeof s.body=="string")try{let f=JSON.parse(s.body),u=r.redactObject(f).value;o={...s,body:JSON.stringify(u)};}catch{o={...s,body:r.redactText(s.body).value};}let e=await i(a,o);if(!n)return e;let c=e.headers.get("content-type")??"";if(c.includes("text/event-stream")&&e.body){let f=nt(r),u=e.body.pipeThrough(f.createByteTransformStream());return new Response(u,{status:e.status,statusText:e.statusText,headers:e.headers})}if(c.includes("application/json")){let f=await e.text();try{let u=JSON.parse(f),l=r.restoreObject(u);return new Response(JSON.stringify(l),{status:e.status,statusText:e.statusText,headers:e.headers})}catch{return new Response(r.restore(f),{status:e.status,statusText:e.statusText,headers:e.headers})}}return e}}function it(i){try{return structuredClone(i)}catch{return JSON.parse(JSON.stringify(i))}}export{Ot as redactMiddleware,Ct as wrapAnthropic,It as wrapFetch,Pt as wrapOpenAI};
package/dist/cli.cjs ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';var A=require('fs'),P=require('path'),Ce=require('readline');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var A__default=/*#__PURE__*/_interopDefault(A);var P__default=/*#__PURE__*/_interopDefault(P);var Ce__default=/*#__PURE__*/_interopDefault(Ce);var ue=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),de=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),F=new TextEncoder;function w(n,e){return n>>>e|n<<32-e}function N(n){let e=n.length*8,t=Math.ceil((n.length+9)/64)*64,s=new Uint8Array(t);s.set(n),s[n.length]=128;let i=new DataView(s.buffer),o=Math.floor(e/4294967296),a=e>>>0;i.setUint32(t-8,o,false),i.setUint32(t-4,a,false);let r=new Uint32Array(de),l=new Uint32Array(64);for(let c=0;c<t;c+=64){for(let p=0;p<16;p++)l[p]=i.getUint32(c+p*4,false);for(let p=16;p<64;p++){let R=l[p-15],E=l[p-2],M=w(R,7)^w(R,18)^R>>>3,z=w(E,17)^w(E,19)^E>>>10;l[p]=l[p-16]+M+l[p-7]+z>>>0;}let u=r[0],f=r[1],d=r[2],y=r[3],b=r[4],m=r[5],S=r[6],v=r[7];for(let p=0;p<64;p++){let R=w(b,6)^w(b,11)^w(b,25),E=b&m^~b&S,M=v+R+E+ue[p]+l[p]>>>0,z=w(u,2)^w(u,13)^w(u,22),ce=u&f^u&d^f&d,le=z+ce>>>0;v=S,S=m,m=b,b=y+M>>>0,y=d,d=f,f=u,u=M+le>>>0;}r[0]=r[0]+u>>>0,r[1]=r[1]+f>>>0,r[2]=r[2]+d>>>0,r[3]=r[3]+y>>>0,r[4]=r[4]+b>>>0,r[5]=r[5]+m>>>0,r[6]=r[6]+S>>>0,r[7]=r[7]+v>>>0;}let h=new Uint8Array(32),g=new DataView(h.buffer);for(let c=0;c<8;c++)g.setUint32(c*4,r[c],false);return h}function O(n,e,t=64){let s=F.encode(n),i=s.length>64?N(s):s,o=new Uint8Array(64);o.set(i);let a=new Uint8Array(64),r=new Uint8Array(64);for(let f=0;f<64;f++){let d=o[f];a[f]=d^92,r[f]=d^54;}let l=F.encode(e),h=new Uint8Array(64+l.length);h.set(r,0),h.set(l,64);let g=N(h),c=new Uint8Array(96);c.set(a,0),c.set(g,64);let u=N(c);return V(u).slice(0,t)}function I(n,e=64){return V(N(F.encode(n))).slice(0,e)}function V(n){let e="";for(let t=0;t<n.length;t++)e+=n[t].toString(16).padStart(2,"0");return e}function U(n=8){let e=new Uint8Array(n);if(typeof globalThis.crypto?.getRandomValues=="function")globalThis.crypto.getRandomValues(e);else for(let t=0;t<n;t++)e[t]=Math.floor(Math.random()*256);return V(e)}function T(n){return n.replace(/\D/g,"")}function H(n){let e=T(n);if(e.length<13||e.length>19||/^(\d)\1+$/.test(e))return false;let t=0,s=false;for(let i=e.length-1;i>=0;i--){let o=e.charCodeAt(i)-48;s&&(o*=2,o>9&&(o-=9)),t+=o,s=!s;}return t%10===0}function L(n){let e=T(n);if(!/^[12]\d{9}$/.test(e))return false;let t="80840"+e,s=0,i=false;for(let o=t.length-1;o>=0;o--){let a=t.charCodeAt(o)-48;i&&(a*=2,a>9&&(a-=9)),s+=a,i=!i;}return s%10===0}function j(n){let e=n.trim().toUpperCase();if(!/^[ABFGMPRX][A-Z9]\d{7}$/.test(e))return false;let t=a=>e.charCodeAt(2+a)-48,s=t(0)+t(2)+t(4),i=t(1)+t(3)+t(5);return (s+2*i)%10===t(6)}var D="ACDEFGHJKMNPQRTUVWXY",Z="0123456789"+D;function B(n){let e=n.replace(/-/g,"").toUpperCase();if(e.length!==11)return false;let t=e.charCodeAt(0);return !(t<49||t>57||!D.includes(e[1])||!Z.includes(e[2])||!/\d/.test(e[3])||!D.includes(e[4])||!Z.includes(e[5])||!/\d/.test(e[6])||!D.includes(e[7])||!D.includes(e[8])||!/\d\d/.test(e.slice(9,11)))}var fe={AD:24,AE:23,AL:28,AT:20,AZ:28,BA:20,BE:16,BG:22,BH:22,BR:29,BY:28,CH:21,CR:22,CY:28,CZ:24,DE:22,DK:18,DO:28,EE:20,EG:29,ES:24,FI:18,FO:18,FR:27,GB:22,GE:22,GI:23,GL:18,GR:27,GT:28,HR:21,HU:28,IE:22,IL:23,IQ:23,IS:26,IT:27,JO:30,KW:30,KZ:20,LB:28,LC:32,LI:21,LT:20,LU:20,LV:21,MC:27,MD:24,ME:22,MK:19,MR:27,MT:31,MU:30,NL:18,NO:15,PK:24,PL:28,PS:29,PT:25,QA:29,RO:24,RS:22,SA:24,SE:24,SI:19,SK:24,SM:27,ST:25,SV:28,TL:23,TN:24,TR:26,UA:29,VA:22,VG:24,XK:20};function Y(n){let e=n.replace(/[\s-]+/g,"").toUpperCase();if(!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(e))return false;let t=fe[e.slice(0,2)];if(t!==void 0&&e.length!==t)return false;let s=e.slice(4)+e.slice(0,4),i=0;for(let o=0;o<s.length;o++){let a=s.charCodeAt(o);if(a>=48&&a<=57)i=(i*10+(a-48))%97;else if(a>=65&&a<=90){let r=a-55;i=(i*100+r)%97;}else return false}return i===1}function G(n){let e=T(n);if(e.length!==10||/^(\d)\1+$/.test(e))return false;let t=0;for(let o=0;o<9;o++)t+=(e.charCodeAt(o)-48)*(10-o);let i=11-t%11;return i===11&&(i=0),i===10?false:i===e.charCodeAt(9)-48}function W(n,e){let t=n.trim(),s=/[-\s]/.test(t),i=T(t);if(i.length!==9)return false;let o=Number(i.slice(0,3)),a=Number(i.slice(3,5)),r=Number(i.slice(5,9));if(o===0||o===666||o>=900||a===0||r===0||/^(\d)\1+$/.test(i))return false;if(!s&&e){let l=e.fullText.slice(Math.max(0,e.start-36),e.start);return /\b(ssn|social[\s_-]?security|tin)\b/i.test(l)}return true}var pe=[[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],[9,8,7,6,5,4,3,2,1,0]],ge=[[0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]];function J(n){let e=T(n);if(!/^[2-9]\d{11}$/.test(e))return false;let t=0;for(let s=0;s<e.length;s++){let i=e.charCodeAt(e.length-1-s)-48;t=pe[t][ge[s%8][i]];}return t===0}function q(n){let e=T(n);if(!/^[1-9]\d{10}$/.test(e))return false;let t=new Array(10).fill(0);for(let r=0;r<10;r++)t[e.charCodeAt(r)-48]+=1;let s=t.filter(r=>r===2||r===3).length,i=Math.max(...t);if(s!==1||i>3)return false;let o=10;for(let r=0;r<10;r++){let l=(e.charCodeAt(r)-48+o)%10;l===0&&(l=10),o=l*2%11;}let a=11-o;return a===10&&(a=0),a===e.charCodeAt(10)-48}function X(n){let e=n.split(".");if(e.length!==3)return false;let t=e[0];if(!t.startsWith("eyJ"))return false;try{let s=t.replace(/-/g,"+").replace(/_/g,"/"),i=(4-s.length%4)%4,o=atob(s+"=".repeat(i));return o.startsWith("{")&&o.includes('"')}catch{return false}}function Q(n){let e=n.split(".").map(Number);if(e.length!==4)return false;let[t,s]=e;return t===void 0||s===void 0?false:t===10||t===127||t===0||t===192&&s===168||t===172&&s>=16&&s<=31||t===169&&s===254}function ee(n){let e=n.split(".");if(e.length!==4)return false;for(let t of e){if(t.length===0||t.length>1&&t.startsWith("0"))return false;let s=Number(t);if(!Number.isInteger(s)||s<0||s>255)return false}return true}function te(n){if(n.length===0)return 0;let e=new Map;for(let i=0;i<n.length;i++){let o=n.charCodeAt(i);e.set(o,(e.get(o)??0)+1);}let t=0,s=n.length;for(let i of e.values()){let o=i/s;t-=o*Math.log2(o);}return t}var x=["default","secrets","hipaa","gdpr","strict"],_=["default","hipaa","gdpr","strict"],C=["hipaa","strict"],he=["gdpr","strict"],re=[{id:"pem-private-key",category:"PRIVATE_KEY",priority:100,presets:x,pattern:/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----[\s\S]{16,8192}?-----END (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY-----/g},{id:"connection-uri-password",category:"CONNECTION_URI",priority:96,presets:x,captureGroup:1,pattern:/\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis(?:s)?|amqp(?:s)?|mssql|clickhouse|cockroachdb):\/\/[^:\s/@]+:([^@\s/]{3,256})@[^\s"'<>]+/gi},{id:"anthropic-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-ant-(?:api\d{2}|admin\d{2}|oat\d{2}|[a-z0-9]+)-[A-Za-z0-9_-]{24,}\b/g},{id:"openai-key",category:"API_KEY",priority:95,presets:x,pattern:/\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{24,}\b|\bsk-[A-Za-z0-9]{16,}T3BlbkFJ[A-Za-z0-9]{16,}\b/g},{id:"github-token",category:"API_KEY",priority:95,presets:x,pattern:/\b(?:gh[pousr]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9]{22}_[A-Za-z0-9]{40,})\b/g},{id:"aws-access-key",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:AKIA|ASIA|AROA|AIDA)[0-9A-Z]{16}\b/g},{id:"stripe-secret",category:"API_KEY",priority:94,presets:x,pattern:/\b(?:sk_live|rk_live|whsec)_[A-Za-z0-9]{20,}\b/g},{id:"google-api-key",category:"API_KEY",priority:93,presets:x,pattern:/\bAIza[0-9A-Za-z_-]{35}\b/g},{id:"slack-token",category:"TOKEN",priority:93,presets:x,pattern:/\bxox[baprs]-[0-9A-Za-z-]{14,}\b|https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g},{id:"discord-webhook",category:"SECRET",priority:92,presets:x,pattern:/https:\/\/discord(?:app)?\.com\/api\/webhooks\/\d{16,22}\/[A-Za-z0-9_-]{40,}/g},{id:"provider-prefixed-keys",category:"API_KEY",priority:92,presets:x,pattern:/\b(?:hf_[A-Za-z0-9]{30,}|gsk_[A-Za-z0-9]{36,}|xai-[A-Za-z0-9]{36,}|pplx-[A-Za-z0-9]{36,}|sbp_[A-Za-z0-9]{36,}|sb_secret_[A-Za-z0-9_-]{24,}|re_[A-Za-z0-9_]{24,}|npm_[A-Za-z0-9]{36}|pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}|SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b/g},{id:"jwt-token",category:"JWT",priority:90,presets:x,pattern:/\beyJ[A-Za-z0-9_-]{6,}\.eyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{8,}\b/g,validate:n=>X(n)},{id:"bearer-auth-header",category:"TOKEN",priority:88,presets:x,captureGroup:1,pattern:/\b(?:Authorization|Proxy-Authorization)\s*[:=]\s*["']?(?:Bearer|Basic|Token)\s+([A-Za-z0-9._~+/=-]{12,})["']?/gi},{id:"contextual-secret-assignment",category:"SECRET",priority:72,presets:x,captureGroup:1,pattern:/\b(?:api[_-]?key|secret[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|client[_-]?secret|private[_-]?key|aws_secret_access_key|password|passwd|pwd|signing[_-]?secret)\b\s*[:=]\s*["']?([^\s"',;}{]{10,128})["']?/gi,validate:n=>!n.startsWith("[")&&!n.startsWith("<")&&te(n)>=2.8},{id:"medicare-mbi",category:"MBI",priority:84,presets:C,pattern:/\b[1-9][AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y][0-9AC-HJKMNP-RT-Y]-?\d[AC-HJKMNP-RT-Y]{2}\d{2}\b/gi,validate:n=>B(n)},{id:"us-dea",category:"DEA",priority:83,presets:C,pattern:/\b[ABFGMPRX][A-Z9]\d{7}\b/g,validate:n=>j(n)},{id:"us-npi",category:"NPI",priority:80,presets:C,contextWindow:40,contextRegex:/\b(?:npi|provider|prescriber|practitioner|physician)\b/i,pattern:/\b[12]\d{9}\b/g,validate:n=>L(n)},{id:"uk-nhs-number",category:"NHS",priority:80,presets:["hipaa","gdpr","strict"],contextWindow:40,contextRegex:/\b(?:nhs|patient|health|care|medical)\b/i,pattern:/\b\d{3}[-\s]?\d{3}[-\s]?\d{4}\b/g,validate:n=>G(n)},{id:"medical-record-number",category:"MRN",priority:78,presets:C,captureGroup:1,pattern:/\b(?:mrn|medical[\s_-]?record(?:[\s_-]?number)?|patient[\s_-]?id)\s*[:=#]?\s*([A-Z0-9-]{5,20})\b/gi},{id:"iban",category:"IBAN",priority:84,presets:_,pattern:/\b[A-Z]{2}\d{2}(?:[\s-]?[A-Z0-9]){11,30}\b/g,validate:n=>Y(n)},{id:"credit-card",category:"CREDIT_CARD",priority:82,presets:_,pattern:/\b(?:\d[ -]?){13,18}\d\b/g,validate:n=>{let e=n.replace(/\D/g,"");return /^(?:4\d{12}(?:\d{3})?(?:\d{3})?|5[1-5]\d{14}|2(?:2[2-9]|[3-6]\d|7[01]|720)\d{12}|3[47]\d{13}|6(?:011|5\d\d)\d{12}|3(?:0[0-5]|[68]\d)\d{11}|(?:2131|1800|35\d{3})\d{11})$/.test(e)&&H(e)}},{id:"us-ssn",category:"SSN",priority:81,presets:_,pattern:/\b\d{3}[-\s]\d{2}[-\s]\d{4}\b|\b\d{9}\b/g,validate:(n,e)=>W(n,e)},{id:"aadhaar-in",category:"AADHAAR",priority:76,presets:["gdpr","strict"],contextWindow:40,contextRegex:/\b(?:aadhaar|aadhar|uidai)\b/i,pattern:/\b[2-9]\d{3}[-\s]?\d{4}[-\s]?\d{4}\b/g,validate:n=>J(n)},{id:"de-tax-id",category:"TAX_ID",priority:76,presets:he,contextWindow:45,contextRegex:/\b(?:steuer|tax|tin|idnr|identifikationsnummer)\b/i,pattern:/\b[1-9]\d{10}\b/g,validate:n=>q(n)},{id:"email",category:"EMAIL",priority:75,presets:_,pattern:/\b[A-Za-z0-9._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\.)+[A-Za-z]{2,24}\b/g},{id:"phone",category:"PHONE",priority:65,presets:_,pattern:/(?:\+\d{1,3}[-.\s]?)?(?:\(\d{2,4}\)[-.\s]?|\b\d{3}[-.\s])\d{3,4}[-.\s]\d{4}\b|\+\d{1,3}[-.\s]?\d{2,4}[-.\s]?\d{3,4}[-.\s]?\d{3,4}\b/g,validate:n=>{let e=n.replace(/\D/g,"");return e.length>=10&&e.length<=15&&!/^(\d)\1+$/.test(e)}},{id:"ipv4",category:"IP_ADDRESS",priority:60,presets:_,pattern:/\b(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}\b/g,validate:n=>ee(n)},{id:"ipv6",category:"IP_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b/g},{id:"mac-address",category:"MAC_ADDRESS",priority:58,presets:["hipaa","gdpr","strict"],pattern:/\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g},{id:"labeled-person-name",category:"PERSON",priority:55,presets:["hipaa","strict"],captureGroup:1,pattern:/\b(?:Patient(?:\s+Name)?|Dr\.|Doctor|Clinician|Provider|Mr\.|Mrs\.|Ms\.|Full\s+Name|Beneficiary)\s*[:.]?\s*([A-Z][a-z]{1,24}(?:\s+[A-Z]\.?)?(?:\s+[A-Z][a-z]{1,24}){1,2})/g},{id:"dob-or-clinical-date",category:"DATE",priority:52,presets:C,contextWindow:40,contextRegex:/\b(?:dob|birth|born|admit(?:ted)?|discharg(?:e|ed)|visit|encounter|date)\b/i,pattern:/\b(?:\d{4}-\d{2}-\d{2}|(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g}];var ye=/^(?:password|passwd|pwd|passphrase|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|authorization|cookie|set-cookie|x-api-key|client[_-]?secret|private[_-]?key|ssn|social[_-]?security(?:[_-]?number)?|cvv|cvc|pin|iban|dob|birth[_-]?date|mrn)$/i,me=/\[[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?\]|<[A-Z_]+_\d+(?:#[a-f0-9]{4,8})?>/g;function ne(n){let e=n.toLowerCase();return e.includes("ssn")||e.includes("social")?"SSN":e.includes("iban")?"IBAN":e.includes("mrn")?"MRN":e.includes("dob")||e.includes("birth")?"DATE":e.includes("password")||e.includes("passwd")||e.includes("secret")||e==="cvv"||e==="cvc"||e==="pin"?"SECRET":e.includes("token")||e==="authorization"||e==="cookie"||e==="set-cookie"?"TOKEN":e.includes("key")?"API_KEY":"CUSTOM"}function be(n){let e=n.preset??"default",t=n.rules?[...n.rules]:re.filter(o=>o.presets.includes(e)),i=[...(n.customRules??[]).map(o=>({id:o.id,category:o.category??"CUSTOM",pattern:o.pattern,captureGroup:o.captureGroup,priority:o.priority??85,presets:["default","secrets","hipaa","gdpr","strict"],validate:o.validate})),...t];if(n.categories?.length){let o=new Set(n.categories);i=i.filter(a=>o.has(a.category));}if(n.excludeCategories?.length){let o=new Set(n.excludeCategories);i=i.filter(a=>!o.has(a.category));}return i}function xe(n,e){let t=[];for(let s of e){if(!s||s.length<4)continue;let i=0;for(;;){let o=n.indexOf(s,i);if(o===-1)break;t.push({id:"literal-secret",category:"SECRET",priority:99,start:o,end:o+s.length,value:s}),i=o+s.length;}}return t}function se(n,e,t){let s=[],i=t.allowlist?new Set(t.allowlist):void 0,o=t.redactPrivateIps??(t.preset==="strict"||t.preset==="hipaa");t.literals?.length&&s.push(...xe(n,t.literals));for(let r of e){let l=r.pattern.flags.includes("g")?r.pattern.flags:r.pattern.flags+"g",h=new RegExp(r.pattern.source,l),g;for(;(g=h.exec(n))!==null;){if(g[0].length===0){h.lastIndex+=1;continue}let c=g.index,u=g[0];if(r.captureGroup!==void 0&&g[r.captureGroup]!==void 0){let d=g[r.captureGroup],y=g[0].indexOf(d);y!==-1&&(c=g.index+y,u=d);}let f=c+u.length;if(!i?.has(u)&&!(r.id==="ipv4"&&!o&&Q(u))){if(r.contextRegex){let d=r.contextWindow??40,y=n.slice(Math.max(0,c-d),c),b=n.slice(f,Math.min(n.length,f+d));if(!r.contextRegex.test(y)&&!r.contextRegex.test(b))continue}if(r.validate){let d={fullText:n,match:g,start:c,end:f,value:u};if(!r.validate(u,d))continue}s.push({id:r.id,category:r.category,priority:r.priority,start:c,end:f,value:u});}}}s.sort((r,l)=>{if(l.priority!==r.priority)return l.priority-r.priority;let h=l.end-l.start-(r.end-r.start);return h!==0?h:r.start-l.start});let a=[];for(let r of s){let l=false;for(let h of a)if(r.start<h.end&&r.end>h.start){l=true;break}l||a.push(r);}return a.sort((r,l)=>r.start-l.start),a}var k=class n{options;rules;tokenFormat;vaultKey;sensitiveKeyRe;forward=new Map;reverse=new Map;counters=new Map;reservedTokens=new Set;_version=0;constructor(e={}){this.options=e,this.rules=be(e),this.tokenFormat=e.tokenFormat??"bracket",this.vaultKey=e.secret??U(16),this.sensitiveKeyRe=e.sensitiveKeys?.length?new RegExp(`^(?:${e.sensitiveKeys.map(t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})$`,"i"):ye;}get version(){return this._version}fingerprint(e){return O(this.vaultKey,e,12)}reserveExistingTokens(e){let t=new RegExp(me.source,"g"),s;for(;(s=t.exec(e))!==null;)this.reverse.has(s[0])||this.reservedTokens.add(s[0]);}tokenize(e,t){let s=`${e}:${t}`,i=this.forward.get(s);if(i!==void 0)return i;if(this.tokenFormat==="mask")return (this.options.maskChar??"*").repeat(Math.min(Math.max(t.length,4),16));if(this.tokenFormat==="hash"){let r=O(this.vaultKey,s,8),l=`[${e}:${r}]`;return this.forward.set(s,l),this.reverse.set(l,{category:e,value:t}),this._version+=1,l}let o=this.counters.get(e)??0,a;do if(o+=1,this.tokenFormat==="angle")a=`<${e}_${o}>`;else if(this.tokenFormat==="signed"){let r=O(this.vaultKey,`${e}:${o}:${t}`,4);a=`[${e}_${o}#${r}]`;}else a=`[${e}_${o}]`;while(this.reservedTokens.has(a)||this.reverse.has(a));return this.counters.set(e,o),this.forward.set(s,a),this.reverse.set(a,{category:e,value:t}),this._version+=1,a}scan(e){return typeof e!="string"||e.length===0?[]:se(e,this.rules,this.options).map(s=>({id:s.id,category:s.category,start:s.start,end:s.end,token:`[${s.category}]`,length:s.value.length,fingerprint:I(s.value,12)}))}redactText(e){if(typeof e!="string"||e.length===0)return {value:e,findings:[],count:0};this.reserveExistingTokens(e);let t=se(e,this.rules,this.options);if(t.length===0)return {value:e,findings:[],count:0};let s="",i=0,o=[];for(let a of t){s+=e.slice(i,a.start);let r=this.tokenize(a.category,a.value);s+=r,i=a.end,o.push({id:a.id,category:a.category,start:a.start,end:a.end,token:r,length:a.value.length,fingerprint:this.fingerprint(a.value)});}return s+=e.slice(i),{value:s,findings:o,count:o.length}}redactObject(e){let t=[],s=this.options.maxDepth??32,i=new WeakMap,o=(r,l,h)=>{if(r==null)return r;if(typeof r=="string"){if(h&&this.sensitiveKeyRe.test(h)&&r.length>0&&!this.reverse.has(r)){let u=ne(h),f=this.tokenize(u,r);return t.push({id:"sensitive-key",category:u,start:0,end:r.length,token:f,length:r.length,fingerprint:this.fingerprint(r)}),f}let c=this.redactText(r);return c.count>0&&t.push(...c.findings),c.value}if(typeof r!="object")return r;if(l>=s)return "[MAX_DEPTH_TRUNCATED]";if(i.has(r))return i.get(r);if(r instanceof Date)return new Date(r.getTime());if(r instanceof RegExp)return new RegExp(r.source,r.flags);if(r instanceof URL){let c=new URL(r.toString());c.password&&(c.password=this.tokenize("SECRET",c.password));let u=[];c.searchParams.forEach((f,d)=>{u.push([d,f]);});for(let[f,d]of u)if(this.sensitiveKeyRe.test(f)&&d)c.searchParams.set(f,this.tokenize(ne(f),d));else {let y=this.redactText(d);y.count>0&&(t.push(...y.findings),c.searchParams.set(f,y.value));}return c}if(typeof Headers<"u"&&r instanceof Headers){let c=new Headers;return r.forEach((u,f)=>{c.set(f,o(u,l+1,f));}),c}if(r instanceof Error){let c={name:r.name,message:this.options.redactErrors!==false?o(r.message,l+1):r.message};r.stack!==void 0&&(c.stack=this.options.redactErrors!==false?o(r.stack,l+1):r.stack),"cause"in r&&r.cause!==void 0&&(c.cause=o(r.cause,l+1));for(let u of Object.keys(r))c[u]=o(r[u],l+1,u);return c}if(Array.isArray(r)){let c=[];i.set(r,c);for(let u=0;u<r.length;u++)c.push(o(r[u],l+1,h));return c}if(r instanceof Map){let c=new Map;i.set(r,c);for(let[u,f]of r.entries()){let d=typeof u=="string"?u:void 0;c.set(o(u,l+1),o(f,l+1,d));}return c}if(r instanceof Set){let c=new Set;i.set(r,c);for(let u of r.values())c.add(o(u,l+1));return c}let g={};i.set(r,g);for(let[c,u]of Object.entries(r))g[c]=o(u,l+1,c);return g};return {value:o(e,0),findings:t,count:t.length}}redact(e){return typeof e=="string"?this.redactText(e):this.redactObject(e)}restore(e){if(typeof e!="string"||e.length===0||this.reverse.size===0)return e;let s=Array.from(this.reverse.keys()).sort((o,a)=>a.length-o.length).map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),i=new RegExp(s.join("|"),"g");return e.replace(i,o=>this.reverse.get(o)?.value??o)}restoreObject(e){let t=new WeakMap,s=(i,o)=>{if(i==null)return i;if(typeof i=="string")return this.restore(i);if(typeof i!="object"||o>=32)return i;if(t.has(i))return t.get(i);if(Array.isArray(i)){let r=[];t.set(i,r);for(let l of i)r.push(s(l,o+1));return r}if(i instanceof Date||i instanceof RegExp||i instanceof URL)return i;let a={};t.set(i,a);for(let[r,l]of Object.entries(i))a[r]=s(l,o+1);return a};return s(e,0)}entries(){return Array.from(this.reverse.entries()).map(([e,t])=>({token:e,category:t.category,value:t.value}))}export(){let e={};for(let[t,s]of this.counters.entries())e[t]=s;return {version:1,tokenFormat:this.tokenFormat,counters:e,entries:this.entries()}}static fromJSON(e,t={}){let s=new n({...t,tokenFormat:e.tokenFormat});for(let[i,o]of Object.entries(e.counters))s.counters.set(i,o);for(let i of e.entries)s.forward.set(`${i.category}:${i.value}`,i.token),s.reverse.set(i.token,{category:i.category,value:i.value});return s._version+=1,s}clear(){this.forward.clear(),this.reverse.clear(),this.counters.clear(),this.reservedTokens.clear(),this._version+=1;}};function $(n,e={}){return new k(e).redact(n)}function K(n,e={}){return new k(e).scan(n)}var ie=new Set(["036","059","063","102","203","556","692","790","821","823","830","831","878","879","884","890","893"]),Ae=new Set([...ie,"205","369"]),ve=new Set(["resourceType","coding","code","system","display","unit","valueQuantity","valueCodeableConcept","severity","clinicalStatus","verificationStatus","category","gender","status","intent","priority"]),Re=new Set(["name","family","given","prefix","suffix","maiden"]),we=new Set(["text","line","city","district","use","note","description","title"]),Se=new Set(["photo","data"]),ke=/^(\d{4})-(\d{2})-(\d{2})(.*)$/,Ee=/^\d{4}$/;function Te(n,e){let t=e??String(n.export().entries.length)+"fhir",s=I(t,8),i=parseInt(s,16),o=30+i%151;return i%2===0?o:-o}function _e(n,e){let t=ke.exec(n);if(!t)return n;let s=Number(t[1]),i=Number(t[2]),o=Number(t[3]),a=t[4]??"",r=new Date(Date.UTC(s,i-1,o));if(Number.isNaN(r.getTime()))return n;r.setUTCDate(r.getUTCDate()+e);let l=r.getUTCFullYear().toString().padStart(4,"0"),h=(r.getUTCMonth()+1).toString().padStart(2,"0"),g=r.getUTCDate().toString().padStart(2,"0");return `${l}-${h}-${g}${a}`}function Ie(n){let e=/^(\d{4})/.exec(n);if(!e)return false;let t=Number(e[1]);return new Date().getUTCFullYear()-t>89}function De(n,e){let t=n.replace(/\D/g,"");if(t.length<3)return "000";let s=t.slice(0,3);return (e==="hhs-2000"?ie:Ae).has(s)?"000":s}function oe(n,e={},t){let s=t??new k({...e,preset:e.preset??"hipaa"}),i=e.zipBaseline??"conservative-union",o=e.dateStrategy??"shift",a=e.capAgeOver89??true,r=e.preserveClinicalCodes??true,l=typeof n.id=="string"?n.id:JSON.stringify(n.identifier??"default"),h=e.dateShiftDays??Te(s,l),g=(d,y)=>{if(y&&a&&Ie(d))return "90+";if(Ee.test(d))return d;if(o==="redact")return s.tokenize("DATE",d);if(o==="year-only"){let b=/^(\d{4})/.exec(d);return b?b[1]:s.tokenize("DATE",d)}return _e(d,h)},c=(d,y,b)=>{if(d==null)return d;let m=y[y.length-1]??"";if(typeof d=="string"){if(b&&m!=="display")return d;if(m==="postalCode")return De(d,i);if(m==="birthDate")return g(d,true);if(m==="date"||m==="effectiveDateTime"||m==="authoredOn"||m==="onsetDateTime"||m==="recordedDate"||m==="issued"||m==="start"||m==="end")return g(d,false);if(m==="div")return s.redactText(d).value;if(Re.has(m))return s.tokenize("PERSON",d);if(m==="line"||m==="street"||m==="city")return s.tokenize("ADDRESS",d);if(m==="id"||y.includes("identifier")&&m==="value")return s.tokenize("MRN",d);if(y.includes("telecom")&&m==="value"){let p=s.redactText(d);return p.count>0?p.value:s.tokenize("CUSTOM",d)}return s.redactText(d).value}if(typeof d!="object")return d;if(Array.isArray(d))return d.map(p=>c(p,y,b));let S=d,v={};for(let[p,R]of Object.entries(S)){if(p==="resourceType"){v[p]=R;continue}if(Se.has(p)&&(y.includes("photo")||p==="photo")){v[p]=p==="photo"?[]:"[REDACTED_BIOMETRIC]";continue}if(p==="name"&&(S.resourceType==="Patient"||S.resourceType==="Practitioner"||S.resourceType==="RelatedPerson")){v[p]=c(R,[...y,p],false);continue}let E=r&&(b||ve.has(p));we.has(p)&&!b?v[p]=c(R,[...y,p],false):v[p]=c(R,[...y,p],E);}return v},u=c(n,[],false),f=s.entries().map((d,y)=>({id:"fhir-phi",category:d.category,start:y,end:y,token:d.token,length:d.value.length,fingerprint:I(d.value,12)}));return {value:u,findings:f,count:f.length,vault:s}}function Pe(n){if(!A__default.default.existsSync(n))return [];let e=A__default.default.readFileSync(n,"utf8"),t=[];for(let s of e.split(/\r?\n/)){let i=s.trim();if(!i||i.startsWith("#"))continue;let o=i.indexOf("=");if(o===-1)continue;let a=i.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),a.length>=6&&t.push(a);}return t}function Me(n){let e=[],t=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv"]),s=i=>{if(!A__default.default.existsSync(i))return;let o=A__default.default.statSync(i);if(o.isFile()){o.size<=2*1024*1024&&e.push(i);return}if(o.isDirectory())for(let a of A__default.default.readdirSync(i))t.has(a)||s(P__default.default.join(i,a));};for(let i of n)s(i);return e}function Ne(){console.log(`redact0 \u2014 0-dep reversible PII, secret & FHIR redactor
3
+
4
+ USAGE:
5
+ echo "email: a@b.com" | redact0 [--preset default|secrets|hipaa|gdpr|strict]
6
+ redact0 scan <paths...> [--preset secrets] [--env .env] [--json|--sarif] [--fail-on-match]
7
+ redact0 init [--cursor] [--claude]
8
+ redact0 mcp
9
+ `);}function Oe(n){let e=P__default.default.join(process.cwd(),"package.json"),t={};if(A__default.default.existsSync(e))try{let s=JSON.parse(A__default.default.readFileSync(e,"utf8"));t={...s.dependencies,...s.devDependencies};}catch{}if(console.log(`
10
+ Detected project stack recommendations:
11
+ `),t.ai&&console.log(" \u2022 Vercel AI SDK detected -> import { redactMiddleware } from 'redact0/ai';"),t.openai&&console.log(" \u2022 OpenAI SDK detected -> import { wrapOpenAI } from 'redact0/ai';"),t["@anthropic-ai/sdk"]&&console.log(" \u2022 Anthropic SDK detected -> import { wrapAnthropic } from 'redact0/ai';"),(t["@modelcontextprotocol/sdk"]||t["@modelcontextprotocol/server"])&&console.log(" \u2022 MCP Server detected -> import { guardMcpServer } from 'redact0/mcp';"),t.pino&&console.log(" \u2022 Pino logger detected -> import { pinoRedactor } from 'redact0/logger';"),t.winston&&console.log(" \u2022 Winston detected -> import { winstonFormat } from 'redact0/logger';"),Object.keys(t).length===0&&console.log(" \u2022 Core usage: import { redact, createVault } from 'redact0';"),n.includes("--cursor")){let s=P__default.default.join(process.cwd(),".cursor","rules");A__default.default.mkdirSync(s,{recursive:true}),A__default.default.writeFileSync(P__default.default.join(s,"redact0.mdc"),"---\ndescription: Automatically protect PII, PHI, and API secrets with redact0 before logging or calling LLMs/MCP tools.\nalwaysApply: true\n---\n- Use `redact0` (zero dependencies) for any PII/secret scrubbing.\n- Wrap Vercel AI SDK models with `redactMiddleware()` from `redact0/ai`.\n- Wrap MCP servers with `guardMcpServer(server)` from `redact0/mcp`.\n- Pass `pinoRedactor()` from `redact0/logger` to Pino loggers.\n"),console.log(`
12
+ Wrote .cursor/rules/redact0.mdc`);}n.includes("--claude")&&(A__default.default.appendFileSync(P__default.default.join(process.cwd(),"CLAUDE.md"),"\n## Security & Redaction\nAlways scrub PII, PHI, and API credentials at LLM, MCP, and logging boundaries using `redact0` (`redact0/ai`, `redact0/mcp`, `redact0/logger`, `redact0/fhir`).\n"),console.log("Appended redact0 guidance to CLAUDE.md"));}function ze(){let n=new k,e=Ce__default.default.createInterface({input:process.stdin,terminal:false}),t=s=>{process.stdout.write(JSON.stringify(s)+`
13
+ `);};e.on("line",s=>{let i=s.trim();if(!i)return;let o;try{o=JSON.parse(i);}catch{return}let{id:a,method:r,params:l}=o;if(r==="initialize"){t({jsonrpc:"2.0",id:a,result:{protocolVersion:"2025-03-26",capabilities:{tools:{}},serverInfo:{name:"redact0",version:"1.0.0"}}});return}if(r!=="notifications/initialized"){if(r==="tools/list"){t({jsonrpc:"2.0",id:a,result:{tools:[{name:"redact_text",description:"Scrub PII, PHI, and API secrets with reversible vault placeholders.",inputSchema:{type:"object",properties:{text:{type:"string"},preset:{type:"string",enum:["default","secrets","hipaa","gdpr","strict"]}},required:["text"]}},{name:"restore_text",description:"Restore vault placeholders back to original values from this MCP session.",inputSchema:{type:"object",properties:{text:{type:"string"}},required:["text"]}},{name:"scan_secrets",description:"Audit text for exposed credentials and PII without exposing raw values.",inputSchema:{type:"object",properties:{text:{type:"string"}},required:["text"]}},{name:"redact_fhir",description:"De-identify a FHIR R4/R5 JSON resource under HIPAA Safe Harbor.",inputSchema:{type:"object",properties:{resource:{type:"object"}},required:["resource"]}}]}});return}if(r==="tools/call"){let h=l?.name,g=l?.arguments??{},c="";if(h==="redact_text")c=(g.preset?$(String(g.text??""),{preset:g.preset}):n.redactText(String(g.text??""))).value;else if(h==="restore_text")c=n.restore(String(g.text??""));else if(h==="scan_secrets")c=JSON.stringify(K(String(g.text??""),{preset:"strict"}),null,2);else if(h==="redact_fhir")c=JSON.stringify(oe(g.resource??{},{},n).value,null,2);else {t({jsonrpc:"2.0",id:a,error:{code:-32601,message:`Unknown tool: ${h}`}});return}t({jsonrpc:"2.0",id:a,result:{content:[{type:"text",text:c}]}});return}a!==void 0&&t({jsonrpc:"2.0",id:a,error:{code:-32601,message:`Method not found: ${r}`}});}});}function ae(n,e){let t=n.indexOf(e);return t!==-1?n[t+1]:void 0}async function Fe(){let n=process.argv.slice(2);if(n.includes("--help")||n.includes("-h")){Ne();return}let e=n[0];if(e==="init"){Oe(n.slice(1));return}if(e==="mcp"){ze();return}let t=ae(n,"--preset")??"default",s=ae(n,"--env"),i=s?Pe(s):[];if(e==="scan"){let l=n.slice(1).filter((c,u,f)=>!c.startsWith("--")&&!f[u-1]?.startsWith("--preset")&&!f[u-1]?.startsWith("--env")),h=Me(l.length>0?l:["."]),g=[];for(let c of h)try{let u=A__default.default.readFileSync(c,"utf8"),f=K(u,{preset:t,literals:i});f.length>0&&g.push({file:c,findings:f});}catch{}if(n.includes("--sarif")){let c={version:"2.1.0",$schema:"https://json.schemastore.org/sarif-2.1.0.json",runs:[{tool:{driver:{name:"redact0",version:"1.0.0"}},results:g.flatMap(u=>u.findings.map(f=>({ruleId:`${f.category}/${f.id}`,level:"warning",message:{text:`Detected ${f.category} (${f.id}), fingerprint=${f.fingerprint}`},locations:[{physicalLocation:{artifactLocation:{uri:u.file}}}]})))}]};console.log(JSON.stringify(c,null,2));}else if(n.includes("--json"))console.log(JSON.stringify(g,null,2));else {for(let c of g)for(let u of c.findings)console.log(`${c.file} [${u.category}:${u.id}] offset=${u.start}..${u.end} fp=${u.fingerprint}`);console.log(`
14
+ Scanned ${h.length} files, found ${g.reduce((c,u)=>c+u.findings.length,0)} potential exposures.`);}n.includes("--fail-on-match")&&g.length>0&&(process.exitCode=1);return}let o=[];for await(let l of process.stdin)o.push(Buffer.isBuffer(l)?l:Buffer.from(l));let a=Buffer.concat(o).toString("utf8"),r=$(a,{preset:t,literals:i});process.stdout.write(r.value);}Fe().catch(n=>{console.error(n),process.exitCode=1;});
@@ -0,0 +1,39 @@
1
+ import { R as RedactOptions, E as EntityCategory, c as Finding, a as RedactResult, V as VaultSnapshot } from './types-DZbmtyhn.cjs';
2
+
3
+ declare class Vault {
4
+ private readonly options;
5
+ private readonly rules;
6
+ private readonly tokenFormat;
7
+ private readonly vaultKey;
8
+ private readonly sensitiveKeyRe;
9
+ private readonly forward;
10
+ private readonly reverse;
11
+ private readonly counters;
12
+ private readonly reservedTokens;
13
+ private _version;
14
+ constructor(options?: RedactOptions);
15
+ get version(): number;
16
+ private fingerprint;
17
+ private reserveExistingTokens;
18
+ tokenize(category: EntityCategory, value: string): string;
19
+ scan(text: string): Finding[];
20
+ redactText(text: string): RedactResult<string>;
21
+ redactObject<T>(input: T): RedactResult<T>;
22
+ redact<T>(input: T): RedactResult<T>;
23
+ restore(text: string): string;
24
+ restoreObject<T>(input: T): T;
25
+ entries(): Array<{
26
+ token: string;
27
+ category: EntityCategory;
28
+ value: string;
29
+ }>;
30
+ export(): VaultSnapshot;
31
+ static fromJSON(snapshot: VaultSnapshot, options?: RedactOptions): Vault;
32
+ clear(): void;
33
+ }
34
+ declare function createVault(options?: RedactOptions): Vault;
35
+ declare function redact<T>(input: T, options?: RedactOptions): T;
36
+ declare function redactDetailed<T>(input: T, options?: RedactOptions): RedactResult<T>;
37
+ declare function scan(text: string, options?: RedactOptions): Finding[];
38
+
39
+ export { Vault as V, redactDetailed as a, createVault as c, redact as r, scan as s };
@@ -0,0 +1,39 @@
1
+ import { R as RedactOptions, E as EntityCategory, c as Finding, a as RedactResult, V as VaultSnapshot } from './types-DZbmtyhn.js';
2
+
3
+ declare class Vault {
4
+ private readonly options;
5
+ private readonly rules;
6
+ private readonly tokenFormat;
7
+ private readonly vaultKey;
8
+ private readonly sensitiveKeyRe;
9
+ private readonly forward;
10
+ private readonly reverse;
11
+ private readonly counters;
12
+ private readonly reservedTokens;
13
+ private _version;
14
+ constructor(options?: RedactOptions);
15
+ get version(): number;
16
+ private fingerprint;
17
+ private reserveExistingTokens;
18
+ tokenize(category: EntityCategory, value: string): string;
19
+ scan(text: string): Finding[];
20
+ redactText(text: string): RedactResult<string>;
21
+ redactObject<T>(input: T): RedactResult<T>;
22
+ redact<T>(input: T): RedactResult<T>;
23
+ restore(text: string): string;
24
+ restoreObject<T>(input: T): T;
25
+ entries(): Array<{
26
+ token: string;
27
+ category: EntityCategory;
28
+ value: string;
29
+ }>;
30
+ export(): VaultSnapshot;
31
+ static fromJSON(snapshot: VaultSnapshot, options?: RedactOptions): Vault;
32
+ clear(): void;
33
+ }
34
+ declare function createVault(options?: RedactOptions): Vault;
35
+ declare function redact<T>(input: T, options?: RedactOptions): T;
36
+ declare function redactDetailed<T>(input: T, options?: RedactOptions): RedactResult<T>;
37
+ declare function scan(text: string, options?: RedactOptions): Finding[];
38
+
39
+ export { Vault as V, redactDetailed as a, createVault as c, redact as r, scan as s };