@privacyscrubber/sdk 2.2.4 → 2.2.6

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.
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @privacyscrubber/sdk - LangChain RAG Ingestion & Synthesis Recipe
3
+ *
4
+ * Demonstrates:
5
+ * 1. Pre-ingestion document transformation with createDocumentTransformer.
6
+ * 2. Neutralizing PII in pageContent and sensitive metadata keys (e.g. author, user_id).
7
+ * 3. Preserving vector embedding semantic fidelity with deterministic tokens.
8
+ * 4. In-memory re-hydration of synthesized LLM answers with zero data leakage.
9
+ *
10
+ * Usage:
11
+ * node npm-sdk/examples/langchain-rag.js
12
+ */
13
+
14
+ import { createDocumentTransformer } from '../index.js';
15
+
16
+ async function main() {
17
+ console.log('=== PrivacyScrubber SDK: LangChain RAG Recipe ===\n');
18
+
19
+ // 1. Initialize the LangChain Document Transformer
20
+ // Zero network egress: operates 100% in local process memory (<1ms per document)
21
+ const transformer = createDocumentTransformer({
22
+ profile: 'General',
23
+ sensitiveMetadataKeys: ['account_owner', 'submitter_email'],
24
+ attachTelemetry: true,
25
+ attachTokenMap: false // Do not leak token mappings into the vector database
26
+ });
27
+
28
+ // 2. Sample raw documents loaded from CRM / internal ticket logs
29
+ const rawDocs = [
30
+ {
31
+ pageContent: 'Account Executive John Doe (john.doe@enterprise.com) finalized deal for client Acme Corp under SSN 000-12-3456.',
32
+ metadata: {
33
+ docId: 'doc_101',
34
+ department: 'Enterprise Sales',
35
+ account_owner: 'john.doe@enterprise.com',
36
+ source: 'Salesforce'
37
+ }
38
+ },
39
+ {
40
+ pageContent: 'Technical escalation for customer Jane Smith. Direct contact phone is +1-555-019-2834, email janes@corp.org.',
41
+ metadata: {
42
+ docId: 'doc_102',
43
+ department: 'Customer Success',
44
+ submitter_email: 'janes@corp.org',
45
+ source: 'Zendesk'
46
+ }
47
+ }
48
+ ];
49
+
50
+ console.log('--- 1. Raw Documents Before Sanitization ---');
51
+ console.log(JSON.stringify(rawDocs, null, 2));
52
+
53
+ // 3. Transform documents before vector embedding / storage
54
+ const sanitizedDocs = await transformer.transformDocuments(rawDocs);
55
+
56
+ console.log('\n--- 2. Sanitized Documents (Safe for Vector DB Ingestion) ---');
57
+ console.log(JSON.stringify(sanitizedDocs, null, 2));
58
+
59
+ // 4. Verify zero cleartext PII exists in the documents to be embedded
60
+ const containsRawEmail = sanitizedDocs.some(d => d.pageContent.includes('john.doe@enterprise.com'));
61
+ const containsRawSsn = sanitizedDocs.some(d => d.pageContent.includes('000-12-3456'));
62
+ console.log(`\nZero Cleartext Email Verified: ${!containsRawEmail}`);
63
+ console.log(`Zero Cleartext SSN Verified: ${!containsRawSsn}`);
64
+
65
+ // 5. Simulate an LLM synthesizing an answer over retrieved tokenized chunks
66
+ // The LLM operates on the tokens without knowing the customer's true identity:
67
+ const mockLlmResponse = 'Based on document [doc_101], [NAME_1] ([EMAIL_1]) successfully closed the deal for Acme Corp. Contract verified under tax ID [ID_1].';
68
+ console.log('\n--- 3. LLM Answer Synthesized over Vector Space ---');
69
+ console.log(`Raw LLM Output: "${mockLlmResponse}"`);
70
+
71
+ // 6. Restore the answer in local memory for the authorized end user
72
+ const { restoredText } = transformer.restore(mockLlmResponse);
73
+ console.log('\n--- 4. Re-hydrated Answer (Local RAM Only) ---');
74
+ console.log(`Final Response: "${restoredText}"`);
75
+
76
+ // 7. Reset session when switching security context / tenant
77
+ transformer.resetSession();
78
+ console.log('\nSession token map purged. Memory footprint clean.');
79
+ }
80
+
81
+ main().catch(console.error);
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @privacyscrubber/sdk - LlamaIndex Node & Pipeline Transformation Recipe
3
+ *
4
+ * Demonstrates:
5
+ * 1. Sanitizing LlamaIndex TextNodes and Documents before VectorStoreIndex insertion.
6
+ * 2. Preserving node IDs, relationships, and structural metadata.
7
+ * 3. Preventing irreversible PII poisoning in vector embedding spaces.
8
+ * 4. Re-hydrating synthesized response text back to original cleartext.
9
+ *
10
+ * Usage:
11
+ * node npm-sdk/examples/llamaindex-rag.js
12
+ */
13
+
14
+ import { createLlamaIndexTransform } from '../index.js';
15
+
16
+ async function main() {
17
+ console.log('=== PrivacyScrubber SDK: LlamaIndex Node Transform Recipe ===\n');
18
+
19
+ // 1. Initialize the LlamaIndex Transform
20
+ // Operates in-memory (<1ms per node) with zero external network dependencies
21
+ const transform = createLlamaIndexTransform({
22
+ profile: 'General',
23
+ detectSecrets: true
24
+ });
25
+
26
+ // 2. Simulated LlamaIndex Nodes / Ingestion Chunks
27
+ const nodes = [
28
+ {
29
+ id_: 'node-001',
30
+ text: 'Patient Alice Brown (phone: 555-839-2001, email: alice.brown@health-secure.org) visited Cardiology Clinic for routine ECG follow-up.',
31
+ metadata: {
32
+ doc_id: 'ehr_84920',
33
+ department: 'Cardiology',
34
+ facility: 'General Hospital'
35
+ }
36
+ },
37
+ {
38
+ id_: 'node-002',
39
+ text: 'Attending physician Dr. Robert House recorded notes: Contact assistant at 555-912-3847 or emergency line doc-house@internal.hospital.',
40
+ metadata: {
41
+ doc_id: 'ehr_84921',
42
+ department: 'Cardiology',
43
+ facility: 'General Hospital'
44
+ }
45
+ }
46
+ ];
47
+
48
+ console.log('--- 1. Raw LlamaIndex Nodes Prior to Index Ingestion ---');
49
+ console.log(JSON.stringify(nodes, null, 2));
50
+
51
+ // 3. Transform nodes through PrivacyScrubber
52
+ const sanitizedNodes = transform.transform(nodes);
53
+
54
+ console.log('\n--- 2. Sanitized Nodes (Vector-Index Ready) ---');
55
+ console.log(JSON.stringify(sanitizedNodes, null, 2));
56
+
57
+ // 4. Invariant checks:
58
+ // - Node IDs remain untouched
59
+ // - All PII replaced with reversible syntax tokens
60
+ // - Metadata flagged with ZTDS security tags
61
+ const containsRawEmail = sanitizedNodes.some(n => n.text.includes('alice.brown@health-secure.org'));
62
+ const preservedIds = sanitizedNodes[0].id_ === 'node-001' && sanitizedNodes[1].id_ === 'node-002';
63
+ console.log(`\nZero Cleartext Email in Embeddings: ${!containsRawEmail}`);
64
+ console.log(`Node IDs & Metadata Intact: ${preservedIds}`);
65
+
66
+ // 5. Query phase: Vector store retrieves tokenized nodes; LLM generates answer
67
+ const mockLlmAnswer = 'The patient [NAME_1] (contact: [EMAIL_1], [PHONE_1]) is under the care of [NAME_2]. For questions, reach out via [EMAIL_2].';
68
+ console.log('\n--- 3. LLM Query Response over Tokenized Index ---');
69
+ console.log(`Raw LLM Synthesis: "${mockLlmAnswer}"`);
70
+
71
+ // 6. Restore original cleartext in local RAM for authorized user
72
+ const { restoredText } = transform.restore(mockLlmAnswer);
73
+ console.log('\n--- 4. Re-hydrated Query Response (Local RAM Only) ---');
74
+ console.log(`De-tokenized Output: "${restoredText}"`);
75
+
76
+ // 7. Reset session map
77
+ transform.resetSession();
78
+ console.log('\nLlamaIndex session map reset complete.');
79
+ }
80
+
81
+ main().catch(console.error);
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @privacyscrubber/sdk - Universal Vector Database Ingestion Guard Recipe
3
+ *
4
+ * Demonstrates:
5
+ * 1. Initializing createVectorIngestionGuard for Chroma, Pinecone, Qdrant, and Weaviate.
6
+ * 2. Columnar batch sanitization for Chroma ({ ids, documents, metadatas }).
7
+ * 3. Record-level sanitization for Pinecone and Qdrant ({ id, text/payload, metadata }).
8
+ * 4. Search query token alignment (query tokens matched to sanitized vector space tokens).
9
+ * 5. Transparent vector store proxy wrapping via wrapVectorStore().
10
+ * 6. Post-retrieval in-memory re-hydration with zero vector store PII retention.
11
+ *
12
+ * Usage:
13
+ * node npm-sdk/examples/vector-guard-rag.js
14
+ */
15
+
16
+ import { createVectorIngestionGuard } from '../index.js';
17
+
18
+ async function main() {
19
+ console.log('=== PrivacyScrubber SDK: Universal Vector DB Ingestion Guard ===\n');
20
+
21
+ // 1. Initialize the Vector Ingestion Guard
22
+ // Operates 100% in-process RAM with zero network egress (<1ms per batch)
23
+ const guard = createVectorIngestionGuard({
24
+ profile: 'General',
25
+ sensitiveMetadataKeys: ['contractor_email', 'billing_contact'],
26
+ attachTelemetry: true
27
+ });
28
+
29
+ // -------------------------------------------------------------------------
30
+ // Scenario A: Chroma Columnar Ingestion ({ ids, documents, metadatas })
31
+ // -------------------------------------------------------------------------
32
+ console.log('--- 1. Chroma Columnar Batch Sanitization ---');
33
+ const chromaBatch = {
34
+ ids: ['doc-101', 'doc-102'],
35
+ documents: [
36
+ 'Vendor agreement with Michael Scott (mscott@dundermifflin.com), SSN 000-44-5555.',
37
+ 'Direct support line for Jim Halpert: +1-555-019-8765, email jhalpert@dundermifflin.com.'
38
+ ],
39
+ metadatas: [
40
+ { branch: 'Scranton', contractor_email: 'temp.auditor@external.org' },
41
+ { branch: 'Scranton', tier: 'Enterprise' }
42
+ ]
43
+ };
44
+
45
+ const cleanChroma = guard.sanitizeRecords(chromaBatch);
46
+ console.log('Sanitized Chroma documents:');
47
+ console.log(cleanChroma.documents);
48
+ console.log('Sanitized Chroma metadatas:');
49
+ console.log(cleanChroma.metadatas);
50
+
51
+ // -------------------------------------------------------------------------
52
+ // Scenario B: Pinecone / Qdrant Record Array Ingestion
53
+ // -------------------------------------------------------------------------
54
+ console.log('\n--- 2. Pinecone & Qdrant Record Sanitization ---');
55
+ const records = [
56
+ {
57
+ id: 'vec-201',
58
+ text: 'Employee record: Pam Beesly (pamb@office.com), personal mobile 555-432-1098.',
59
+ metadata: { role: 'Office Administrator', department: 'Operations' }
60
+ },
61
+ {
62
+ id: 'vec-202',
63
+ payload: {
64
+ text: 'Executive escalation from Dwight Schrute (dschrute@schrutefarms.com).',
65
+ region: 'PA'
66
+ }
67
+ }
68
+ ];
69
+
70
+ const cleanRecords = guard.sanitizeRecords(records);
71
+ console.log('Sanitized Pinecone record:');
72
+ console.log(cleanRecords[0]);
73
+ console.log('Sanitized Qdrant payload:');
74
+ console.log(cleanRecords[1]);
75
+
76
+ // -------------------------------------------------------------------------
77
+ // Scenario C: Search Query Token Alignment
78
+ // When a user searches for an email or SSN that was previously ingested,
79
+ // the query must be mapped to the identical ZTDS token before vector embedding.
80
+ // -------------------------------------------------------------------------
81
+ console.log('\n--- 3. Search Query Token Alignment ---');
82
+ const rawUserQuery = 'Find agreements involving mscott@dundermifflin.com and audit history';
83
+ const alignedQuery = guard.sanitizeQuery(rawUserQuery);
84
+
85
+ console.log('Raw user query: ', rawUserQuery);
86
+ console.log('Aligned query: ', alignedQuery.query);
87
+ console.log('Tokens detected: ', alignedQuery.tokensDetected);
88
+
89
+ // -------------------------------------------------------------------------
90
+ // Scenario D: Transparent Vector Store Proxy Wrapping
91
+ // wrapVectorStore intercepts addDocuments/upsert and similaritySearch/query
92
+ // to sanitize pre-write and re-hydrate post-read automatically.
93
+ // -------------------------------------------------------------------------
94
+ console.log('\n--- 4. Transparent Vector Store Proxy Wrapping ---');
95
+
96
+ // Mock client simulating Chroma / Pinecone / LangChain VectorStore
97
+ const nativeVectorStore = {
98
+ storage: [],
99
+ async addDocuments(docs) {
100
+ this.storage.push(...docs);
101
+ return { count: docs.length };
102
+ },
103
+ async similaritySearch(query) {
104
+ // Emulate cosine similarity retrieval against vector store text
105
+ return this.storage.filter(d => (d.pageContent || d.text || '').includes(query));
106
+ }
107
+ };
108
+
109
+ const guardedStore = guard.wrapVectorStore(nativeVectorStore);
110
+
111
+ // Ingest through transparent guard
112
+ await guardedStore.addDocuments([
113
+ {
114
+ pageContent: 'Restricted memo: Contact CFO David Wallace at dwallace@cfo-network.com regarding Q4 EBITDA.',
115
+ metadata: { classification: 'Confidential' }
116
+ }
117
+ ]);
118
+
119
+ // Verify vector store internal memory contains ZERO plaintext PII
120
+ const rawStored = nativeVectorStore.storage[nativeVectorStore.storage.length - 1];
121
+ console.log('Physical vector store entry (Zero-Trust RAM):');
122
+ console.log(' pageContent:', rawStored.pageContent);
123
+ console.log(' Contains raw email:', rawStored.pageContent.includes('dwallace@cfo-network.com')); // false
124
+
125
+ // Query through transparent guard: query is tokenized, retrieved results are automatically re-hydrated
126
+ const searchResults = await guardedStore.similaritySearch('dwallace@cfo-network.com');
127
+ console.log('\nRetrieved & Re-hydrated Search Result:');
128
+ console.log(' pageContent:', searchResults[0].pageContent);
129
+ console.log(' Contains authentic email:', searchResults[0].pageContent.includes('dwallace@cfo-network.com')); // true
130
+
131
+ console.log('\nUniversal Vector Ingestion Guard recipe completed with 0 bytes network egress.');
132
+ }
133
+
134
+ main().catch(err => {
135
+ console.error('Vector Guard Recipe Error:', err);
136
+ process.exit(1);
137
+ });
package/index.d.ts CHANGED
@@ -136,6 +136,62 @@ export function validateLicenseKey(key: string): 'PRO' | 'TEAMS' | 'SDK' | 'ENTE
136
136
  export function buildAuditTelemetry(currentTokenMap?: Record<string, string> | string[]): AuditTelemetry;
137
137
  export function formatAuditReceipt(telemetry: AuditTelemetry): string;
138
138
 
139
+ export interface AuditEventData {
140
+ timestamp?: string;
141
+ version?: string;
142
+ protocol?: string;
143
+ event?: string;
144
+ riskLevel?: string;
145
+ tokensMasked?: number;
146
+ entities?: Record<string, number>;
147
+ frameworks?: string[];
148
+ sessionHash?: string;
149
+ source?: string;
150
+ action?: string;
151
+ organization?: string;
152
+ department?: string;
153
+ executionMs?: number;
154
+ metadata?: Record<string, any>;
155
+ [key: string]: any;
156
+ }
157
+
158
+ export function formatCefEvent(eventData?: AuditEventData): string;
159
+ export function formatSyslogEvent(eventData?: AuditEventData): string;
160
+ export function formatJsonlEvent(eventData?: AuditEventData): string;
161
+
162
+ export interface AuditLoggerOptions {
163
+ format?: 'jsonl' | 'cef' | 'syslog' | 'json';
164
+ destination?: string | any;
165
+ organization?: string;
166
+ department?: string;
167
+ }
168
+
169
+ export interface AuditLogger {
170
+ formatEvent(eventData: AuditEventData): string;
171
+ logSanitization(result: SanitizeResult | Record<string, string>, context?: any): string;
172
+ logEvent(eventData: AuditEventData): string;
173
+ log(eventData: AuditEventData): string;
174
+ getEntries(): string[];
175
+ getBuffer(): string[];
176
+ clear(): void;
177
+ clearBuffer(): void;
178
+ format: string;
179
+ destination: any;
180
+ }
181
+
182
+ export function createAuditLogger(options?: AuditLoggerOptions): AuditLogger;
183
+
184
+ export interface GenerateAuditReportOptions {
185
+ companyName?: string;
186
+ department?: string;
187
+ format?: 'markdown' | 'json' | 'summary' | 'cef' | 'syslog' | 'jsonl';
188
+ }
189
+
190
+ export function generateAuditReport(
191
+ sessionMap?: Record<string, string>,
192
+ options?: GenerateAuditReportOptions
193
+ ): any;
194
+
139
195
  export interface ProcurementMemoOptions {
140
196
  /** Target application or pipeline name (Default: 'Internal AI Applications & LLM Pipelines'). */
141
197
  appName?: string;
@@ -202,6 +258,69 @@ export function createLangChainTransform(options?: SanitizeOptions): {
202
258
  postprocess: (output: string, tokenMap: Record<string, string>) => RestoreResult;
203
259
  };
204
260
 
261
+ export interface LangChainDocument {
262
+ pageContent: string;
263
+ metadata?: Record<string, any>;
264
+ [key: string]: any;
265
+ }
266
+
267
+ export interface DocumentTransformerOptions extends SanitizeOptions {
268
+ sensitiveMetadataKeys?: string[];
269
+ attachTelemetry?: boolean;
270
+ attachTokenMap?: boolean;
271
+ }
272
+
273
+ export interface DocumentTransformer {
274
+ transformDocuments(documents: LangChainDocument[]): Promise<LangChainDocument[]>;
275
+ invoke(documents: LangChainDocument[]): Promise<LangChainDocument[]>;
276
+ sessionMap: Record<string, string>;
277
+ restore(output: string, tokenMap?: Record<string, string>): RestoreResult;
278
+ resetSession(): void;
279
+ }
280
+
281
+ export function createDocumentTransformer(options?: DocumentTransformerOptions): DocumentTransformer;
282
+ export const createLangChainDocumentTransformer: typeof createDocumentTransformer;
283
+
284
+ export interface LlamaIndexNode {
285
+ text?: string;
286
+ pageContent?: string;
287
+ getContent?: () => string;
288
+ setContent?: (text: string) => void;
289
+ metadata?: Record<string, any>;
290
+ [key: string]: any;
291
+ }
292
+
293
+ export interface LlamaIndexTransform {
294
+ transform<T extends LlamaIndexNode | LlamaIndexNode[]>(nodes: T): T;
295
+ sessionMap: Record<string, string>;
296
+ restore(text: string, map?: Record<string, string>): RestoreResult;
297
+ resetSession(): void;
298
+ }
299
+
300
+ export function createLlamaIndexTransform(options?: SanitizeOptions): LlamaIndexTransform;
301
+
302
+ export interface VectorIngestionGuardOptions extends SanitizeOptions {
303
+ sensitiveMetadataKeys?: string[];
304
+ autoRestoreResults?: boolean;
305
+ }
306
+
307
+ export interface VectorIngestionGuard {
308
+ sanitizeRecords<T = any>(records: T): T;
309
+ sanitizeQuery(query: string): {
310
+ query: string;
311
+ rawQuery: string;
312
+ tokensDetected: number;
313
+ tokenMap: Record<string, string>;
314
+ };
315
+ restoreSearchResults<T = any>(results: T, customTokenMap?: Record<string, string> | null): T;
316
+ wrapVectorStore<T = any>(vectorStore: T): T;
317
+ sessionMap: Record<string, string>;
318
+ restore(text: string, map?: Record<string, string>): RestoreResult;
319
+ resetSession(): void;
320
+ }
321
+
322
+ export function createVectorIngestionGuard(options?: VectorIngestionGuardOptions): VectorIngestionGuard;
323
+
205
324
  export interface ApplyPatchOptions {
206
325
  tokenMap?: Record<string, string>;
207
326
  engine?: PrivacyScrubberEngine;
@@ -444,6 +563,10 @@ declare const defaultExport: {
444
563
  PrivacyScrubberLicenseError: typeof PrivacyScrubberLicenseError;
445
564
  wrapOpenAI: typeof wrapOpenAI;
446
565
  createLangChainTransform: typeof createLangChainTransform;
566
+ createDocumentTransformer: typeof createDocumentTransformer;
567
+ createLangChainDocumentTransformer: typeof createLangChainDocumentTransformer;
568
+ createLlamaIndexTransform: typeof createLlamaIndexTransform;
569
+ createVectorIngestionGuard: typeof createVectorIngestionGuard;
447
570
  createSanitizeStream: typeof createSanitizeStream;
448
571
  applyPatch: typeof applyPatch;
449
572
  restoreToFile: typeof restoreToFile;