@privacyscrubber/mcp-server 2.1.0 → 2.2.1
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/README.md +125 -22
- package/index.js +486 -21
- package/manifest.json +4 -2
- package/package.json +7 -2
- package/pii-masking-run.js +213 -54
- package/ps-license-manager.cjs +257 -0
- package/ps-pii-engine.cjs +79 -36
- package/ps-pii-engine.js +79 -36
- package/scrubber-core.cjs +6 -6
- package/server.json +3 -3
package/ps-pii-engine.cjs
CHANGED
|
@@ -47,9 +47,9 @@ let REGEX_RULES = [
|
|
|
47
47
|
|
|
48
48
|
// Professional IDs & Organizations
|
|
49
49
|
{ type: 'NAME', isContextName: true, isCorporateName: true, regex: /\b(?:[A-Z][A-Za-z0-9&.,'-]*[ \t\xA0]+){1,5}(?:Inc\.?|LLC|Corp\.?|Corporation|Ltd\.?|Limited|Co\.?|Company|Group|Holdings|Solutions|Services|Technologies|Logistics|Industries|Capital|Bank|Partners|LLP|PLLC)(?:\s+(?:LLC|Inc\.?|Corp\.?|Ltd\.?|USA|Group))?\b/g },
|
|
50
|
-
{ type: 'ID', regex: /\b(?:Employee|Emp|EE|Worker|Staff|File|Badge|Member|Advisor|Producer|Agent|Borrower)\s*(?:#|ID|No\.?|Number)[:\s#]*[A-Z0-9-]{3,15}\b/gi },
|
|
50
|
+
{ type: 'ID', regex: /\b(?:Employee|Emp|EE|Worker|Staff|File|Badge|Member|Advisor|Producer|Agent|Borrower)\s*(?:#|ID|No\.?|Number)[:\s#]*([A-Z0-9-]{3,15})\b/gi },
|
|
51
51
|
{ type: 'ID', regex: /\b(?:Pay\s+Group[:#\s]+[A-Za-z0-9_-]{2,30}|(?:Cost\s+Center|Dept|Department)[:#\s]+[A-Za-z0-9_-]*\d[A-Za-z0-9_-]*)\b/gi },
|
|
52
|
-
{ type: 'ID', regex: /(?:\b(?:Box\s+d\b|d\.\s*(?:Control
|
|
52
|
+
{ type: 'ID', regex: /(?:\b(?:Box\s+d\b|d\.\s*(?:Control|#|number|no\.?|num)|d\s+Control)\s*(?:Control\s+)?(?:number|no\.?|#|num)?[:\s#]+|\bControl\s*(?:number|no\.?|#|num)?[:\s#]+|\bControl[:#]\s*)([A-Za-z0-9-]{3,30})/gi },
|
|
53
53
|
{ type: 'ID', regex: /\bEEID[ -]?\d{4,}\b/gi },
|
|
54
54
|
{ type: 'ID', regex: /\bEMP[-_]\d{3,}\b/gi },
|
|
55
55
|
|
|
@@ -92,7 +92,7 @@ let REGEX_RULES = [
|
|
|
92
92
|
{ type: 'ID', regex: /\b\d{2}\/\d{2}\/\d{4}\b/g },
|
|
93
93
|
|
|
94
94
|
// Phone Numbers
|
|
95
|
-
{ type: 'PHONE', regex: /(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/
|
|
95
|
+
{ type: 'PHONE', regex: /(?<!\w)(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}(?:\s*(?:ext\.?|x)\s*\d{1,5})?\b/gi },
|
|
96
96
|
{ type: 'PHONE', regex: /\+\d{1,3}[ \t.-]+(?:\(?\d{1,4}\)?[ \t.-]+)?\d{2,8}(?:[ \t.-]+\d{2,8}){0,4}\b/g },
|
|
97
97
|
{ type: 'PHONE', regex: /\+?[1-9]\d{1,3}[\s.-]\(?\d{1,4}\)?[\s.-]\d{2,4}[\s.-]\d{4}/g },
|
|
98
98
|
{ type: 'PHONE', regex: /(?:\+44\s?7\d{3}|\(?07\d{3}\)?)\s?\d{3}\s?\d{3}\b/g },
|
|
@@ -109,16 +109,18 @@ let REGEX_RULES = [
|
|
|
109
109
|
// Generalized Name Detection (First [Middle] Last) — max 1 middle word to avoid grabbing job titles
|
|
110
110
|
// Middle word must be: a particle (van/de/etc.), a single initial (A. or A), or a capitalized word of ≥2 lowercase letters
|
|
111
111
|
{ type: 'NAME', isAggressiveName: true, regex: /(?<=^|[^\p{L}\p{N}_])(?:\p{Lu}[\p{Ll}'-]*\p{Ll}|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*)(?:[ \t\xA0]+(?:\p{Lu}[\p{Ll}'-]*\p{Ll}|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*|\p{Lu}\.?|van|von|de|di|da|la|le|del|du|der|van[ \t\xA0]+de|van[ \t\xA0]+der)){0,1}[ \t\xA0]+(?:\p{Lu}[\p{Ll}'-]*\p{Ll}|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
112
|
-
// Payroll Format Names (e.g. "BARKER, KELLY", "
|
|
113
|
-
{ type: 'NAME', regex: /\b[A-Z]
|
|
112
|
+
// Payroll & Inverted Format Names (e.g. "BARKER, KELLY", "Vance-Soto, Eleanor", "Kaufman-Alvarez, Liam T.")
|
|
113
|
+
{ type: 'NAME', regex: /\b[A-Z][a-zA-Z'’-]+(?:-[A-Za-z'’-]+)?,\s+[A-Z][a-zA-Z'’-]+(?:\s+[A-Z]\.?(?!\w)|\s+[A-Z][a-zA-Z'’-]+)*\b/g },
|
|
114
114
|
// All-Caps Names (2–3 words, supporting single-letter middle initial e.g. "KELLY M BARKER", "JOHN M BARKER")
|
|
115
115
|
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]+(?:\p{Lu}\.?|[A-Z][a-z]+))?[ \t\xA0]+\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
116
116
|
// ALL-CAPS first + middle initial(s) with optional spaces + ALL-CAPS last name
|
|
117
117
|
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
118
118
|
// ALL-CAPS first name + optional middle initial(s) with optional spaces + Mixed-Case last name
|
|
119
119
|
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])\p{Lu}{2,}(?:[\p{Lu}'-]*\p{Lu})?(?:(?:[ \t\xA0]*\p{Lu}\.)+[ \t\xA0]*|[ \t\xA0]+)(?:\p{Lu}\p{Ll}[\p{Ll}'-]*|\p{Lu}[\p{Ll}'-]*[\p{Lu}'-][\p{Ll}'-]*)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
120
|
-
// Names with Honorifics (with or without period, supporting
|
|
121
|
-
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])(?:Mr|Mrs|Ms|Dr|Prof|Hon|
|
|
120
|
+
// Names with Honorifics (with or without period, supporting middle initials and hyphenated surnames) (Unicode-safe)
|
|
121
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])(?:Mr|Mrs|Ms|Dr|Prof|Hon|Rev|Judge|Atty|Doctor|Professor)(?:\.|\b)[ \t\xA0]+(?:\p{Lu}[\p{L}'-]+)(?:[ \t\xA0]+(?:\p{Lu}\.?|\p{Lu}[\p{L}'-]+)){0,2}(?:[ \t\xA0]+(?:\p{Lu}[\p{L}'-]+))(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
122
|
+
// Names with Quoted or Parenthetical Nicknames (e.g. Judith "Judy" Diaz, Robert (Bob) Smith)
|
|
123
|
+
{ type: 'NAME', regex: /(?<=^|[^\p{L}\p{N}_])(?:\p{Lu}[\p{Ll}'-]+)[ \t\xA0]+(?:"[\p{Lu}\p{Ll}'-]+"|'[\p{Lu}\p{Ll}'-]+'|[“‘][\p{Lu}\p{Ll}'-]+[”’]|\([\p{Lu}\p{Ll}'-]+\))[ \t\xA0]+(?:\p{Lu}[\p{Ll}'-]+)(?:'s)?(?=[^\p{L}\p{N}_]|$)(?![ \t\xA0]*:)/gu },
|
|
122
124
|
|
|
123
125
|
// W-2 Box c Employer Block (Name, Address, and Zip Code)
|
|
124
126
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:\bBox\s+c\b|\bc\.\s*|\bc\s+(?=Employer))\s*(?:Employer(?:'s)?\s*)?(?:name[,\s]+address[,\s]+and\s+ZIP\s+code|name)?|(?:Employer(?:'s)?\s+name[,\s]+address[,\s]+and\s+ZIP\s+code))[\s:#]*([A-Za-z0-9&., \t\xA0'-]{2,45}?)(?=\r?\n|$|\s{3,}|\t|EIN|FEIN|Box|\d+\b|Wages|Federal|Social|Medicare)/gi },
|
|
@@ -129,7 +131,11 @@ let REGEX_RULES = [
|
|
|
129
131
|
// Contextual Last Names (Last name, Surname, Family name)
|
|
130
132
|
{ type: 'NAME', isContextName: true, regex: /(?:(?:Employee(?:'s)?|Borrower(?:'s)?|Co-Borrower(?:'s)?|Applicant(?:'s)?|Candidate(?:'s)?|Worker(?:'s)?|Taxpayer(?:'s)?|Spouse(?:'s)?|Person(?:'s)?)\s+)?(?:Last\s+name|Surname|Family\s+name)[\s:#]+(?:\b|\b\s*)([A-Za-z'-]{2,30})/gi },
|
|
131
133
|
// Contextual General Names (Employee, Principal Investigator, Physician, Doctor, etc.)
|
|
132
|
-
{ type: 'NAME', isContextName: true, regex: /(?:(?:Employee|Employer|Borrower|Co-Borrower|Applicant|Candidate|Worker|Taxpayer|Spouse|Client|Customer|Patient|Claimant|Insured|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Testator|Author)\s+(?:Name|Full\s+Name)|(?:Principal\s+Investigator|Investigator|Physician|Doctor|Supervisor|Reporting\s+To|Prepared\s+By|Attention|Attn|Contact(?:\s+Person)?|Author)(?:\s+Name)?|(?:Employee|Employer|Borrower|Client|Customer|Patient|Claimant|Insured|Doctor|Attn|Signatory|Witness|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Author)\s*[:=#])[:\s
|
|
134
|
+
{ type: 'NAME', isContextName: true, regex: /(?:(?:Employee|Employer|Borrower|Co-Borrower|Applicant|Candidate|Worker|Taxpayer|Spouse|Client|Customer|Patient|Claimant|Insured|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Testator|Author)\s+(?:Name|Full\s+Name)|(?:Principal\s+Investigator|Investigator|Physician|Doctor|Supervisor|Reporting\s+To|Prepared\s+By|Attention|Attn|(?<!Emergency\s+|ICE\s+)Contact(?:\s+Person)?|Author)(?:\s+Name)?|(?:Employee|Employer|Borrower|Client|Customer|Patient|Claimant|Insured|Doctor|Attn|Signatory|Witness|Tenant|Landlord|Buyer|Seller|Plaintiff|Defendant|Author)\s*[:=#])[:\s#|]*(?:\b|\b\s*)([A-Z\p{Lu}][A-Za-z0-9&.,\s'"“”()-]{1,35}?)(?=\r?\n|$|\s{3,}|\t|Employee|Employer|Address|Phone|SSN|EIN|FEIN|Date|Pay|Rate|Tax|W-2|OMB|Copy|Box|Status|\|)/giu },
|
|
135
|
+
// Contextual Nicknames & Preferred Names (e.g. "Nickname: Judy", "Preferred Name: Alex", "AKA: Bob", "Goes by: Sam")
|
|
136
|
+
{ type: 'NAME', isContextName: true, regex: /(?:(?:Patient(?:'s)?|Client(?:'s)?|Child(?:'s)?|Employee(?:'s)?|Person(?:'s)?)\s+)?(?:Nickname|Nick\s+Name|Preferred\s+(?:First\s+)?Name|Also\s+Known\s+As|AKA|Alias|Goes\s+by)[\s:#]+(?:\b|\b\s*)([A-Z\p{Lu}][A-Za-z0-9&.,\s'-]{1,30}?)(?=\r?\n|$|\s{3,}|\t|DOB|Date|Phone|Address|Emergency|Relationship|Notes|MRN|\()/giu },
|
|
137
|
+
// Emergency Contacts (Standard, Inverted Last First, Single Name, Table Cells, Extended Relationships, Brackets & Phone Lookahead)
|
|
138
|
+
{ type: 'NAME', isContextName: true, regex: /(?:(?:^|[^\p{L}\p{N}_]|\|)\s*(?:In\s+Case\s+of\s+Emergency(?:\s*\(ICE\))?|ICE(?:[ \t\xA0]*(?:Contact|Notification|Person|Name))?|Emergency(?:[ \t\xA0]*(?:Contact|Notification|Person|Info|Details))?|Primary\s+Emergency\s+Contact|Secondary\s+Emergency\s+Contact|Alternate\s+Emergency\s+Contact|Person\s+to\s+notify\s+(?:in\s+case\s+of\s+emergency|in\s+emergency))(?:[ \t\xA0]*(?:[12#]|#\s*\d|\(\d\)))?(?:[ \t\xA0]*(?:Person|Name|Full\s+Name))?(?:[ \t\xA0]*(?:[\/&+-]|and)[ \t\xA0]*(?:Relationship|Relation|Proxy|Guarantor|Guardian))?(?:[ \t\xA0]*\((?:Primary|Secondary|Name|Relationship|Relation|Proxy|Guarantor|Legal\s+Guardian|Full\s+Name)\))?)[:=#|\/\t\s-]*[:=#|\/\t-][ \t\xA0]*([A-Z\p{Lu}][A-Za-z0-9&.'’]*(?:[ \t\xA0]+[A-Za-z0-9&.'’]+)*(?:,[ \t\xA0]*(?!(?:Relationship|Relation|Rel|Mother|Father|Spouse|Wife|Husband|Partner|Son|Daughter|Child|Parent|Brother|Sister|Sibling|Friend|Aunt|Uncle|Cousin|Guardian|Caregiver|Carer|Neighbor|Relative|Family|Grandmother|Grandfather|Grandparent|Grandson|Granddaughter|Stepmother|Stepfather|Stepson|Stepdaughter|Step-mother|Step-father|In-law|Mother-in-law|Father-in-law|Sister-in-law|Brother-in-law|Son-in-law|Daughter-in-law|Fiancé|Fiance|Fiancee|Significant\s+Other|Domestic\s+Partner|Life\s+Partner|Roommate|Colleague|Coworker|Co-worker|Legal\s+Guardian|Case\s+Worker|Caseworker|Social\s+Worker|Foster\s+Parent|POA|Power\s+of\s+Attorney|Healthcare\s+Proxy|Medical\s+Proxy|Proxy|Next\s+of\s+Kin|Aide)\b)[A-Z\p{Lu}][A-Za-z0-9&.'’]*(?:[ \t\xA0]+[A-Za-z0-9&.'’]+)*)?)(?=[ \t\xA0]*(?:\([A-Za-z0-9\s\/&':.+–-]+\)|\[[A-Za-z0-9\s\/&':.+–-]+\]|\{[A-Za-z0-9\s\/&':.+–-]+\}|[,\/|\-–—]{1,3}\s*(?:Relationship|Relation|Rel|Mother|Father|Spouse|Wife|Husband|Partner|Son|Daughter|Child|Parent|Brother|Sister|Sibling|Friend|Aunt|Uncle|Cousin|Guardian|Caregiver|Carer|Neighbor|Relative|Family|Grandmother|Grandfather|Grandparent|Grandson|Granddaughter|Stepmother|Stepfather|Stepson|Stepdaughter|Step-mother|Step-father|In-law|Mother-in-law|Father-in-law|Sister-in-law|Brother-in-law|Son-in-law|Daughter-in-law|Fiancé|Fiance|Fiancee|Significant\s+Other|Domestic\s+Partner|Life\s+Partner|Roommate|Colleague|Coworker|Co-worker|Legal\s+Guardian|Case\s+Worker|Caseworker|Social\s+Worker|Foster\s+Parent|POA|Power\s+of\s+Attorney|Healthcare\s+Proxy|Medical\s+Proxy|Proxy|Next\s+of\s+Kin|Aide)\b|[,\/|\-–—]?[ \t\xA0]*(?:Phone|Tel|Cell|Mobile|Work|Home|Office|Direct|Telephone)[:\s#-]*|[,\/|\-–—]?[ \t\xA0]*(?:Relationship|Relation|Rel)[:\s#-]*|[,\/|\-–—]?[ \t\xA0]*(?:\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b|[,\/|\-–—]?[ \t\xA0]*\d{3}[-.\s]?\d{4}\b|[ \t\xA0]*(?:\||\r?\n|$|\s{2,}|\t)))/gui },
|
|
133
139
|
// Box e shorthand
|
|
134
140
|
{ type: 'NAME', isContextName: true, regex: /\b(?:Box\s+e)\s*[:#-]\s*([A-Za-z0-9&.,\s'-]{2,40})/gi }
|
|
135
141
|
];
|
|
@@ -137,17 +143,29 @@ let REGEX_RULES = [
|
|
|
137
143
|
let PROFILE_RULES = {
|
|
138
144
|
general: [],
|
|
139
145
|
legal: [
|
|
146
|
+
// Legal Party & Role-Prefixed Names (Claimant, Respondent, Plaintiff, Defendant, Petitioner, Appellant, Principal, Grantor, Attorney-in-Fact, Counsel)
|
|
147
|
+
{ type: 'NAME', isContextName: true, regex: /\b(?:Registered\s+Representative|Claimant|Respondent|Plaintiff|Defendant|Petitioner|Appellant|Appellee|Principal|Grantor|Grantee|Trustee|Trustor|Fiduciary|Attorney-in-Fact|Designated\s+Attorney-in-Fact|Client\s*(?:\/\s*Principal)?|Lead\s+Counsel|Counsel|Managing\s+Partner|Escrow\s+(?:Trust\s+)?Officer)\s*[:#,]?\s*(?:(?:Dr|Mr|Mrs|Ms|Prof)\.?\s+)?([A-Z][a-zA-Z'’-]+(?:-[A-Z][a-zA-Z'’-]+)?(?:,\s+[A-Z][a-zA-Z'’-]+(?:\s+[A-Z]\.?)?|\s+(?:[A-Z]\.?\s+)?[A-Z][a-zA-Z'’-]+(?:-[A-Z][a-zA-Z'’-]+)?))/gi },
|
|
140
148
|
{ type: 'LEGAL', regex: /\bCASE[-_][A-Z0-9_-]{4,}\b/gi },
|
|
141
149
|
{ type: 'LEGAL', regex: /\bMATTER[-_][A-Z0-9_-]{4,}\b/gi },
|
|
142
150
|
{ type: 'LEGAL', regex: /\b[A-Z]{2,4}[- ]?\d{2}[- ]?\d{4,}\b/g },
|
|
143
|
-
{ type: 'PRIVILEGE', regex:
|
|
151
|
+
{ type: 'PRIVILEGE', regex: /\bATTORNEY[- ]CLIENT[- ]PRIVILEGE[DS]?\b/gi },
|
|
144
152
|
{ type: 'LEGAL', regex: /\b(?:BATES|PROD|PLTF|DEFT|CONF|EXHIBIT)[-_ ]?[A-Z0-9]{2,10}[-_ ]?\d{4,10}\b/gi },
|
|
145
|
-
|
|
146
|
-
{ type: '
|
|
153
|
+
// Case / Proceeding / Arbitration Numbers (including OCR homoglyphs O/0, I/1, l/1)
|
|
154
|
+
{ type: 'LEGAL', regex: /\b(?:Case|Matter|Arbitration|Docket|Proceeding)\s*(?:(?:No\.?|Number|#)[:\s#]*|[:#]\s*)([A-Za-z0-9_-]{4,25})\b/gi },
|
|
155
|
+
{ type: 'LEGAL', regex: /\b(?:\d{1,2}:)?\d{2,4}[-_ ]?(?:CV|CR|MDL|BK|MC|MISC|MJ|PO|CA|AP|PR|AR)[-_ ][A-Za-z0-9_-]{3,15}\b/gi },
|
|
156
|
+
// Bar registration & CRD / Broker / Representative IDs (including OCR homoglyphs)
|
|
157
|
+
{ type: 'ID', regex: /\b(?:STATE\s+BAR|BAR\s+(?:NO\.?|#|ID)|SBN|ATTORNEY\s+REG(?:ISTRATION)?)[:\s#-]*([0-9OIloA-Za-z]{4,10})\b/gi },
|
|
158
|
+
{ type: 'ID', regex: /\b(?:CRD|CIK|Broker\s*ID|Rep(?:resentative)?\s*ID|Advisor\s*ID|Registration\s*(?:No\.?|#)?)[:\s#]*([0-9OIloA-Za-z]{5,12})\b/gi },
|
|
147
159
|
{ type: 'LEGAL', regex: /\b(?:RETAINER|ENGAGEMENT|REPRESENTATION)[-_: ]*(?:AGREEMENT|ID|REF)?[:\s#-]*[A-Z0-9_-]{4,20}\b/gi },
|
|
148
160
|
{ type: 'LEGAL', regex: /\bECLI:[A-Z]{2}:[A-Za-z0-9]{1,7}:\d{4}:[A-Za-z0-9.]{1,25}\b/g },
|
|
149
161
|
{ type: 'ID', regex: /\bPCT\/[A-Z]{2}\d{4}\/\d{6}\b/g },
|
|
150
|
-
{ type: 'ID', regex: /\b(?:TX|TXu|VA|VAu|PA|PAu|SR|SRu|SE|SEu|RE)\s*-?\d[-\d ]{5,9}\d\b/g }
|
|
162
|
+
{ type: 'ID', regex: /\b(?:TX|TXu|VA|VAu|PA|PAu|SR|SRu|SE|SEu|RE)\s*-?\d[-\d ]{5,9}\d\b/g },
|
|
163
|
+
// Escrow / Trust / Settlement / Disputed Account Numbers & ABA Routing
|
|
164
|
+
{ type: 'FINANCIAL', regex: /\b(?:Escrow\s+(?:Account|Acct|Deposit)|Trust\s+Account|Settlement\s+Account|Disputed\s+Account)\s*(?:Number|Num|No\.?|#)?[:\s#]+([A-Za-z0-9-]{5,25})\b/gi },
|
|
165
|
+
{ type: 'FINANCIAL', regex: /\b(?:ABA\s+Routing|Routing\s+Transit|Fedwire\s+Routing)\s*(?:Number|Num|No\.?|#)?[:\s#]+(\d{9})\b/gi },
|
|
166
|
+
// Legal Financial Amounts (lookbehind + standalone)
|
|
167
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:Settlement(?:\s+Amount)?|Retainer(?:\s+Fee)?|Hourly\s+Rate|Damages(?:\s+Claimed)?|Legal\s+Fees?|Sanctions?|Judgement|Judgment|Disgorgement|Penalty|(?:Prejudgment\s+)?Interest|Escrow(?:\s+Funds?|\s+Amount)?|Fine|Restitution)(?:[\s:]+(?:of)?[\s:]*|[:\s]+))(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])|[0-9,.'’]{3,}\b)/gi },
|
|
168
|
+
{ type: 'FINANCIAL', regex: /(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹]))/gi }
|
|
151
169
|
],
|
|
152
170
|
hr: [
|
|
153
171
|
{ type: 'NAME', isContextName: true, regex: /(?:Candidate|Applicant|Employee|Reporting To|Manager|Mentored by|Direct Report)[\s:]+([A-Z][a-z]*(?:\s+[A-Z][a-z]*)?)/g },
|
|
@@ -181,17 +199,26 @@ let PROFILE_RULES = {
|
|
|
181
199
|
{ type: 'ID', regex: /\b(?:FEIN|EIN|TIN|Tax\s*ID)[:\s#]*(\d{2}-\d{7})\b/gi },
|
|
182
200
|
{ type: 'ID', regex: /\b(?:CRD|CIK|Advisor\s*ID|Broker\s*ID)[:\s#]*(\d{5,10})\b/gi },
|
|
183
201
|
{ type: 'ID', regex: /\b(?:LEI|LEGAL[\s-]ENTITY[\s-]IDENTIFIER)[:\s#-]*[0-9A-Z]{20}\b/gi },
|
|
184
|
-
{ type: 'ID', regex: /\bBBG[0-9A-Z]{9}\b/g }
|
|
202
|
+
{ type: 'ID', regex: /\bBBG[0-9A-Z]{9}\b/g },
|
|
203
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:Wire(?:\s+(?:Transfer|Amount))?|Transfer|Balance|Deposit|Withdrawal|Settlement|Principal|Interest|Remittance|Payout|Transaction(?:\s+Amount)?|Payment(?:\s+Amount)?|Total|Amount)[:\s]+)(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])|[0-9,.'’]{3,}\b)/gi }
|
|
185
204
|
],
|
|
186
205
|
medical: [
|
|
187
|
-
{ type: '
|
|
206
|
+
{ type: 'NAME', isContextName: true, regex: /\b(?:PATIENT|Pt\.?|LEGAL\s+GUARDIAN(?:\/PROXY)?|PROXY|EMERGENCY\s+CONTACT|ATTENDING\s+PHYSICIAN|ATTENDING|SURGEON|PHYSICIAN|PROVIDER|SUBSCRIBER|GUARDIAN)\s*[:#|]?\s*(?!\b(?:NPI|MRN|DOB|ID|DATE|RECORD|PHONE)\b)(?:(?:Dr|Mr|Mrs|Ms|Prof)\.?\s+)?([A-Z][a-zA-Z'’-]+(?:-[A-Z][a-zA-Z'’-]+)?(?:,\s+[A-Z][a-zA-Z'’-]+(?:\s+[A-Z]\.?)?|\s+(?:[A-Z]\.?\s+)?[A-Z][a-zA-Z'’-]+(?:-[A-Z][a-zA-Z'’-]+)?))/gi },
|
|
207
|
+
// HL7 v2 PID-5 Caret-Delimited Patient / Provider Names (e.g. "Guillermo^Maricela^C", "Vance-Soto^Eleanor^M")
|
|
208
|
+
{ type: 'NAME', isContextName: true, isHL7Name: true, regex: /\b[A-Za-z'’-]{2,}\^[A-Za-z'’-]{2,}(?:\^[A-Za-z'’.-]+){0,4}\b/g },
|
|
209
|
+
// HL7 v2 Segment Delimited Dates (YYYYMMDD in PID-7, MSH-7, etc. e.g. "||19820412|F")
|
|
210
|
+
{ type: 'DATE', regex: /(?<=[|:])(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])(?=[|:\s])/g },
|
|
211
|
+
{ type: 'PHI', regex: /\b(?:MRN|Patient\s+(?:ID|Number|No\.?|#)|Medical\s+Record\s+(?:No\.?|Num(?:ber)?|#)|EHR(?:\s*(?:ID|Record|Number|No\.?|#))?)[\s:#.]+([A-Za-z0-9\/-]+)/gi },
|
|
188
212
|
{ type: 'DATE', regex: /\b(?:DOB|Date of Birth|BIRTHDAY)[\s:]+([0-9./-]{6,10})\b/gi },
|
|
189
|
-
{ type: 'PHI', regex: /\
|
|
213
|
+
{ type: 'PHI', regex: /\b(?:MRN|EHR)[-_ .]*[A-Za-z0-9\/-]{4,}\b/gi },
|
|
190
214
|
{ type: 'ID', regex: /\b(?:Insurance\s+(?:ID|No\.?|Number|#)|Policy(?:\s*(?:ID|No\.?|Number|#)|[:#])|Member\s*(?:ID|No\.?|Number|#|[:#])|Subscriber\s*(?:ID|No\.?|Number|#|[:#])|Group\s*(?:ID|No\.?|Number|#|[:#])|Plan\s*(?:ID|No\.?|Number|#|[:#])|Health(?:\s+Plan)?\s*(?:ID|No\.?|Number|#)|Rx\s*(?:ID|No\.?|Number|Group|BIN|PCN|#))[:\s#]+([A-Za-z0-9-]{3,30})\b/gi },
|
|
191
215
|
{ type: 'ID', regex: /\b(?:Health\s+Plan(?:\s+Beneficiary)?|Beneficiary(?:\s+No\.?|\s+Number)?|HPN)[:\s#]+([A-Za-z0-9-]+)/gi },
|
|
192
216
|
{ type: 'ID', regex: /\bHPN[-_][A-Za-z0-9-]+\b/gi },
|
|
193
217
|
{ type: 'ID', regex: /\b(?:BCB|BCBS|AETNA|CIGNA|UHC|HUMANA|MEDICARE|MEDICAID)[-_A-Za-z0-9]+\b/gi },
|
|
194
|
-
{ type: 'ID', regex: /\b(?:NPI|National
|
|
218
|
+
{ type: 'ID', regex: /\b(?:NPI|National\s+Provider\s+(?:Identifier|ID)|Provider\s+(?:NPI|ID)|Attending\s+(?:NPI|Provider\s+ID)|Physician\s+NPI)[:\s#.]*([0-9OIlo]{10})\b/gi },
|
|
219
|
+
{ type: 'ID', regex: /\(01\)\d{14}(?:\(\d{2}\)[A-Za-z0-9-]+)+/g },
|
|
220
|
+
{ type: 'LOCATION', regex: /\b(?:Pavilion|Ward|Bed|Room|Rm\.?|Suite|Bldg|Building|Floor|Wing|Tower|Unit)\s+[A-Za-z0-9-]+\b/gi },
|
|
221
|
+
{ type: 'DATE', regex: /\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember))\s+\d{1,2}(?:st|nd|rd|th)?,?\s+\d{4}\b/gi },
|
|
195
222
|
{ type: 'ID', regex: /\b(?:Device\s+(?:Identifier|ID|Serial|No\.?|Number)|UDI)[:\s#]+([A-Za-z0-9-]+)/gi },
|
|
196
223
|
{ type: 'ID', regex: /\bUDI[-_][A-Za-z0-9-]+\b/gi },
|
|
197
224
|
{ type: 'ID', regex: /\b(?:Vehicle\s+(?:Serial|ID|Identification(?:\s+Number)?|No\.?|Number)|VIN)[:\s#]+([A-Za-z0-9-]+)/gi },
|
|
@@ -285,7 +312,7 @@ let PROFILE_RULES = {
|
|
|
285
312
|
{ type: 'ID', regex: /\bPARCEL[- ]?\d{5,15}\b/gi },
|
|
286
313
|
{ type: 'ID', regex: /\b(?:APN|Assessor(?:'s)?\s*Parcel(?:\s*Number)?|Parcel\s*(?:ID|Number|No\.?|#))[:\s#-]*(\d{2,5}[-\s]\d{2,5}[-\s]\d{2,5}(?:[-\s]\d{1,4})?|\d{6,15})\b/gi },
|
|
287
314
|
{ type: 'ID', regex: /\bTENANT[-_]ID[-_][0-9]{4,}\b/gi },
|
|
288
|
-
{ type: 'FINANCIAL', regex: /(?<=\b(?:RENT|LEASE|ESCROW)[\s:]+)(?:[$€£¥₪₽₹]
|
|
315
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:RENT|LEASE|ESCROW|Purchase\s+Price|Listing\s+Price|Asking\s+Price|Down\s+Payment|Mortgage(?:\s+Balance)?|Closing\s+Costs?|Appraisal(?:\s+Value)?)[\s:]+)(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])|[0-9,.'’]{3,}\b)/gi },
|
|
289
316
|
{ type: 'SECRET', regex: /\b(?:GATE|DOOR|LOBBY)[-_ ](?:CODE|PIN)[\s:]*\d{4,6}\b/gi },
|
|
290
317
|
{ type: 'ID', regex: /\b(?:Escrow\s*(?:Number|No\.?|#|Account|File|Order)|Escrow)[:\s#]*([A-Za-z0-9-]{5,18})\b/gi },
|
|
291
318
|
{ type: 'ID', regex: /\b(?:Title\s*Policy|Title\s*Order|Title\s*Commitment)\s*(?:#|ID|No\.?)?[:\s#]*([A-Z0-9-]{6,20})\b/gi },
|
|
@@ -396,7 +423,7 @@ let PROFILE_RULES = {
|
|
|
396
423
|
{ type: 'FINANCIAL', regex: /\b(?:Policy|Contract)\s*(?:No\.?|Number|#)[:\s]+[A-Z0-9][A-Z0-9\-]{3,14}\b/gi },
|
|
397
424
|
{ type: 'ID', regex: /\bCRD\s*#?\s*\d{4,8}\b/gi },
|
|
398
425
|
{ type: 'FINANCIAL', regex: /\b(?:Annual\s+(?:Distribution|Withdrawal)|RMD|Required\s+Minimum\s+Distribution)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’]+\b/gi },
|
|
399
|
-
{ type: 'FINANCIAL', regex:
|
|
426
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:Portfolio(?:\s+Value)?|Market\s+Value|Net\s+Worth|AUM|Total\s+Assets)[:\s]+)(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])|[0-9,.'’]{3,}\b)/gi },
|
|
400
427
|
{ type: 'FINANCIAL', regex: /\b(?:Roth\s+)?(?:IRA|401k|401\(k\)|403b|403\(b\)|SEP|SIMPLE)\s*(?:Account|Acct|Plan)?\s*(?:No|Number|#)?[:\s#]*[A-Z0-9]{4,15}\b/gi },
|
|
401
428
|
{ type: 'ID', regex: /\bCUSIP[:\s#]*([0-9A-Z]{9})\b/gi },
|
|
402
429
|
{ type: 'ID', regex: /\bISIN[:\s#]*([A-Z]{2}[0-9A-Z]{9}[0-9])\b/gi },
|
|
@@ -409,7 +436,7 @@ let PROFILE_RULES = {
|
|
|
409
436
|
{ type: 'FINANCIAL', regex: /\b(?:Loss|Claim\s+Amount|Claim\s+Settlement|Settlement|Reserve|Indemnity)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’]+\b/gi },
|
|
410
437
|
{ type: 'ID', regex: /\b(?:(?:Assigned\s+)?Adjuster\s+(?:ID|No)|Claim\s+Rep(?:\.|resentative)?)[:\s#]*[-A-Z0-9]{4,15}\b/gi },
|
|
411
438
|
{ type: 'ID', regex: /\bNAIC(?:\s+(?:Company\s+)?(?:Code|CoCode|No\.?|Number|#))?[:\s#]*(\d{5})\b/gi },
|
|
412
|
-
{ type: 'FINANCIAL', regex: /\b(?:Deductible|Premium|Coverage\s+Amount)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'
|
|
439
|
+
{ type: 'FINANCIAL', regex: /\b(?:Deductible|Premium|Coverage\s+Amount)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’\u2018\u2019]+\b/gi },
|
|
413
440
|
{ type: 'ID', regex: /\b[A-HJ-NPR-Z0-9]{17}\b/g },
|
|
414
441
|
{ type: 'ID', regex: /\b(?:Insured|Named\s+Insured)[:\s]+[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+/g },
|
|
415
442
|
{ type: 'ID', regex: /\b(?:Agent|Producer)\s*(?:Code|No|ID)[:\s#]*[-A-Z0-9]{4,15}\b/gi },
|
|
@@ -421,15 +448,17 @@ let PROFILE_RULES = {
|
|
|
421
448
|
accounting: [
|
|
422
449
|
{ type: 'ID', regex: /\b(?:EIN|FEIN|Tax\s+ID)[:\s#]*\d{2}-\d{7}\b/gi },
|
|
423
450
|
{ type: 'FINANCIAL', regex: /\b(?:AGI|Adjusted\s+Gross\s+Income|Taxable\s+Income|Total\s+Income)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’]+\b/gi },
|
|
424
|
-
{ type: 'FINANCIAL', regex: /\b(?:Form\s+|Withheld\s+)?Box\s+\d{1,2}[a-z]?(?:\s*:\s*[A-Z])?\s*[:\s]+(?:[
|
|
451
|
+
{ type: 'FINANCIAL', regex: /\b(?:Form\s+|Withheld\s+)?Box\s+\d{1,2}[a-z]?(?:\s*:\s*[A-Z])?\s*[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’\u2018\u2019]+\b/gi },
|
|
425
452
|
{ type: 'ID', regex: /\b(?:Form|Schedule)\s+(?:1040|1040-SR|W-2|W-4|1099-[A-Z]{1,4}|K-1|941|990|4562)\b/gi },
|
|
426
|
-
{ type: 'FINANCIAL', regex: /\b(?:Federal|State|Assessed)?\s*(?:Tax\s+Due|Balance\s+Due|Overpayment|Refund)[:\s]+(?:[
|
|
453
|
+
{ type: 'FINANCIAL', regex: /\b(?:Federal|State|Assessed)?\s*(?:Tax\s+Due|Balance\s+Due|Overpayment|Refund)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’\u2018\u2019]+\b/gi },
|
|
427
454
|
{ type: 'ID', regex: /\b(?:State\s+Tax\s+ID|SUI|UI\s+Account\s+No)[:\s#]*[A-Z]{0,3}[-]?\d{4,15}\b/gi },
|
|
428
|
-
{ type: 'FINANCIAL', regex: /\b(?:Gross|Net|Medicare|Social\s+Security)\s+(?:Pay|Wages|Tips|Withholding)[:\s]+(?:[
|
|
455
|
+
{ type: 'FINANCIAL', regex: /\b(?:Gross|Net|Medicare|Social\s+Security)\s+(?:Pay|Wages|Tips|Withholding)[:\s]+(?:[$€£¥₪₽₹]|(?:USD|EUR|GBP|CHF|ILS|RUB)\s?)[\d,.'’\u2018\u2019]+\b/gi },
|
|
429
456
|
{ type: 'ID', regex: /\b(?:CAF(?:\s+ID)?|(?:Practitioner|Tax\s+Preparer)\s+(?:PIN|ID)|PTIN)[:\s#]*[A-Z0-9-]{6,12}\b/gi },
|
|
430
457
|
{ type: 'ID', regex: /\bEFIN[:\s#]*\d{6}\b/gi },
|
|
431
458
|
{ type: 'ID', regex: /\bGL[-_\s]*(?:Account|Acct|Code)?[:\s#]*\d{4,10}\b/gi },
|
|
432
|
-
{ type: 'ID', regex: /\b(?:Cost\s+Center|CC)[-_\s]*(?:ID|Code|#)?[:\s#]*[A-Z0-9_-]*\d[A-Z0-9_-]*\b/gi }
|
|
459
|
+
{ type: 'ID', regex: /\b(?:Cost\s+Center|CC)[-_\s]*(?:ID|Code|#)?[:\s#]*[A-Z0-9_-]*\d[A-Z0-9_-]*\b/gi },
|
|
460
|
+
{ type: 'ID', regex: /\b(?:Invoice|Inv|Purchase\s+Order|PO|Bill|Check|Voucher|Remittance)\s*(?:Number|Num|No\.?|#)?[:\s#]+([A-Za-z0-9_-]{4,25})\b/gi },
|
|
461
|
+
{ type: 'FINANCIAL', regex: /(?<=\b(?:Invoice(?:\s+Total)?|Amount\s+Due|Subtotal|Total\s+Due|Payment(?:\s+Amount)?|Ledger\s+Balance|Credit|Debit|Net\s+Amount|Total\s+Paid|Billed|Remittance)[:\s]+)(?:(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\s*|[$€£¥₪₽₹]\s*)[0-9,.'’]*\d[KMB]?\b|\b\d[0-9,.'’]*\d?[KMB]?\s*(?:\b(?:USD|EUR|GBP|CHF|ILS|RUB)\b|[$€£¥₪₽₹])|[0-9,.'’]{3,}\b)/gi }
|
|
433
462
|
],
|
|
434
463
|
pharma: [
|
|
435
464
|
{ type: 'ID', regex: /\b(?:Subject|Patient|Participant)\s+(?:ID|No)[:\s#]*[-A-Z0-9]{3,15}\b/gi },
|
|
@@ -588,7 +617,7 @@ const CORPORATE_SUFFIXES = new Set([
|
|
|
588
617
|
let NOT_NAME_WORDS = new Set([
|
|
589
618
|
'uk', 'eu', 'us', 'usa', 'dpa', 'ico', 'dpo', 'ciso', 'ssrn', 'elsevier', 'gdpr', 'ccpa', 'cpra', 'hipaa', 'soc2', 'iso27001', 'governance', 'regulatory', 'framework', 'mandate', 'mandates', 'guidance', 'statute', 'statutes', 'jurisdiction', 'jurisdictions', 'recital', 'article', 'articles', 'treatise', 'workstation', 'device', 'endpoint', 'blueprint', 'personal', 'cross-border', 'cross', 'border', 'transfer', 'retrieval', 'augmented', 'generation', 'limitation', 'discrimination', 'imposes', 'heavy', 'identifiable', 'bypasses', 'author', 'authors', 'contact', 'contacts', 'keywords', 'keyword', 'keys', 'key', 'separation', 'pre-print', 'preprint', 'abstract', 'structured', 'background', 'methods', 'results', 'discussion', 'conclusion', 'conclusions', 'introduction', 'overview', 'workflow', 'paradigm', 'nomenclature', 'repository', 'classification', 'phenotypes', 'biomedical', 'bioinformatics', 'identifiers', 'de-identification', 'sanitization', 'ephemeral', 'validation', 'validating', 'genomic', 'genomics', 'clinical', 'phenotype', 'target', 'corresponding', 'subject', 'biorxiv', 'medrxiv', 'arxiv', 'privacyscrubber', 'research', 'lead', 'architect', 'chief', 'founder', 'symbols', 'gene', 'genes', 'sample', 'barcode', 'pipeline', 'downstream', 'pedigree', 'trees', 'exposes', 'violates', 'protecting', 'anonymization', 'redacted', 'redaction', 'zero-trust', 'ztds',
|
|
590
619
|
'conventional', 'model', 'models', 'potential', 'multi', 'million', 'dollar', 'dollars', 'surrogate', 'surrogates', 'geographic', 'subdivisions', 'subdivision', 'inference', 'response', 'responses', 'latency', 'benchmarks', 'benchmark', 'experimental', 'methodology', 'informatics', 'ethics', 'accountability', 'civil', 'rights', 'perimeter', 'network', 'requirements', 'requirement', 'statutory', 'categories', 'category', 'regulations', 'regulation', 'penalties', 'penalty', 'disclosure', 'disclosures', 'clinician', 'terminal', 'transport', 'inpatient', 'discharge', 'summaries', 'operative', 'reports', 'outpatient', 'psychiatric', 'telehealth', 'consultation', 'pathology', 'sequencing', 'laboratory', 'sensitivity', 'specificity', 'proxy', 'gateways', 'gateway', 'packet', 'packets', 'inspection', 'declarations', 'availability', 'competing', 'interests', 'interventions', 'multicenter', 'multi-center', 'institution', 'institutional', 'protocol', 'deviations', 'adverse', 'events', 'abbreviations', 'agents', 'agent', 'committee', 'committees', 'board', 'boards', 'nih', 'pubmed', 'central', 'open', 'access', 'policy', 'trial', 'trials', 'crf', 'crfs', 'ehr', 'ehrs', 'baa', 'baas', 'hitech', 'safe', 'harbor', 'section',
|
|
591
|
-
'retirement', 'roth', 'ira', 'acct', 'custodial', 'brokerage', 'portfolio', 'annuity', 'dividend', 'distribution', 'reconciliation', 'withholding', 'remuneration', 'pin', 'lobby', 'passcode', 'code', 'gate', 'door', 'access', 'tenant', 'landlord', 'escrow', 'cadastral', 'claim', 'claims', 'adjuster', 'insured', 'carrier', 'indemnity', 'underwriter', 'underwriting', 'deductible', 'premium', 'settlement', 'loss', 'cargo', 'writers', 'guild', 'ghostwriter', 'actor', 'screenplay', 'audiovisual', 'cinematic', 'co-production', 'alumnus', 'alumni', 'registrar', 'transcript', 'diploma', 'orchestration', 'runtime', 'helpdesk', 'freshdesk', 'intercom', 'zendesk', 'investigational', 'pharmacovigilance', 'reaction', 'medication', 'manufacturing', 'lot', 'industrial', 'electronics', 'driver', 'drivers', 'license', 'licence', 'clearing', 'house', 'automated', 'central', 'securities', 'depository', 'arbitration', 'tribunal', 'instrument', 'infrastructure', 'talent', 'dossier',
|
|
620
|
+
'retirement', 'roth', 'ira', 'acct', 'custodial', 'brokerage', 'portfolio', 'annuity', 'dividend', 'distribution', 'reconciliation', 'withholding', 'remuneration', 'pin', 'lobby', 'passcode', 'code', 'gate', 'door', 'access', 'tenant', 'landlord', 'escrow', 'cadastral', 'claim', 'claims', 'adjuster', 'insured', 'carrier', 'indemnity', 'underwriter', 'underwriting', 'deductible', 'premium', 'settlement', 'loss', 'cargo', 'writers', 'guild', 'ghostwriter', 'actor', 'screenplay', 'audiovisual', 'cinematic', 'co-production', 'alumnus', 'alumni', 'registrar', 'transcript', 'diploma', 'orchestration', 'runtime', 'helpdesk', 'freshdesk', 'intercom', 'zendesk', 'investigational', 'pharmacovigilance', 'reaction', 'medication', 'manufacturing', 'lot', 'industrial', 'electronics', 'driver', 'drivers', 'license', 'licence', 'clearing', 'house', 'automated', 'central', 'securities', 'depository', 'arbitration', 'tribunal', 'instrument', 'infrastructure', 'talent', 'dossier', 'tel', 'phone', 'fax', 'mobile', 'cell', 'email', 'dpoa', 'poa',
|
|
592
621
|
// Grammatical & Sentence Starters
|
|
593
622
|
'the', 'a', 'an', 'this', 'that', 'these', 'those', 'my', 'your', 'his', 'her', 'their', 'our', 'its', 'it', 'he', 'she', 'they', 'we', 'i', 'you', 'who', 'whom', 'which', 'what', 'whose', 'why', 'how', 'when', 'where', 'with', 'for', 'from', 'by', 'to', 'at', 'in', 'on', 'of', 'about', 'as', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'and', 'but', 'or', 'so', 'yet', 'im', "i'm", "you're", "they're", "we're", "it's", "he's", "she's", "that's", "there's", "what's", "who's", "i've", "you've", "we've", "they've", "i'll", "you'll", "we'll", "they'll", "i'd", "you'd", "we'd", "they'd",
|
|
594
623
|
// Verbs, Auxiliaries, Commands & Imperatives
|
|
@@ -727,7 +756,7 @@ const PROFILE_JARGON = {
|
|
|
727
756
|
'insurance', 'bcbs', 'bronchitis', 'amoxicillin', 'penicillin', 'antibiotic', 'antibiotics', 'vital',
|
|
728
757
|
'vitals', 'bp', 'hr', 'bpm', 'mmhg', 'allergies', 'dosage', 'parenchyma', 'ventricles', 'fazekas',
|
|
729
758
|
'ischemia', 'lesion', 'cardiology', 'atherosclerotic', 'aortocoronary', 'bypass', 'graft', 'hyperlipidemia',
|
|
730
|
-
'diverticulitis', 'resection', 'colon', 'superbill', 'encounter', 'cpt', 'hcpcs', 'icd-10'
|
|
759
|
+
'diverticulitis', 'resection', 'colon', 'superbill', 'encounter', 'cpt', 'hcpcs', 'icd-10', 'pt'
|
|
731
760
|
],
|
|
732
761
|
realestate: [
|
|
733
762
|
'escrow', 'tenant', 'landlord', 'lease', 'mortgage', 'appraisal', 'broker', 'property', 'zoning',
|
|
@@ -744,7 +773,13 @@ const PROFILE_JARGON = {
|
|
|
744
773
|
'recitals', 'whereas', 'confidential', 'information', 'care', 'term', 'exhibit', 'party', 'parties',
|
|
745
774
|
'disclosing', 'receiving', 'witnesseth', 'standard', 'indemnification', 'liability', 'governing',
|
|
746
775
|
'law', 'docket', 'deponent', 'reporter', 'appearances', 'examination', 'services', 'scope', 'work',
|
|
747
|
-
'master', 'msa'
|
|
776
|
+
'master', 'msa',
|
|
777
|
+
'finra', 'sec', 'disciplinary', 'arbitration', 'proceeding', 'proceedings', 'dispute', 'resolution',
|
|
778
|
+
'escrow', 'claimant', 'respondent', 'petitioner', 'appellant', 'appellee', 'trustee', 'trustor',
|
|
779
|
+
'grantor', 'grantee', 'fiduciary', 'principal', 'agent', 'officer', 'counsel', 'lead', 'attorney',
|
|
780
|
+
'partner', 'associate', 'representative', 'broker', 'primary', 'privilege', 'privileged', 'doctrine',
|
|
781
|
+
'work-product', 'power', 'durable', 'evidence', 'rules', 'rule', 'statutory', 'disqualification',
|
|
782
|
+
'acquisition', 'file', 'securities', 'exchange'
|
|
748
783
|
],
|
|
749
784
|
academic: [
|
|
750
785
|
'institutional', 'review', 'board', 'irb', 'protocol', 'national', 'institutes', 'health', 'nih',
|
|
@@ -829,7 +864,7 @@ const PROFILE_JARGON = {
|
|
|
829
864
|
'underwriting': 'underwriting', 'lending': 'underwriting', 'mortgage': 'underwriting', 'loan': 'underwriting', 'income': 'underwriting', 'income_verification': 'underwriting', 'payroll': 'underwriting', 'w2': 'underwriting', 'paystub': 'underwriting',
|
|
830
865
|
'medical': 'medical', 'healthcare': 'medical', 'health': 'medical', 'pharma': 'pharma', 'hipaa': 'medical',
|
|
831
866
|
'engineering': 'engineering', 'dev': 'dev', 'api': 'dev', 'devops': 'engineering', 'tech': 'tech',
|
|
832
|
-
'finance': 'finance', 'bizops': 'bizops', 'sales': 'sales', 'wealthmgmt': 'wealthmgmt', 'wealth': 'wealthmgmt', 'insurance': 'insurance', 'accounting': 'accounting', 'pci': 'finance',
|
|
867
|
+
'finance': 'finance', 'financial': 'finance', 'bizops': 'bizops', 'sales': 'sales', 'wealthmgmt': 'wealthmgmt', 'wealth': 'wealthmgmt', 'insurance': 'insurance', 'accounting': 'accounting', 'pci': 'finance',
|
|
833
868
|
'legal': 'legal', 'compliance': 'compliance', 'ccpa': 'ccpa', 'gdpr': 'compliance', 'soc2': 'compliance', 'iso27001': 'compliance', 'nist': 'compliance', 'dpo': 'compliance', 'grc': 'compliance',
|
|
834
869
|
'hr': 'hr', 'security': 'security', 'marketing': 'marketing', 'support': 'support',
|
|
835
870
|
'realestate': 'realestate', 'academic': 'academic', 'agents': 'agents', 'ai_agents': 'agents', 'creative': 'creative', 'personal': 'personal'
|
|
@@ -847,16 +882,18 @@ const PROFILE_JARGON = {
|
|
|
847
882
|
}
|
|
848
883
|
|
|
849
884
|
function stitchOrphanedNameLines(text, profile) {
|
|
850
|
-
if (
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
text = text.replace(/
|
|
885
|
+
if (!text || !text.includes('\n')) return text;
|
|
886
|
+
const prof = (profile || 'general').toLowerCase();
|
|
887
|
+
if (prof === 'medical' || prof === 'general') {
|
|
888
|
+
text = text.replace(/(Patient\s+Name|Emergency\s+Contact|In\s+Case\s+of\s+Emergency|ICE(?:\s+Contact)?):\s*\r?\n+([A-Z\p{Lu}][A-Za-z0-9&.,'’ \t-]*?[A-Za-z0-9\p{Lu}\p{Ll}])(?=\r?\n|$)/gui, '$1: $2');
|
|
889
|
+
} else if (prof === 'legal') {
|
|
890
|
+
text = text.replace(/Defendant:\s*\r?\n+([A-Z][a-zA-Z]+\s[A-Z][a-zA-Z]+)/g, 'Defendant: $1');
|
|
854
891
|
}
|
|
855
892
|
return text;
|
|
856
893
|
}
|
|
857
894
|
|
|
858
895
|
function detectMatches(text, activeProfile = 'general', customRules = [], nlpNames = [], enabledEntities = null, mlEntities = []) {
|
|
859
|
-
let textToProcess = text.replace(/[\u200b\u200c\u200d\ufeff]/
|
|
896
|
+
let textToProcess = stitchOrphanedNameLines(text, activeProfile).replace(/[\u200b\u200c\u200d\ufeff\u00ad]/gi, '');
|
|
860
897
|
textToProcess = textToProcess.replace(/([a-z])(Email|Phone|Mobile|Tel|Address|IP|ID|URL|SSN|Date):/g, '$1 $2:');
|
|
861
898
|
|
|
862
899
|
let matches = [];
|
|
@@ -934,9 +971,9 @@ const PROFILE_JARGON = {
|
|
|
934
971
|
if (!val || NAME_STOP_LIST.has(val) || currentJargon.has(val) || NOT_NAME_WORDS.has(val)) continue;
|
|
935
972
|
|
|
936
973
|
if (rule.type === 'NAME') {
|
|
937
|
-
let words = val.split(/[ \t\xA0]+/);
|
|
974
|
+
let words = val.split(/[ \t\xA0\^]+/);
|
|
938
975
|
if (!rule.isContextName) {
|
|
939
|
-
let origWords = matchedText.split(/[ \t\xA0]+/);
|
|
976
|
+
let origWords = matchedText.split(/[ \t\xA0\^]+/);
|
|
940
977
|
while (words.length > 2 && (currentJargon.has(words[0]) || (words[0].length > 1 && NOT_NAME_WORDS.has(words[0])) || (words[0].replace(/[^\p{L}]/gu, '').length > 1 && NOT_NAME_WORDS.has(words[0].replace(/[^\p{L}]/gu, ''))))) {
|
|
941
978
|
origWords.shift();
|
|
942
979
|
words.shift();
|
|
@@ -956,7 +993,7 @@ const PROFILE_JARGON = {
|
|
|
956
993
|
if (cleanW.length <= 1) return false;
|
|
957
994
|
return currentJargon.has(w) || NOT_NAME_WORDS.has(w) || NOT_NAME_WORDS.has(cleanW) || NAME_STOP_LIST.has(w) || NAME_STOP_LIST.has(cleanW);
|
|
958
995
|
}) ||
|
|
959
|
-
val.split(/[ \t\xA0
|
|
996
|
+
val.split(/[ \t\xA0\^\-]+/).some(sw => {
|
|
960
997
|
const cleanSW = sw.replace(/[^\p{L}]/gu, '');
|
|
961
998
|
if (cleanSW.length <= 1) return false;
|
|
962
999
|
return currentJargon.has(sw) || NOT_NAME_WORDS.has(sw) || NOT_NAME_WORDS.has(cleanSW) || NAME_STOP_LIST.has(sw) || NAME_STOP_LIST.has(cleanSW);
|
|
@@ -974,6 +1011,7 @@ const PROFILE_JARGON = {
|
|
|
974
1011
|
|
|
975
1012
|
if (rule.isContextName && words.length > 0 && words.some(w => {
|
|
976
1013
|
const cleanW = w.replace(/[^\p{L}]/gu, '');
|
|
1014
|
+
if (cleanW.length <= 1) return false;
|
|
977
1015
|
if (rule.isCorporateName && (CORPORATE_SUFFIXES.has(cleanW) || US_STATES_SET.has(cleanW))) {
|
|
978
1016
|
return false;
|
|
979
1017
|
}
|
|
@@ -1168,7 +1206,12 @@ const PROFILE_JARGON = {
|
|
|
1168
1206
|
cleaned = cleaned.replace(/^(?:Here (?:is|are) (?:the )?(?:redacted|scrubbed|sanitized|processed|clean|updated|modified) (?:text|output|version|data).*?[:\n]+|\*\*Scrubbed Text\*\*[:\n]+|### Scrubbed Text[:\n]+)/i, '');
|
|
1169
1207
|
cleaned = cleaned.replace(/^\s*Edit\s*\n+/i, "");
|
|
1170
1208
|
cleaned = cleaned.replace(/\s*\bEdit\s+in\s+a\s+page\b\s*$/i, "");
|
|
1171
|
-
// 3. Strip
|
|
1209
|
+
// 3. Strip echoed system instructions and PrivacyScrubber pseudonymization disclaimers
|
|
1210
|
+
cleaned = cleaned.replace(/^\s*(?:Understood|Acknowledged|Got it|Sure|OK|Okay|Note taken|Understood[.,!])[^\n]*\n+/i, "");
|
|
1211
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*\[(?:Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE)[\s\S]*?exactly as formatted in your response\.?\]\s*(?:\n*|$)/gi, "\n\n");
|
|
1212
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*\[(?:Privacy Note|Context: identifiers|Privacy Scrubber Mode|SYSTEM INSTRUCTION: DATA PRIVACY MODE)[^\]]*\]\s*(?:\n*|$)/gi, "\n\n");
|
|
1213
|
+
cleaned = cleaned.replace(/(?:^|\n*)\s*(?:Direct identifiers in this prompt were pseudonymized|I will retain all bracketed tokens)[^\n]*(?:\n*|$)/gi, "\n\n");
|
|
1214
|
+
// 4. Strip stray leading colons, semicolons, or separators left by stripped icons/artifact headers
|
|
1172
1215
|
cleaned = cleaned.replace(/^[:;|\-\—\–]+(?=\n|$)/, "");
|
|
1173
1216
|
cleaned = cleaned.replace(/^[:;]+\s*/, "");
|
|
1174
1217
|
return cleaned.trim();
|