secure-redact 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.
@@ -0,0 +1,139 @@
1
+ function d(t) {
2
+ for (let e = 0; e < t.length; e += 4) {
3
+ const r = Math.round(
4
+ 0.299 * t[e] + // R
5
+ 0.587 * t[e + 1] + // G
6
+ 0.114 * t[e + 2]
7
+ // B
8
+ );
9
+ t[e] = r, t[e + 1] = r, t[e + 2] = r;
10
+ }
11
+ }
12
+ function y(t) {
13
+ let e = 255, r = 0;
14
+ for (let s = 0; s < t.length; s += 4) {
15
+ const o = t[s];
16
+ o < e && (e = o), o > r && (r = o);
17
+ }
18
+ const n = r - e;
19
+ if (n !== 0)
20
+ for (let s = 0; s < t.length; s += 4) {
21
+ const o = Math.round((t[s] - e) / n * 255);
22
+ t[s] = o, t[s + 1] = o, t[s + 2] = o;
23
+ }
24
+ }
25
+ function R(t) {
26
+ const e = new Array(256).fill(0), r = t.length / 4;
27
+ for (let i = 0; i < t.length; i += 4)
28
+ e[t[i]]++;
29
+ let n = 0;
30
+ for (let i = 0; i < 256; i++)
31
+ n += i * e[i];
32
+ let s = 0, o = 0, l = 0, f = 0;
33
+ for (let i = 0; i < 256; i++) {
34
+ if (o += e[i], o === 0) continue;
35
+ const a = r - o;
36
+ if (a === 0) break;
37
+ s += i * e[i];
38
+ const g = s / o, u = (n - s) / a, p = o * a * (g - u) * (g - u);
39
+ p > l && (l = p, f = i);
40
+ }
41
+ return f;
42
+ }
43
+ function w(t, e) {
44
+ for (let r = 0; r < t.length; r += 4) {
45
+ const n = t[r] >= e ? 255 : 0;
46
+ t[r] = n, t[r + 1] = n, t[r + 2] = n;
47
+ }
48
+ }
49
+ function O(t, e, r) {
50
+ let n = 0;
51
+ const s = e * r;
52
+ for (let l = 0; l < t.length; l += 4)
53
+ (t[l] + t[l + 1] + t[l + 2]) / 3 < 240 && n++;
54
+ const o = n / s;
55
+ return o < 0.2 ? 11 : o > 0.5 ? 6 : o > 0.3 ? 4 : 3;
56
+ }
57
+ async function k(t) {
58
+ try {
59
+ const e = await createImageBitmap(t), r = new OffscreenCanvas(e.width, e.height), n = r.getContext("2d", { willReadFrequently: !0 });
60
+ if (!n)
61
+ return e.close(), { blob: t, psm: 3 };
62
+ n.drawImage(e, 0, 0);
63
+ const s = n.getImageData(0, 0, e.width, e.height), o = s.data;
64
+ d(o), y(o);
65
+ const l = O(o, e.width, e.height), f = R(o);
66
+ w(o, f), n.putImageData(s, 0, 0);
67
+ const i = await r.convertToBlob({ type: "image/png" });
68
+ return e.close(), { blob: i, psm: l };
69
+ } catch (e) {
70
+ return console.warn("[OCR Worker] Preprocessing failed, using original image:", e), { blob: t, psm: 3 };
71
+ }
72
+ }
73
+ let h = null;
74
+ async function C() {
75
+ return h || (h = await (await import("./index-C62fEJ4q.js").then(function(e) {
76
+ return e.i;
77
+ })).createWorker("eng", void 0, {
78
+ logger: (e) => {
79
+ self.postMessage({
80
+ type: "OCR_PROGRESS",
81
+ progress: e.progress,
82
+ message: e.status
83
+ });
84
+ }
85
+ }), h);
86
+ }
87
+ self.onmessage = async (t) => {
88
+ const { type: e, fileBuffer: r, fileType: n, pageIndex: s } = t.data;
89
+ if (e === "OCR_START")
90
+ try {
91
+ const o = await C();
92
+ let l;
93
+ n === "application/pdf" ? l = new Blob([r], { type: "image/png" }) : l = new Blob([r], { type: n }), self.postMessage({
94
+ type: "OCR_PROGRESS",
95
+ progress: 0.1,
96
+ message: "Preprocessing image..."
97
+ });
98
+ const { blob: f, psm: i } = await k(l);
99
+ console.log(`[OCR Worker] Detected optimal PSM: ${i}`), await o.setParameters({
100
+ tessedit_pageseg_mode: i.toString()
101
+ });
102
+ const a = await o.recognize(f, {}, { text: !0, blocks: !0 }), g = [], u = (c) => {
103
+ !c || !c.text || !c.bbox || g.push({
104
+ text: c.text,
105
+ confidence: (c.confidence ?? 0) / 100,
106
+ bbox: {
107
+ x: c.bbox.x0,
108
+ y: c.bbox.y0,
109
+ w: c.bbox.x1 - c.bbox.x0,
110
+ h: c.bbox.y1 - c.bbox.y0,
111
+ pageIndex: s ?? 0
112
+ }
113
+ });
114
+ };
115
+ if (a.data.blocks && a.data.blocks.length > 0)
116
+ for (const c of a.data.blocks)
117
+ for (const m of c.paragraphs ?? [])
118
+ for (const x of m.lines ?? [])
119
+ for (const b of x.words ?? [])
120
+ u(b);
121
+ else if (a.data.words && a.data.words.length > 0)
122
+ for (const c of a.data.words)
123
+ u(c);
124
+ console.log(`[OCR Worker] Extracted ${g.length} words from Tesseract`);
125
+ let p = a.data.text ?? "";
126
+ !p.trim() && g.length > 0 && (p = g.map((c) => c.text).join(" "), console.log("[OCR Worker] Reconstructed fullText from words")), console.log(`[OCR Worker] fullText length: ${p.length}`), self.postMessage({
127
+ type: "OCR_RESULT",
128
+ words: g,
129
+ fullText: p,
130
+ pageIndex: s ?? 0
131
+ });
132
+ } catch (o) {
133
+ self.postMessage({
134
+ type: "OCR_ERROR",
135
+ error: o instanceof Error ? o.message : "OCR processing failed"
136
+ });
137
+ }
138
+ };
139
+ //# sourceMappingURL=ocr.worker-D5s6dY7M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocr.worker-D5s6dY7M.js","sources":["../src/workers/ocr.worker.ts"],"sourcesContent":["// ─── Worker Message Types (self-contained for worker scope) ─────────────────\r\n\r\ninterface BBox {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n pageIndex: number;\r\n}\r\n\r\ninterface OCRWordResult {\r\n text: string;\r\n confidence: number;\r\n bbox: BBox;\r\n}\r\n\r\n// ─── Image Preprocessing (Worker-optimized) ─────────────────────────────────\r\n\r\n/**\r\n * Grayscale conversion using luminance formula\r\n */\r\nfunction grayscale(data: Uint8ClampedArray): void {\r\n for (let i = 0; i < data.length; i += 4) {\r\n const gray = Math.round(\r\n 0.299 * data[i] + // R\r\n 0.587 * data[i + 1] + // G\r\n 0.114 * data[i + 2] // B\r\n );\r\n data[i] = gray;\r\n data[i + 1] = gray;\r\n data[i + 2] = gray;\r\n }\r\n}\r\n\r\n/**\r\n * Histogram stretching for contrast enhancement\r\n */\r\nfunction enhanceContrast(data: Uint8ClampedArray): void {\r\n let min = 255;\r\n let max = 0;\r\n\r\n for (let i = 0; i < data.length; i += 4) {\r\n const gray = data[i];\r\n if (gray < min) min = gray;\r\n if (gray > max) max = gray;\r\n }\r\n\r\n const range = max - min;\r\n if (range === 0) return;\r\n\r\n for (let i = 0; i < data.length; i += 4) {\r\n const stretched = Math.round(((data[i] - min) / range) * 255);\r\n data[i] = stretched;\r\n data[i + 1] = stretched;\r\n data[i + 2] = stretched;\r\n }\r\n}\r\n\r\n/**\r\n * Otsu's method for automatic thresholding\r\n */\r\nfunction calculateOtsuThreshold(data: Uint8ClampedArray): number {\r\n const histogram = new Array(256).fill(0);\r\n const pixels = data.length / 4;\r\n\r\n for (let i = 0; i < data.length; i += 4) {\r\n histogram[data[i]]++;\r\n }\r\n\r\n let sum = 0;\r\n for (let i = 0; i < 256; i++) {\r\n sum += i * histogram[i];\r\n }\r\n\r\n let sumB = 0;\r\n let weightB = 0;\r\n let maxVariance = 0;\r\n let threshold = 0;\r\n\r\n for (let t = 0; t < 256; t++) {\r\n weightB += histogram[t];\r\n if (weightB === 0) continue;\r\n\r\n const weightF = pixels - weightB;\r\n if (weightF === 0) break;\r\n\r\n sumB += t * histogram[t];\r\n\r\n const meanB = sumB / weightB;\r\n const meanF = (sum - sumB) / weightF;\r\n\r\n const variance = weightB * weightF * (meanB - meanF) * (meanB - meanF);\r\n\r\n if (variance > maxVariance) {\r\n maxVariance = variance;\r\n threshold = t;\r\n }\r\n }\r\n\r\n return threshold;\r\n}\r\n\r\n/**\r\n * Binarization\r\n */\r\nfunction binarize(data: Uint8ClampedArray, threshold: number): void {\r\n for (let i = 0; i < data.length; i += 4) {\r\n const binary = data[i] >= threshold ? 255 : 0;\r\n data[i] = binary;\r\n data[i + 1] = binary;\r\n data[i + 2] = binary;\r\n }\r\n}\r\n\r\n/**\r\n * Detects optimal PSM based on text density\r\n */\r\nfunction detectLayoutPSM(data: Uint8ClampedArray, width: number, height: number): number {\r\n let nonWhitePixels = 0;\r\n const totalPixels = width * height;\r\n\r\n for (let i = 0; i < data.length; i += 4) {\r\n const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;\r\n if (brightness < 240) nonWhitePixels++;\r\n }\r\n\r\n const density = nonWhitePixels / totalPixels;\r\n\r\n if (density < 0.20) return 11; // Sparse (forms/invoices)\r\n if (density > 0.50) return 6; // Dense text blocks\r\n if (density > 0.30) return 4; // Single column\r\n return 3; // Default auto\r\n}\r\n\r\n/**\r\n * Preprocesses image blob for better OCR accuracy\r\n * Uses createImageBitmap (worker-compatible, no DOM required)\r\n */\r\nasync function preprocessImage(blob: Blob): Promise<{ blob: Blob; psm: number }> {\r\n try {\r\n // createImageBitmap is available in workers (no DOM needed)\r\n const imageBitmap = await createImageBitmap(blob);\r\n \r\n const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);\r\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\r\n\r\n if (!ctx) {\r\n imageBitmap.close();\r\n return { blob, psm: 3 }; // Return original if context fails\r\n }\r\n\r\n ctx.drawImage(imageBitmap, 0, 0);\r\n const imageData = ctx.getImageData(0, 0, imageBitmap.width, imageBitmap.height);\r\n const data = imageData.data;\r\n\r\n // Preprocessing pipeline\r\n grayscale(data);\r\n enhanceContrast(data);\r\n\r\n // Detect PSM before binarization\r\n const psm = detectLayoutPSM(data, imageBitmap.width, imageBitmap.height);\r\n\r\n const threshold = calculateOtsuThreshold(data);\r\n binarize(data, threshold);\r\n\r\n ctx.putImageData(imageData, 0, 0);\r\n\r\n // Convert canvas to blob\r\n const processedBlob = await canvas.convertToBlob({ type: 'image/png' });\r\n \r\n // Clean up\r\n imageBitmap.close();\r\n\r\n return { blob: processedBlob, psm };\r\n \r\n } catch (err) {\r\n console.warn('[OCR Worker] Preprocessing failed, using original image:', err);\r\n return { blob, psm: 3 }; // Fallback to original\r\n }\r\n}\r\n\r\n// ─── Tesseract Worker ────────────────────────────────────────────────────────\r\n\r\nlet tesseractWorker: import('tesseract.js').Worker | null = null;\r\n\r\nasync function initTesseract(): Promise<import('tesseract.js').Worker> {\r\n if (tesseractWorker) return tesseractWorker;\r\n const Tesseract = await import('tesseract.js');\r\n tesseractWorker = await Tesseract.createWorker('eng', undefined, {\r\n logger: (m: { status: string; progress: number }) => {\r\n self.postMessage({\r\n type: 'OCR_PROGRESS',\r\n progress: m.progress,\r\n message: m.status,\r\n });\r\n },\r\n });\r\n return tesseractWorker;\r\n}\r\n\r\nself.onmessage = async (e: MessageEvent) => {\r\n const { type, fileBuffer, fileType, pageIndex } = e.data;\r\n\r\n if (type !== 'OCR_START') return;\r\n\r\n try {\r\n const worker = await initTesseract();\r\n\r\n let imageSource: Blob;\r\n if (fileType === 'application/pdf') {\r\n // For PDF, we receive an already-rendered image buffer\r\n imageSource = new Blob([fileBuffer], { type: 'image/png' });\r\n } else {\r\n imageSource = new Blob([fileBuffer], { type: fileType });\r\n }\r\n\r\n // Preprocess image for better OCR accuracy\r\n self.postMessage({\r\n type: 'OCR_PROGRESS',\r\n progress: 0.1,\r\n message: 'Preprocessing image...',\r\n });\r\n\r\n const { blob: processedBlob, psm } = await preprocessImage(imageSource);\r\n\r\n console.log(`[OCR Worker] Detected optimal PSM: ${psm}`);\r\n\r\n // Configure Tesseract with dynamic PSM\r\n await worker.setParameters({\r\n tessedit_pageseg_mode: psm.toString(),\r\n });\r\n\r\n const result = await worker.recognize(processedBlob, {}, { text: true, blocks: true });\r\n const words: OCRWordResult[] = [];\r\n\r\n // Tesseract.js v7 nests words in blocks → paragraphs → lines → words.\r\n // blocks are only populated when { blocks: true } is passed to recognize().\r\n const extractWord = (w: any) => {\r\n if (!w || !w.text || !w.bbox) return;\r\n words.push({\r\n text: w.text,\r\n confidence: (w.confidence ?? 0) / 100,\r\n bbox: {\r\n x: w.bbox.x0,\r\n y: w.bbox.y0,\r\n w: w.bbox.x1 - w.bbox.x0,\r\n h: w.bbox.y1 - w.bbox.y0,\r\n pageIndex: pageIndex ?? 0,\r\n },\r\n });\r\n };\r\n\r\n if (result.data.blocks && result.data.blocks.length > 0) {\r\n for (const block of result.data.blocks) {\r\n for (const paragraph of (block.paragraphs ?? [])) {\r\n for (const line of (paragraph.lines ?? [])) {\r\n for (const word of (line.words ?? [])) {\r\n extractWord(word);\r\n }\r\n }\r\n }\r\n }\r\n } else if ((result.data as any).words && (result.data as any).words.length > 0) {\r\n // Legacy v4 fallback\r\n for (const word of (result.data as any).words) {\r\n extractWord(word);\r\n }\r\n }\r\n\r\n console.log(`[OCR Worker] Extracted ${words.length} words from Tesseract`);\r\n\r\n // Use Tesseract's text if available, otherwise reconstruct from words\r\n let fullText = result.data.text ?? '';\r\n if (!fullText.trim() && words.length > 0) {\r\n fullText = words.map(w => w.text).join(' ');\r\n console.log('[OCR Worker] Reconstructed fullText from words');\r\n }\r\n console.log(`[OCR Worker] fullText length: ${fullText.length}`);\r\n\r\n self.postMessage({\r\n type: 'OCR_RESULT',\r\n words,\r\n fullText,\r\n pageIndex: pageIndex ?? 0,\r\n });\r\n } catch (error) {\r\n self.postMessage({\r\n type: 'OCR_ERROR',\r\n error: error instanceof Error ? error.message : 'OCR processing failed',\r\n });\r\n }\r\n};\r\n"],"names":["grayscale","data","i","gray","enhanceContrast","min","max","range","stretched","calculateOtsuThreshold","histogram","pixels","sum","sumB","weightB","maxVariance","threshold","t","weightF","meanB","meanF","variance","binarize","binary","detectLayoutPSM","width","height","nonWhitePixels","totalPixels","density","preprocessImage","blob","imageBitmap","canvas","ctx","imageData","psm","processedBlob","err","tesseractWorker","initTesseract","n","m","e","type","fileBuffer","fileType","pageIndex","worker","imageSource","result","words","extractWord","w","block","paragraph","line","word","fullText","error"],"mappings":"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"}
package/dist/lib.d.ts ADDED
@@ -0,0 +1,158 @@
1
+ import { default as default_2 } from 'react';
2
+
3
+ export declare interface BoundingBox {
4
+ x: number;
5
+ y: number;
6
+ w: number;
7
+ h: number;
8
+ pageIndex: number;
9
+ }
10
+
11
+ export declare interface DetectedEntity {
12
+ id: string;
13
+ type: PIIType;
14
+ value: string;
15
+ confidence: number;
16
+ bbox: BoundingBox;
17
+ masked: boolean;
18
+ layer: 0 | 1 | 2 | 3 | 4;
19
+ }
20
+
21
+ export declare interface DocField {
22
+ id: string;
23
+ label: string;
24
+ description: string;
25
+ }
26
+
27
+ export declare interface DocTypeConfig {
28
+ id: string;
29
+ label: string;
30
+ icon: string;
31
+ fields: DocField[];
32
+ }
33
+
34
+ export declare const DocTypeSelector: default_2.FC<DocTypeSelectorProps>;
35
+
36
+ declare interface DocTypeSelectorProps {
37
+ selectedDocType: string | null;
38
+ selectedFields: string[];
39
+ onDocTypeChange: (docTypeId: string) => void;
40
+ onFieldsChange: (fields: string[]) => void;
41
+ }
42
+
43
+ export declare const DOCUMENT_TYPES: DocTypeConfig[];
44
+
45
+ export declare interface EvidenceLog {
46
+ timestamp: string;
47
+ fileName: string;
48
+ detectedEntities: Array<{
49
+ type: PIIType;
50
+ confidence: number;
51
+ action: 'masked' | 'kept_visible';
52
+ userConfirmed: boolean;
53
+ }>;
54
+ requiredFields: string[];
55
+ }
56
+
57
+ export declare type PIIType = 'AADHAAR' | 'PAN' | 'CREDIT_CARD' | 'PHONE' | 'NAME' | 'ADDRESS' | 'MEDICAL' | 'EMAIL' | 'DOB' | 'ACCOUNT_NUMBER' | 'IFSC' | 'INVOICE_NO' | 'GST' | 'SENSITIVE';
58
+
59
+ export declare type ProcessingStage = 'idle' | 'loading' | 'ocr' | 'detection' | 'review' | 'redacting' | 'complete' | 'error';
60
+
61
+ export declare interface ProcessingState {
62
+ stage: ProcessingStage;
63
+ progress: number;
64
+ message: string;
65
+ }
66
+
67
+ /**
68
+ * SecureRedact — Drop-in React component for client-side PII detection & redaction.
69
+ *
70
+ * Upload a document (image or PDF), automatically detect sensitive information
71
+ * using OCR + regex + NLP + Gemini AI, review detections, and download a
72
+ * redacted version — all without sending the original document to any server.
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * import { SecureRedact } from 'secure-redact';
77
+ * import 'secure-redact/style.css';
78
+ *
79
+ * function App() {
80
+ * return (
81
+ * <SecureRedact
82
+ * apiKey="your-gemini-api-key"
83
+ * requiredFields={['NAME', 'DOB']}
84
+ * onComplete={(maskedFile, evidence) => {
85
+ * console.log('Redacted:', maskedFile.name);
86
+ * console.log('Evidence:', evidence);
87
+ * }}
88
+ * />
89
+ * );
90
+ * }
91
+ * ```
92
+ */
93
+ export declare const SecureRedact: default_2.FC<SecureRedactProps>;
94
+
95
+ export declare interface SecureRedactProps {
96
+ /**
97
+ * Gemini API key for AI-powered PII detection.
98
+ * Get one at https://aistudio.google.com/apikey
99
+ */
100
+ apiKey: string;
101
+ /**
102
+ * Array of PII field types that the developer wants to KEEP VISIBLE.
103
+ * Everything else detected as PII will be redacted.
104
+ *
105
+ * Valid types: 'NAME' | 'PHONE' | 'EMAIL' | 'ADDRESS' | 'AADHAAR' | 'PAN' |
106
+ * 'CREDIT_CARD' | 'DOB' | 'MEDICAL' | 'ACCOUNT_NUMBER' | 'IFSC' |
107
+ * 'INVOICE_NO' | 'GST'
108
+ *
109
+ * @example ['NAME', 'DOB'] — keeps only name and date of birth visible
110
+ */
111
+ requiredFields?: string[];
112
+ /**
113
+ * Called when redaction is complete.
114
+ * @param maskedFile - The redacted document as a File object (ready to upload/download)
115
+ * @param evidence - Audit trail of what was detected and what actions were taken
116
+ */
117
+ onComplete: (maskedFile: File, evidence: EvidenceLog) => void;
118
+ /**
119
+ * Minimum confidence threshold (0-1) for PII detection.
120
+ * Lower values catch more entities but may have false positives.
121
+ * @default 0.5
122
+ */
123
+ confidenceThreshold?: number;
124
+ /**
125
+ * Maximum uploaded file size in MB.
126
+ * @default 25
127
+ */
128
+ maxFileSizeMB?: number;
129
+ /**
130
+ * Accepted MIME types for file upload.
131
+ * @default ['image/png', 'image/jpeg', 'image/webp', 'image/bmp', 'application/pdf']
132
+ */
133
+ acceptedTypes?: string[];
134
+ /**
135
+ * Whether to show the document type selector UI.
136
+ * When true, users can pick a document type and select which fields to keep.
137
+ * When false, only the uploader is shown and `requiredFields` prop is used directly.
138
+ * @default false
139
+ */
140
+ showDocTypeSelector?: boolean;
141
+ /**
142
+ * Custom CSS class name for the root container.
143
+ */
144
+ className?: string;
145
+ }
146
+
147
+ export declare const SecureUploader: default_2.FC<SecureUploaderProps>;
148
+
149
+ export declare interface SecureUploaderProps {
150
+ requiredFields: string[];
151
+ confidenceThreshold?: number;
152
+ onUpload: (maskedFile: File, evidenceBlob: string) => void;
153
+ maxFileSizeMB?: number;
154
+ acceptedTypes?: string[];
155
+ apiKey?: string;
156
+ }
157
+
158
+ export { }