@privacyscrubber/sdk 2.4.7 → 2.4.8
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/cli.js +1 -1
- package/examples/python-bridge/fastapi_example.py +1 -1
- package/examples/python-bridge/privacyscrubber/__init__.py +1 -1
- package/examples/python-bridge/privacyscrubber/bridge_daemon.cjs +1 -1
- package/examples/python-bridge/privacyscrubber/cli.py +1 -1
- package/examples/python-bridge/pyproject.toml +1 -1
- package/examples/python-bridge/setup.py +1 -1
- package/index.cjs +179 -13
- package/index.js +179 -13
- package/package.json +1 -1
- package/ps-license-manager.js +1 -1
- package/ps-pii-engine.cjs +1 -1
- package/sarif.cjs +2 -2
- package/scrubber-core.cjs +1 -1
package/index.js
CHANGED
|
@@ -41,7 +41,7 @@ export const SDK_VERSION = (() => {
|
|
|
41
41
|
return pkgJson.version;
|
|
42
42
|
}
|
|
43
43
|
} catch (_) {}
|
|
44
|
-
return '2.4.
|
|
44
|
+
return '2.4.8';
|
|
45
45
|
})();
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -134,7 +134,7 @@ export function validateLicenseKey(key) {
|
|
|
134
134
|
* @param {Record<string, string>|string[]} currentTokenMap
|
|
135
135
|
* @returns {object}
|
|
136
136
|
*/
|
|
137
|
-
export function buildAuditTelemetry(currentTokenMap = {}) {
|
|
137
|
+
export function buildAuditTelemetry(currentTokenMap = {}, extraStats = {}) {
|
|
138
138
|
const entities = {};
|
|
139
139
|
let totalCount = 0;
|
|
140
140
|
|
|
@@ -244,12 +244,31 @@ export function buildAuditTelemetry(currentTokenMap = {}) {
|
|
|
244
244
|
}
|
|
245
245
|
];
|
|
246
246
|
|
|
247
|
+
const rawLicenseTier = String(extraStats?.licenseTier || '').trim().toUpperCase();
|
|
248
|
+
const isOrganizationalScope = ['TEAMS', 'SDK', 'OEM', 'ENTERPRISE', 'ENTERPRISE_AIRGAP'].includes(rawLicenseTier);
|
|
249
|
+
const auditScope = isOrganizationalScope ? {
|
|
250
|
+
tier: rawLicenseTier,
|
|
251
|
+
isOrganizational: true,
|
|
252
|
+
badge: 'ORGANIZATIONAL MULTI-SEAT COMPLIANCE SCOPE',
|
|
253
|
+
coverage: 'Covers department, clinic, or firm personnel under unified ZTDS policy governance.',
|
|
254
|
+
upgradeRecommended: false,
|
|
255
|
+
upgradeUrl: null
|
|
256
|
+
} : {
|
|
257
|
+
tier: rawLicenseTier || 'SINGLE_OPERATOR',
|
|
258
|
+
isOrganizational: false,
|
|
259
|
+
badge: 'SINGLE-OPERATOR PERSONAL SCOPE',
|
|
260
|
+
coverage: 'Valid for individual workstation only. Multi-employee clinics, CPA firms, and departments require TEAMS ($99/mo flat, unlimited seats) for organizational audit coverage.',
|
|
261
|
+
upgradeRecommended: true,
|
|
262
|
+
upgradeUrl: 'https://privacyscrubber.com/pricing/?tier=teams&utm_source=audit_receipt&utm_medium=scope_upsell'
|
|
263
|
+
};
|
|
264
|
+
|
|
247
265
|
return {
|
|
248
266
|
totalCount,
|
|
249
267
|
entities,
|
|
250
268
|
types,
|
|
251
269
|
riskLevel,
|
|
252
270
|
frameworksList: Array.from(frameworksSet),
|
|
271
|
+
auditScope,
|
|
253
272
|
statutoryCitations,
|
|
254
273
|
ipHoldings,
|
|
255
274
|
agenticProtocol,
|
|
@@ -303,6 +322,19 @@ export function _resetCommunityNoticeForTesting() {
|
|
|
303
322
|
communityNoticeLogged = false;
|
|
304
323
|
}
|
|
305
324
|
|
|
325
|
+
export const FREE_PROD_SPECIALIZED_CALL_LIMIT = 250;
|
|
326
|
+
let _freeProdSpecializedCalls = 0;
|
|
327
|
+
let _prodProfileFallbackNoticeLogged = false;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Resets the production specialized call quota state for testing purposes.
|
|
331
|
+
* @private
|
|
332
|
+
*/
|
|
333
|
+
export function _resetProdQuotaForTesting() {
|
|
334
|
+
_freeProdSpecializedCalls = 0;
|
|
335
|
+
_prodProfileFallbackNoticeLogged = false;
|
|
336
|
+
}
|
|
337
|
+
|
|
306
338
|
let devSecretNoticeLogged = false;
|
|
307
339
|
|
|
308
340
|
function emitDevSecretNoticeIfNeeded(isPro, tokenMap = {}, limit = 15000) {
|
|
@@ -483,6 +515,82 @@ We request approval to acquire a **Developer SDK License** (\$299/month flat or
|
|
|
483
515
|
* auditReceipt: string
|
|
484
516
|
* }}
|
|
485
517
|
*/
|
|
518
|
+
const SDK_VERTICAL_DETECTORS = [
|
|
519
|
+
{ profile: 'medical', label: 'Medical PHI (HIPAA)', regex: /\b(?:Patient\s*(?:Name|ID|DOB|Record)|MRN\b|Medical\s+Record|Attending\s+Physician|Chief\s+Complaint|Diagnosis\s*:|ICD-10|HIPAA|Clinical\s+Intake|Discharge\s+Summary|MedPod|NPI\s*(?:#|No|:)?\s*\d{10}|Medicare\s*(?:ID|Beneficiary|Claim)|Medicaid\s*ID|Prescription|Rx\s*#|Blood\s+Type|Vital\s+Signs|Radiology|Lab\s+Results|EHR\b|EMR\b)\b/gi },
|
|
520
|
+
{ profile: 'accounting', label: 'Tax & Accounting', regex: /\b(?:Form\s*1040|Form\s*W-2|Form\s*1099|Adjusted\s+Gross\s+Income|Employer\s+Identification\s+Number|Schedule\s+C\b|Steuer-ID|USt-IdNr|Tax\s+Return|General\s+Ledger|Withholding\s+Allowance|Total\s+Tax\s+Liability)\b/gi },
|
|
521
|
+
{ profile: 'wealthmgmt', label: 'Wealth Management', regex: /\b(?:Revocable\s+Living\s+Trust|Irrevocable\s+(?:Generation-Skipping\s+)?Trust|Grantor\s*:|Settlor\s*:|Trustee\s*:|Beneficiary\s+Designation|Roth\s+IRA|Asset\s+Allocation|FBO\b|CUSIP\s*:|Grantor\s+Retained\s+Annuity\s+Trust|AUM\s*:)\b/gi },
|
|
522
|
+
{ profile: 'legal', label: 'Legal & Contracts', regex: /\b(?:Non-Disclosure\s+Agreement|Attorney-Client\s+Privilege|Docket\s+No|Hereinafter\s+referred|Indemnification\s+Clause|Governing\s+Law\s+and\s+Jurisdiction|Plaintiff\b|Defendant\b|Subpoena\b|Deposition\b|State\s+Bar\s*#)\b/gi },
|
|
523
|
+
{ profile: 'finance', label: 'Finance & Banking', regex: /\b(?:Wire\s+Transfer\s+Authorization|SWIFT\s*\/?\s*BIC\s*:|IBAN\s*:\s*[A-Z]{2}\d{2}|ABA\s+Routing|ACH\s+Transfer|PCI-DSS|Primary\s+Account\s+Number)\b/gi },
|
|
524
|
+
{ profile: 'hr', label: 'HR & Resumes', regex: /\b(?:Employee\s*ID|Performance\s+Improvement\s+Plan|Payroll\s+Register|Gross\s+Pay\b|Net\s+Pay\b|Candidate\s+Evaluation|Compensation\s+Band|Sozialversicherungsnummer|Personalnummer|EEID\s*:)\b/gi },
|
|
525
|
+
{ profile: 'realestate', label: 'Real Estate', regex: /\b(?:Assessor\s+Parcel\s+Number|APN\s*:|MLS\s*#|Closing\s+Disclosure|Escrow\s+(?:Account|Number|Officer)|Property\s+Deed|Title\s+Insurance|Lease\s+Application)\b/gi },
|
|
526
|
+
{ profile: 'dev', label: 'API & Dev Logs', regex: /\b(?:BEGIN\s+(?:RSA|OPENSSH|EC|PRIVATE)\s+PRIVATE\s+KEY|AWS_SECRET_ACCESS_KEY|DATABASE_URL\s*=|GITHUB_TOKEN\s*=|Bearer\s+eyJ[A-Za-z0-9_-]+)\b/g },
|
|
527
|
+
{ profile: 'sales', label: 'Sales & CRM', regex: /\b(?:CRM\s+(?:Opportunity|Export)|HubSpot\b|Salesforce\b|MEDDPICC\b|Primary\s+Buyer\s*:|MSA\s+Redlines|Deal\s+Stage|Pipeline\s+Forecast|Opportunity\s+ID|Account\s+Executive)\b/gi },
|
|
528
|
+
{ profile: 'engineering', label: 'DevOps & Infra', regex: /\b(?:Incident\s+Postmortem|Kubeconfig|Kubernetes\s+Cluster|Helm\s+Chart|Terraform\s+State|DMAIC\b|Bill\s+of\s+Materials|BOM\s+Spec|CNC\s+Machining|Shop\s+Floor\s+Batch)\b/gi },
|
|
529
|
+
{ profile: 'insurance', label: 'Insurance & Claims', regex: /\b(?:Claim\s+Settlement|Policyholder\s*:|Policy\s*#?POL-|Claim\s+Number|Adjuster\s*:|Loss\s+Location|Loss\s+Run|Subrogation\b|FNOL\b|Deductible\s*:)\b/gi },
|
|
530
|
+
{ profile: 'pharma', label: 'Pharma & Trials', regex: /\b(?:Clinical\s+Trial(?:\s+Protocol)?|NCT\d{8}\b|IRB\s+Protocol|FDA\s+1572|Adverse\s+Event|Pharmacovigilance|Principal\s+Investigator|Cohort\s+[A-Z]\b|Blinded\s+Study|CDISC\b|IND\s*(?:#|Protocol))\b/gi },
|
|
531
|
+
{ profile: 'underwriting', label: 'Loan Underwriting & Income', regex: /\b(?:Loan\s+Underwriting|Mortgage\s+Appraisal|Loan\s+Application\s+#?LOS|FICO\s*:\s*\d{3}|Appraised\s+Value\s*:|80%\s+LTV|Monthly\s+Qualifying\s*:|YTD\s+Earnings|Borrower\s*:)\b/gi },
|
|
532
|
+
{ profile: 'security', label: 'Security & SIEM', regex: /\b(?:SIEM\s+Alert|CVE-\d{4}-\d{4,7}\b|Threat\s*:\s*CRITICAL|Unauthorized\s+S3\s+bucket|SOC\s+Incident|Firewall\s+Rule\s+Violation|Intrusion\s+Detection)\b/gi },
|
|
533
|
+
{ profile: 'support', label: 'Support & Tickets', regex: /\b(?:Support\s+Ticket|Ticket\s*#INC-|Zendesk\b|Intercom\b|Billing\s+Discrepancy|SLA\s+Escalation|CSAT\s+Score|Customer\s+Support\s+Escalation)\b/gi },
|
|
534
|
+
{ profile: 'compliance', label: 'Compliance Audit', regex: /\b(?:Suspicious\s+Activity\s+Report|FinCEN\s+SAR|BSA\s+Officer|31\s+CFR\b|ROPA\s+Register|Data\s+Protection\s+Impact\s+Assessment|SOC\s*2\s+Type\s+II|ISO\s*27001\s+Audit|CMMC\s+Level|ITAR\s+Controlled)\b/gi },
|
|
535
|
+
{ profile: 'ccpa', label: 'CCPA / CPRA Privacy', regex: /\b(?:CCPA\s*\/?\s*CPRA|1798\.105|Right\s+to\s+Delete|Opt-out\s+of\s+Sale|Ticket\s*#?DSAR-)\b/gi },
|
|
536
|
+
{ profile: 'bizops', label: 'Biz Ops & M&A', regex: /\b(?:Vendor\s+Master\s+Agreement|Bill\s+of\s+Lading|Customs\s+Declaration|Purchase\s+Order\s*#?PO-|Supply\s+Chain\s+Manifest)\b/gi },
|
|
537
|
+
{ profile: 'biotech', label: 'Biotech & Genomics', regex: /\b(?:Sequencing\s+Platform|Illumina\s+NovaSeq|Flowcell\s*:|FastQ\s+Sample|ClinVar\b|HGVS\s+Variant|Genomic\s+Sequencing|Bioinformatics\s+Intake|BRCA[12]\s+c\.)\b/gi },
|
|
538
|
+
{ profile: 'automotive', label: 'Automotive & EV', regex: /\b(?:Connected\s+Vehicle\s+Telematics|ECU\s+Serial|Telematics\s+Device|ASIL-D\b|DTC\s+P\d{4}\b|CAN-Bus\s+Log)\b/gi },
|
|
539
|
+
{ profile: 'energy', label: 'Energy & Smart Grid', regex: /\b(?:Critical\s+Infrastructure\s+SCADA|Substation\s+ID|Feeder\s+ID|Smart\s+Meter\s*:|ESI\s+ID\s*:|NERC\s+CIP|BES\s+Cyber\s+Asset)\b/gi },
|
|
540
|
+
{ profile: 'hospitality', label: 'Hospitality & Travel', regex: /\b(?:Airline\s+Passenger\s+Dossier|PNR\s*:\s*[A-Z0-9]{6}|e-Ticket\s*:|Boarding\s+Pass\s*:|Known\s+Traveler\s+KTN|Guest\s+Folio|Marriott\s+Bonvoy|SkyMiles)\b/gi },
|
|
541
|
+
{ profile: 'telecom', label: 'Telecom & Call Center', regex: /\b(?:Telecom\s+Subscriber\s+CDR|MSISDN\s*:|IMSI\s*:\s*\d{14,15}|IMEI\s*:\s*\d{14,16}|Cell\s+Tower\s+ID|SIP\s+Signaling)\b/gi },
|
|
542
|
+
{ profile: 'academic', label: 'Academic & Research', regex: /\b(?:FERPA\s+Student\s+Record|Student\s+ID\s*:\s*#?STU-|Disciplinary\s+Record|IEP\s+Evaluation|IRB\s+Approval)\b/gi },
|
|
543
|
+
{ profile: 'agents', label: 'AI Agents & Prompts', regex: /\b(?:Autonomous\s+Financial\s+Procurement\s+Agent|AgentID\s*:\s*agt_|Encrypted\s+Tool\s+Token|Agent\s+Memory\s*>)\b/gi }
|
|
544
|
+
];
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Automatically detects the most relevant industry compliance profile from text content.
|
|
548
|
+
* Executes in <0.05ms in local RAM with zero network egress.
|
|
549
|
+
*
|
|
550
|
+
* @param {string} text - Input document or prompt text.
|
|
551
|
+
* @returns {{
|
|
552
|
+
* detectedProfile: string,
|
|
553
|
+
* label: string,
|
|
554
|
+
* confidence: 'high'|'medium'|'low',
|
|
555
|
+
* score: number,
|
|
556
|
+
* alternatives: Array<{ profile: string, label: string, score: number }>
|
|
557
|
+
* }}
|
|
558
|
+
*/
|
|
559
|
+
export function detectProfile(text) {
|
|
560
|
+
if (!text || typeof text !== 'string') {
|
|
561
|
+
return { detectedProfile: 'general', label: 'General PII', confidence: 'low', score: 0, alternatives: [] };
|
|
562
|
+
}
|
|
563
|
+
const sampleSlice = text.length > 16384 ? text.slice(0, 16384) : text;
|
|
564
|
+
const matches = [];
|
|
565
|
+
for (let i = 0; i < SDK_VERTICAL_DETECTORS.length; i++) {
|
|
566
|
+
const c = SDK_VERTICAL_DETECTORS[i];
|
|
567
|
+
c.regex.lastIndex = 0;
|
|
568
|
+
const found = sampleSlice.match(c.regex);
|
|
569
|
+
if (found && found.length > 0) {
|
|
570
|
+
matches.push({
|
|
571
|
+
profile: c.profile,
|
|
572
|
+
label: c.label,
|
|
573
|
+
score: found.length,
|
|
574
|
+
priority: i
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
if (matches.length === 0) {
|
|
579
|
+
return { detectedProfile: 'general', label: 'General PII', confidence: 'low', score: 0, alternatives: [] };
|
|
580
|
+
}
|
|
581
|
+
matches.sort((a, b) => (b.score !== a.score) ? (b.score - a.score) : (a.priority - b.priority));
|
|
582
|
+
const primary = matches[0];
|
|
583
|
+
const alternatives = matches.slice(1, 4).map(({ profile, label, score }) => ({ profile, label, score }));
|
|
584
|
+
const confidence = primary.score >= 3 ? 'high' : (primary.score >= 2 ? 'medium' : 'low');
|
|
585
|
+
return {
|
|
586
|
+
detectedProfile: primary.profile,
|
|
587
|
+
label: primary.label,
|
|
588
|
+
confidence,
|
|
589
|
+
score: primary.score,
|
|
590
|
+
alternatives
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
486
594
|
export function sanitize(text, options = {}) {
|
|
487
595
|
if (!text || typeof text !== 'string') {
|
|
488
596
|
return {
|
|
@@ -501,7 +609,7 @@ export function sanitize(text, options = {}) {
|
|
|
501
609
|
}
|
|
502
610
|
|
|
503
611
|
const {
|
|
504
|
-
profile = 'General',
|
|
612
|
+
profile: rawProfileOption = 'General',
|
|
505
613
|
licenseKey = (typeof process !== 'undefined' && (process.env?.PRIVACYSCRUBBER_KEY || process.env?.PRIVACYSCRUBBER_LICENSE_KEY)) || '',
|
|
506
614
|
customRules = [],
|
|
507
615
|
tokenLabelMap = {},
|
|
@@ -513,6 +621,12 @@ export function sanitize(text, options = {}) {
|
|
|
513
621
|
ignoreList = null
|
|
514
622
|
} = options;
|
|
515
623
|
|
|
624
|
+
const isAutoProfile = Boolean(
|
|
625
|
+
(typeof rawProfileOption === 'string' && rawProfileOption.trim().toLowerCase() === 'auto') ||
|
|
626
|
+
options.autoDetectProfile === true
|
|
627
|
+
);
|
|
628
|
+
const autoDetected = isAutoProfile ? detectProfile(text) : null;
|
|
629
|
+
|
|
516
630
|
const licenseCheck = validateLicense(licenseKey);
|
|
517
631
|
const rawTier = licenseCheck.valid ? (licenseCheck.tier || 'PRO') : 'FREE';
|
|
518
632
|
const isExpiredKey = !licenseCheck.valid && typeof licenseCheck.error === 'string' && /expired/i.test(licenseCheck.error);
|
|
@@ -534,6 +648,21 @@ export function sanitize(text, options = {}) {
|
|
|
534
648
|
const isSdkTier = licenseCheck.valid && ['SDK', 'OEM', 'ENTERPRISE'].includes(rawTier);
|
|
535
649
|
const isSeatTier = licenseCheck.valid && ['PRO', 'TEAMS'].includes(rawTier);
|
|
536
650
|
|
|
651
|
+
const isPro = isSdkTier;
|
|
652
|
+
const tier = isPro ? rawTier : (isSeatTier ? rawTier : 'FREE');
|
|
653
|
+
|
|
654
|
+
let autoSuggestedOnly = false;
|
|
655
|
+
let profile = rawProfileOption;
|
|
656
|
+
if (isAutoProfile && autoDetected) {
|
|
657
|
+
if (!isPro && text.length > 5000 && text.length <= 15000 && autoDetected.detectedProfile !== 'general') {
|
|
658
|
+
// Non-blocking PLG fallback: keep General for Free 5k-15k texts so auto-mode never breaks free calls
|
|
659
|
+
profile = 'General';
|
|
660
|
+
autoSuggestedOnly = true;
|
|
661
|
+
} else {
|
|
662
|
+
profile = autoDetected.detectedProfile;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
537
666
|
if (isSeatTier) {
|
|
538
667
|
const keyPreview = licenseKey ? `${licenseKey.slice(0, 12)}...` : '';
|
|
539
668
|
const errorMsg = `[PrivacyScrubber] License tier mismatch: ${rawTier} license (${keyPreview}) is licensed strictly for human seats (Web App & Chrome Extension). Backend automation, microservices, and CRM pipelines require a Developer SDK license ($299/mo). Upgrade: https://privacyscrubber.com/pricing?tier=sdk&src=seat_tier_mismatch`;
|
|
@@ -547,9 +676,6 @@ export function sanitize(text, options = {}) {
|
|
|
547
676
|
}
|
|
548
677
|
}
|
|
549
678
|
|
|
550
|
-
const isPro = isSdkTier;
|
|
551
|
-
const tier = isPro ? rawTier : (isSeatTier ? rawTier : 'FREE');
|
|
552
|
-
|
|
553
679
|
emitCommunityNoticeIfNeeded(isPro);
|
|
554
680
|
|
|
555
681
|
const isSpecialized = profile && profile.toLowerCase() !== 'general';
|
|
@@ -583,8 +709,33 @@ export function sanitize(text, options = {}) {
|
|
|
583
709
|
});
|
|
584
710
|
|
|
585
711
|
// Auto-inject DevOps Secrets rules when in Dev profile or when detectSecrets is requested
|
|
586
|
-
const
|
|
587
|
-
|
|
712
|
+
const isProdEnv = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';
|
|
713
|
+
const hasCustomEnterpriseConfig = isSpecialized || safeCustomRules.length > 0 || (Array.isArray(ignoreList) && ignoreList.length > 0);
|
|
714
|
+
let profileFallback = false;
|
|
715
|
+
let effectiveProfile = profile;
|
|
716
|
+
let effectiveCustomRules = safeCustomRules;
|
|
717
|
+
let effectiveIgnoreList = ignoreList;
|
|
718
|
+
|
|
719
|
+
if (!isPro && isProdEnv && hasCustomEnterpriseConfig) {
|
|
720
|
+
_freeProdSpecializedCalls++;
|
|
721
|
+
if (_freeProdSpecializedCalls > FREE_PROD_SPECIALIZED_CALL_LIMIT) {
|
|
722
|
+
profileFallback = true;
|
|
723
|
+
effectiveProfile = 'General';
|
|
724
|
+
effectiveCustomRules = [];
|
|
725
|
+
effectiveIgnoreList = null;
|
|
726
|
+
if (!_prodProfileFallbackNoticeLogged && typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
|
|
727
|
+
_prodProfileFallbackNoticeLogged = true;
|
|
728
|
+
process.stderr.write(
|
|
729
|
+
`\n[@privacyscrubber/sdk] Free Production Quota (${FREE_PROD_SPECIALIZED_CALL_LIMIT} specialized calls) reached for profile '${profile}'.\n` +
|
|
730
|
+
`[@privacyscrubber/sdk] Gracefully falling back to 'General' profile (Core PII remains protected, 0 downtime).\n` +
|
|
731
|
+
`[@privacyscrubber/sdk] Unlock unlimited specialized profiles, custom rules & ignoreLists in production ($299/mo): https://privacyscrubber.com/pricing?tier=sdk&src=prod_profile_fallback (7-Day Trial: npx @privacyscrubber/sdk trial)\n\n`
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const activeRules = [...effectiveCustomRules];
|
|
738
|
+
if (effectiveProfile.toLowerCase() === 'dev' || detectSecrets === true) {
|
|
588
739
|
DEVOPS_SECRETS_DETECTOR.forEach(rule => {
|
|
589
740
|
activeRules.push({
|
|
590
741
|
name: rule.name,
|
|
@@ -605,10 +756,10 @@ export function sanitize(text, options = {}) {
|
|
|
605
756
|
textToScrub,
|
|
606
757
|
activeRules,
|
|
607
758
|
tokenLabelMap,
|
|
608
|
-
|
|
759
|
+
effectiveProfile,
|
|
609
760
|
existingSessionMap,
|
|
610
761
|
isPro,
|
|
611
|
-
|
|
762
|
+
effectiveIgnoreList
|
|
612
763
|
);
|
|
613
764
|
|
|
614
765
|
const endTime = (typeof performance !== 'undefined' && typeof performance.now === 'function')
|
|
@@ -616,7 +767,7 @@ export function sanitize(text, options = {}) {
|
|
|
616
767
|
: Date.now();
|
|
617
768
|
|
|
618
769
|
const executionMs = Math.round((endTime - startTime) * 100) / 100;
|
|
619
|
-
const telemetry = buildAuditTelemetry(rawResult.tokenMap || {});
|
|
770
|
+
const telemetry = buildAuditTelemetry(rawResult.tokenMap || {}, { licenseTier: tier });
|
|
620
771
|
const auditReceipt = generateReceipt ? formatAuditReceipt(telemetry) : '';
|
|
621
772
|
|
|
622
773
|
emitDevSecretNoticeIfNeeded(isPro, rawResult.tokenMap, limit);
|
|
@@ -644,6 +795,10 @@ export function sanitize(text, options = {}) {
|
|
|
644
795
|
limit: limit,
|
|
645
796
|
wasTruncated: wasTruncated,
|
|
646
797
|
truncated: wasTruncated,
|
|
798
|
+
profileFallback: profileFallback,
|
|
799
|
+
effectiveProfile: effectiveProfile,
|
|
800
|
+
specializedCallsUsed: _freeProdSpecializedCalls,
|
|
801
|
+
specializedCallsLimit: isPro ? Infinity : FREE_PROD_SPECIALIZED_CALL_LIMIT,
|
|
647
802
|
...(isSeatTier && {
|
|
648
803
|
upgradeUrl: `https://privacyscrubber.com/pricing?tier=sdk&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src=seat_tier_mismatch`,
|
|
649
804
|
trialUrl: `https://privacyscrubber.com/pricing?tier=sdk&trial=true&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src=seat_tier_mismatch`,
|
|
@@ -651,12 +806,20 @@ export function sanitize(text, options = {}) {
|
|
|
651
806
|
recommendation: `Your ${rawTier} license is valid for interactive browser seats only. Upgrade to Developer SDK ($299/mo) for unlimited backend server throughput: https://privacyscrubber.com/pricing?tier=sdk`
|
|
652
807
|
}),
|
|
653
808
|
...(!isPro && !isSeatTier && {
|
|
654
|
-
upgradeUrl: `https://privacyscrubber.com/pricing?tier=sdk&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src
|
|
655
|
-
trialUrl: `https://privacyscrubber.com/pricing?tier=sdk&trial=true&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src
|
|
809
|
+
upgradeUrl: `https://privacyscrubber.com/pricing?tier=sdk&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src=${profileFallback ? 'prod_profile_fallback' : 'dev_upsell'}`,
|
|
810
|
+
trialUrl: `https://privacyscrubber.com/pricing?tier=sdk&trial=true&profile=${encodeURIComponent(String(profile || 'General').toLowerCase())}&src=${profileFallback ? 'prod_profile_fallback' : 'dev_upsell'}`,
|
|
656
811
|
trialCommand: 'npx @privacyscrubber/sdk trial',
|
|
657
812
|
recommendation: 'Upgrade to Developer SDK ($299/mo) for unlimited backend text processing, custom regex rules, and specialized compliance profiles.'
|
|
658
813
|
})
|
|
659
814
|
},
|
|
815
|
+
profileDetection: {
|
|
816
|
+
autoDetected: isAutoProfile,
|
|
817
|
+
detectedProfile: autoDetected ? autoDetected.detectedProfile : String(effectiveProfile || 'General').toLowerCase(),
|
|
818
|
+
label: autoDetected ? autoDetected.label : effectiveProfile,
|
|
819
|
+
confidence: autoDetected ? autoDetected.confidence : 'high',
|
|
820
|
+
suggestedOnly: autoSuggestedOnly,
|
|
821
|
+
alternatives: autoDetected ? autoDetected.alternatives : []
|
|
822
|
+
},
|
|
660
823
|
telemetry: telemetry,
|
|
661
824
|
auditReceipt: auditReceipt
|
|
662
825
|
};
|
|
@@ -3888,6 +4051,7 @@ import {
|
|
|
3888
4051
|
|
|
3889
4052
|
export default {
|
|
3890
4053
|
SDK_VERSION,
|
|
4054
|
+
detectProfile,
|
|
3891
4055
|
sanitize,
|
|
3892
4056
|
sanitizeObject,
|
|
3893
4057
|
scrub,
|
|
@@ -3940,6 +4104,8 @@ export default {
|
|
|
3940
4104
|
scrubText,
|
|
3941
4105
|
unscrubText,
|
|
3942
4106
|
DEVOPS_SECRETS_DETECTOR,
|
|
4107
|
+
FREE_PROD_SPECIALIZED_CALL_LIMIT,
|
|
4108
|
+
_resetProdQuotaForTesting,
|
|
3943
4109
|
stripExifMetadata,
|
|
3944
4110
|
redactImageBoundingBoxes,
|
|
3945
4111
|
generateSvgRedactionOverlay
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@privacyscrubber/sdk",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.8",
|
|
4
4
|
"description": "In-process consumer privacy defense and pre-emptive PII interception SDK for Node.js, Next.js, and AI pipelines. Zero data loss, zero third parties, sub-millisecond in-memory execution.",
|
|
5
5
|
"main": "index.cjs",
|
|
6
6
|
"module": "index.js",
|