@stll/anonymize-pdf 2.9.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/index.d.mts +9 -2
- package/dist/index.mjs +26 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -51,7 +51,8 @@ appropriate for untrusted files.
|
|
|
51
51
|
`anonymizePdfRaster` accepts pages produced by an explicit renderer/OCR
|
|
52
52
|
provider and creates a brand-new image-only PDF. It requires a prepared stella
|
|
53
53
|
pipeline, runs native detection over each page's observed text, merges an
|
|
54
|
-
optional digest-bound `ExternalDetectionBatch`,
|
|
54
|
+
optional digest-bound `ExternalDetectionBatch`, applies optional user-reviewed
|
|
55
|
+
`manualRegions` expressed in displayed-page PDF points, and fails if any selected
|
|
55
56
|
non-whitespace UTF-16 span is not completely mapped to observed glyph geometry.
|
|
56
57
|
Provider metadata must identify one explicit OCR language pack; mixed or
|
|
57
58
|
implicit language selection is not part of the contract.
|
|
@@ -60,6 +61,8 @@ binds the source and each page, requires complete rendering and OCR assertions,
|
|
|
60
61
|
destructively fills the mapped pixels, and verifies both the newly written PDF
|
|
61
62
|
graph and its decompressed image pixels. Encrypted inputs are rejected.
|
|
62
63
|
|
|
64
|
+
Manual regions are validated against the observed page and mapped outward to
|
|
65
|
+
pixels before filling, so partially covered edge pixels cannot retain content.
|
|
63
66
|
The output never reuses source PDF objects, streams, text layers, metadata,
|
|
64
67
|
forms, annotations, attachments, actions, signatures, optional content, or
|
|
65
68
|
incremental revisions. A solid rectangle in this output is destructive: the
|
|
@@ -104,6 +107,11 @@ document-profile capability; PDF inspection remains available through the
|
|
|
104
107
|
byte-oriented core runtimes. The Poppler/Tesseract adapter is separately named
|
|
105
108
|
as the Node-only `document.pdf.observe-raster-local` capability.
|
|
106
109
|
|
|
110
|
+
Raster certificates use `PDF_RASTER_CERTIFICATE_CONTRACT_VERSION` (2), including
|
|
111
|
+
the required `manualRegionCount` field. The decoder rejects version 1 certificates;
|
|
112
|
+
consumers storing certificates must dispatch by their version. Raster requests
|
|
113
|
+
(`PDF_RASTER_CONTRACT_VERSION`) and inspections remain at version 1.
|
|
114
|
+
|
|
107
115
|
`rewritePdfRasterFromDetections` is the advanced rewrite-only seam for trusted
|
|
108
116
|
adapters that already ran detection. Detection spans must be strictly ordered
|
|
109
117
|
and non-overlapping. Its name and certificate deliberately do not imply
|
package/dist/index.d.mts
CHANGED
|
@@ -84,6 +84,8 @@ type PdfRasterPage = {
|
|
|
84
84
|
pixelSha256: string;
|
|
85
85
|
/** Strictly ordered, non-overlapping UTF-16 spans. */
|
|
86
86
|
detections: readonly PdfRasterDetection[];
|
|
87
|
+
/** User-reviewed regions in normalized displayed-page PDF points. */
|
|
88
|
+
manualRegions?: readonly PdfRect[];
|
|
87
89
|
};
|
|
88
90
|
type PdfRasterDetection = {
|
|
89
91
|
start: number;
|
|
@@ -97,13 +99,15 @@ type PdfRasterRewrite = {
|
|
|
97
99
|
fillRgb: readonly [number, number, number];
|
|
98
100
|
pages: readonly PdfRasterPage[];
|
|
99
101
|
};
|
|
102
|
+
declare const PDF_RASTER_CERTIFICATE_CONTRACT_VERSION: 2;
|
|
100
103
|
type PdfRasterRewriteCertificate = {
|
|
101
|
-
contractVersion:
|
|
104
|
+
contractVersion: typeof PDF_RASTER_CERTIFICATE_CONTRACT_VERSION;
|
|
102
105
|
pageCount: number;
|
|
103
106
|
sourceSha256: string;
|
|
104
107
|
outputSha256: string;
|
|
105
108
|
provider: PdfRasterProvider;
|
|
106
109
|
detectionCount: number;
|
|
110
|
+
manualRegionCount: number;
|
|
107
111
|
mappedRegionCount: number;
|
|
108
112
|
structurePixelRewriteVerified: true;
|
|
109
113
|
providerAssertedCoverage: "complete-rendering-and-ocr-observation";
|
|
@@ -171,6 +175,7 @@ declare const PDF_INSPECTION_CONTRACT_VERSION: 1;
|
|
|
171
175
|
declare const PDF_RASTER_CONTRACT_VERSION: 1;
|
|
172
176
|
declare const PDF_RASTER_MAX_PAGE_BYTES: number;
|
|
173
177
|
declare const PDF_RASTER_MAX_TOTAL_BYTES: number;
|
|
178
|
+
declare const PDF_RASTER_MAX_MANUAL_REGIONS = 1000000;
|
|
174
179
|
declare const PDF_RASTER_MAX_OUTPUT_BYTES: number;
|
|
175
180
|
declare const PDF_RASTER_REQUEST_JSON_MAX_BYTES: number;
|
|
176
181
|
declare const PDF_DOCUMENT_MAX_BYTES: number;
|
|
@@ -216,6 +221,8 @@ type PdfRasterObservedPageInput = {
|
|
|
216
221
|
pixels: Uint8Array;
|
|
217
222
|
/** Optional digest-bound provider batch merged through stella caller semantics. */
|
|
218
223
|
externalDetectionBatch?: ExternalDetectionBatch | string | undefined;
|
|
224
|
+
/** User-reviewed regions in normalized displayed-page PDF points. */
|
|
225
|
+
manualRegions?: readonly PdfRect[] | undefined;
|
|
219
226
|
};
|
|
220
227
|
type AnonymizePdfRasterOptions = {
|
|
221
228
|
document: Uint8Array;
|
|
@@ -227,5 +234,5 @@ type AnonymizePdfRasterOptions = {
|
|
|
227
234
|
/** Run stella detection, merge optional external detections, then rewrite pixels. */
|
|
228
235
|
declare const anonymizePdfRaster: ({ document, pipeline, provider, pages, fillRgb }: AnonymizePdfRasterOptions) => PdfRasterRewriteResult;
|
|
229
236
|
//#endregion
|
|
230
|
-
export { AnonymizePdfRasterOptions, InspectPdfOptions, type LocalPdfRasterObservation, type LocalPdfRasterPage, PDF_DOCUMENT_MAX_BYTES, PDF_INSPECTION_CONTRACT_VERSION, PDF_INSPECTION_ERROR_CODES, PDF_LOADED_PAYLOAD_MAX_BYTES, PDF_LOCAL_PROVIDER_ERROR_CODES, PDF_MAX_GLYPHS, PDF_MAX_OBJECTS, PDF_MAX_OBJECT_DEPTH, PDF_MAX_OBJECT_NODES, PDF_MAX_OBSERVED_TEXT_UTF8_BYTES, PDF_MAX_PAGES, PDF_MAX_PAGE_TEXT_UTF8_BYTES, PDF_OBSERVATIONS_JSON_MAX_BYTES, PDF_PAGE_DIMENSION_TOLERANCE_POINTS, PDF_RASTER_CONTRACT_VERSION, PDF_RASTER_ERROR_CODES, PDF_RASTER_MAX_OUTPUT_BYTES, PDF_RASTER_MAX_PAGE_BYTES, PDF_RASTER_MAX_TOTAL_BYTES, PDF_RASTER_REQUEST_JSON_MAX_BYTES, PDF_STREAM_DECOMPRESSED_MAX_BYTES, type PdfGlyphObservation, type PdfInspection, PdfInspectionError, type PdfInspectionErrorCode, type PdfInspectionGap, PdfLocalProviderError, type PdfLocalProviderErrorCode, type PdfPageInspection, type PdfPageObservation, type PdfRasterDetection, PdfRasterError, type PdfRasterErrorCode, PdfRasterObservedPageInput, type PdfRasterPage, type PdfRasterProvider, type PdfRasterRewrite, type PdfRasterRewriteCertificate, type PdfRasterRewriteResult, type PdfRect, type PdfRiskInventory, type RenderPdfWithPopplerTesseractOptions, RewritePdfRasterFromDetectionsOptions, anonymizePdfRaster, inspectPdf, renderPdfWithPopplerTesseract, rewritePdfRasterFromDetections };
|
|
237
|
+
export { AnonymizePdfRasterOptions, InspectPdfOptions, type LocalPdfRasterObservation, type LocalPdfRasterPage, PDF_DOCUMENT_MAX_BYTES, PDF_INSPECTION_CONTRACT_VERSION, PDF_INSPECTION_ERROR_CODES, PDF_LOADED_PAYLOAD_MAX_BYTES, PDF_LOCAL_PROVIDER_ERROR_CODES, PDF_MAX_GLYPHS, PDF_MAX_OBJECTS, PDF_MAX_OBJECT_DEPTH, PDF_MAX_OBJECT_NODES, PDF_MAX_OBSERVED_TEXT_UTF8_BYTES, PDF_MAX_PAGES, PDF_MAX_PAGE_TEXT_UTF8_BYTES, PDF_OBSERVATIONS_JSON_MAX_BYTES, PDF_PAGE_DIMENSION_TOLERANCE_POINTS, PDF_RASTER_CERTIFICATE_CONTRACT_VERSION, PDF_RASTER_CONTRACT_VERSION, PDF_RASTER_ERROR_CODES, PDF_RASTER_MAX_MANUAL_REGIONS, PDF_RASTER_MAX_OUTPUT_BYTES, PDF_RASTER_MAX_PAGE_BYTES, PDF_RASTER_MAX_TOTAL_BYTES, PDF_RASTER_REQUEST_JSON_MAX_BYTES, PDF_STREAM_DECOMPRESSED_MAX_BYTES, type PdfGlyphObservation, type PdfInspection, PdfInspectionError, type PdfInspectionErrorCode, type PdfInspectionGap, PdfLocalProviderError, type PdfLocalProviderErrorCode, type PdfPageInspection, type PdfPageObservation, type PdfRasterDetection, PdfRasterError, type PdfRasterErrorCode, PdfRasterObservedPageInput, type PdfRasterPage, type PdfRasterProvider, type PdfRasterRewrite, type PdfRasterRewriteCertificate, type PdfRasterRewriteResult, type PdfRect, type PdfRiskInventory, type RenderPdfWithPopplerTesseractOptions, RewritePdfRasterFromDetectionsOptions, anonymizePdfRaster, inspectPdf, renderPdfWithPopplerTesseract, rewritePdfRasterFromDetections };
|
|
231
238
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { lstat, mkdtemp, readFile, rm, unlink, writeFile } from "node:fs/promise
|
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { join, sep } from "node:path";
|
|
7
7
|
//#region src/types.ts
|
|
8
|
+
const PDF_RASTER_CERTIFICATE_CONTRACT_VERSION = 2;
|
|
8
9
|
const PDF_INSPECTION_ERROR_CODES = {
|
|
9
10
|
documentLimitExceeded: "document-limit-exceeded",
|
|
10
11
|
invalidDocument: "invalid-document",
|
|
@@ -94,6 +95,7 @@ const CERTIFICATE_FIELDS = {
|
|
|
94
95
|
outputSha256: true,
|
|
95
96
|
provider: true,
|
|
96
97
|
detectionCount: true,
|
|
98
|
+
manualRegionCount: true,
|
|
97
99
|
mappedRegionCount: true,
|
|
98
100
|
structurePixelRewriteVerified: true,
|
|
99
101
|
providerAssertedCoverage: true,
|
|
@@ -128,7 +130,7 @@ const isInspectionGap = (value) => typeof value === "string" && Object.hasOwn(IN
|
|
|
128
130
|
const isInspection = (value) => isRecord(value) && hasExactFields(value, INSPECTION_FIELDS) && value["contractVersion"] === 1 && typeof value["pdfVersion"] === "string" && isNonNegativeInteger(value["byteLength"]) && isNonNegativeInteger(value["objectCount"]) && isNonNegativeInteger(value["pageCount"]) && typeof value["encrypted"] === "boolean" && Array.isArray(value["pages"]) && value["pages"].length === value["pageCount"] && value["pages"].every(isPage) && value["pages"].every(({ pageIndex }, index) => pageIndex === index) && isRiskInventory(value["risks"]) && isRecord(value["coverage"]) && hasExactFields(value["coverage"], COVERAGE_FIELDS) && (value["coverage"]["status"] === "full" || value["coverage"]["status"] === "partial") && Array.isArray(value["coverage"]["gaps"]) && value["coverage"]["gaps"].every(isInspectionGap);
|
|
129
131
|
const isProvider = (value) => isRecord(value) && hasExactFields(value, PROVIDER_FIELDS) && typeof value["providerId"] === "string" && typeof value["rendererName"] === "string" && typeof value["rendererVersion"] === "string" && typeof value["ocrName"] === "string" && typeof value["ocrVersion"] === "string" && typeof value["ocrLanguage"] === "string";
|
|
130
132
|
const isSha256 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
|
|
131
|
-
const isCertificate = (value) => isRecord(value) && hasExactFields(value, CERTIFICATE_FIELDS) && value["contractVersion"] ===
|
|
133
|
+
const isCertificate = (value) => isRecord(value) && hasExactFields(value, CERTIFICATE_FIELDS) && value["contractVersion"] === 2 && isNonNegativeInteger(value["pageCount"]) && isSha256(value["sourceSha256"]) && isSha256(value["outputSha256"]) && isProvider(value["provider"]) && isNonNegativeInteger(value["detectionCount"]) && isNonNegativeInteger(value["manualRegionCount"]) && isNonNegativeInteger(value["mappedRegionCount"]) && value["structurePixelRewriteVerified"] === true && value["providerAssertedCoverage"] === "complete-rendering-and-ocr-observation" && value["piiCleanGuaranteed"] === false && typeof value["limitation"] === "string";
|
|
132
134
|
const decodePdfInspection = (json) => {
|
|
133
135
|
const value = JSON.parse(json);
|
|
134
136
|
if (!isInspection(value)) throw new Error("Native PDF inspection does not match contract version 1");
|
|
@@ -136,19 +138,19 @@ const decodePdfInspection = (json) => {
|
|
|
136
138
|
};
|
|
137
139
|
const decodePdfRasterRewriteCertificate = (json) => {
|
|
138
140
|
const value = JSON.parse(json);
|
|
139
|
-
if (!isCertificate(value)) throw new Error(
|
|
141
|
+
if (!isCertificate(value)) throw new Error(`Native PDF raster certificate does not match contract version 2`);
|
|
140
142
|
return value;
|
|
141
143
|
};
|
|
142
144
|
//#endregion
|
|
143
145
|
//#region src/local-provider.ts
|
|
144
146
|
const LOCAL_PROVIDER_ID = "poppler-tesseract-local";
|
|
145
|
-
const PROCESS_OUTPUT_MAX_BYTES =
|
|
146
|
-
const PDF_DOCUMENT_MAX_BYTES$1 =
|
|
147
|
-
const PDF_RASTER_MAX_PAGE_BYTES$1 =
|
|
148
|
-
const PDF_RASTER_MAX_TOTAL_BYTES$1 =
|
|
147
|
+
const PROCESS_OUTPUT_MAX_BYTES = 67108864;
|
|
148
|
+
const PDF_DOCUMENT_MAX_BYTES$1 = 67108864;
|
|
149
|
+
const PDF_RASTER_MAX_PAGE_BYTES$1 = 134217728;
|
|
150
|
+
const PDF_RASTER_MAX_TOTAL_BYTES$1 = 536870912;
|
|
149
151
|
const PDF_MAX_PAGES$1 = 1e4;
|
|
150
152
|
const PDF_MAX_GLYPHS$1 = 5e6;
|
|
151
|
-
const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES$1 =
|
|
153
|
+
const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES$1 = 67108864;
|
|
152
154
|
const DEFAULT_DPI = 300;
|
|
153
155
|
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
154
156
|
const MIN_DPI = 72;
|
|
@@ -462,21 +464,22 @@ const renderPdfWithPopplerTesseract = async (options) => {
|
|
|
462
464
|
//#region src/index.ts
|
|
463
465
|
const PDF_INSPECTION_CONTRACT_VERSION = 1;
|
|
464
466
|
const PDF_RASTER_CONTRACT_VERSION = 1;
|
|
465
|
-
const PDF_RASTER_MAX_PAGE_BYTES =
|
|
466
|
-
const PDF_RASTER_MAX_TOTAL_BYTES =
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
const
|
|
470
|
-
const
|
|
471
|
-
const
|
|
467
|
+
const PDF_RASTER_MAX_PAGE_BYTES = 134217728;
|
|
468
|
+
const PDF_RASTER_MAX_TOTAL_BYTES = 536870912;
|
|
469
|
+
const PDF_RASTER_MAX_MANUAL_REGIONS = 1e6;
|
|
470
|
+
const PDF_RASTER_MAX_OUTPUT_BYTES = 536870912;
|
|
471
|
+
const PDF_RASTER_REQUEST_JSON_MAX_BYTES = 67108864;
|
|
472
|
+
const PDF_DOCUMENT_MAX_BYTES = 67108864;
|
|
473
|
+
const PDF_STREAM_DECOMPRESSED_MAX_BYTES = 33554432;
|
|
474
|
+
const PDF_LOADED_PAYLOAD_MAX_BYTES = 134217728;
|
|
472
475
|
const PDF_MAX_OBJECTS = 2e5;
|
|
473
476
|
const PDF_MAX_OBJECT_NODES = 1e6;
|
|
474
477
|
const PDF_MAX_OBJECT_DEPTH = 128;
|
|
475
478
|
const PDF_MAX_PAGES = 1e4;
|
|
476
479
|
const PDF_MAX_GLYPHS = 5e6;
|
|
477
|
-
const PDF_MAX_PAGE_TEXT_UTF8_BYTES =
|
|
478
|
-
const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES =
|
|
479
|
-
const PDF_OBSERVATIONS_JSON_MAX_BYTES =
|
|
480
|
+
const PDF_MAX_PAGE_TEXT_UTF8_BYTES = 16777216;
|
|
481
|
+
const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES = 67108864;
|
|
482
|
+
const PDF_OBSERVATIONS_JSON_MAX_BYTES = 67108864;
|
|
480
483
|
/** Renderer dimensions may differ by this many points due to numeric rounding. */
|
|
481
484
|
const PDF_PAGE_DIMENSION_TOLERANCE_POINTS = .25;
|
|
482
485
|
var PdfInspectionError = class extends Error {
|
|
@@ -541,6 +544,7 @@ const anonymizePdfRaster = ({ document, pipeline, provider, pages, fillRgb = [
|
|
|
541
544
|
if (pages.length > 1e4) throw new PdfRasterError(PDF_RASTER_ERROR_CODES.limitExceeded, "limit-exceeded: PDF raster page count exceeds its limit");
|
|
542
545
|
let totalPixelBytes = 0;
|
|
543
546
|
let totalObservedTextBytes = 0;
|
|
547
|
+
let totalManualRegions = 0;
|
|
544
548
|
const textEncoder = new TextEncoder();
|
|
545
549
|
for (const page of pages) {
|
|
546
550
|
if (typeof page.observation?.text !== "string") throw new PdfRasterError(PDF_RASTER_ERROR_CODES.invalidContract, "invalid-contract: PDF raster observed text is invalid");
|
|
@@ -554,6 +558,8 @@ const anonymizePdfRaster = ({ document, pipeline, provider, pages, fillRgb = [
|
|
|
554
558
|
if (!Number.isSafeInteger(expected) || expected > 134217728 || page.pixels.byteLength !== expected) throw new PdfRasterError(PDF_RASTER_ERROR_CODES.limitExceeded, "limit-exceeded: PDF raster page pixels exceed limits or have an invalid RGB8 length");
|
|
555
559
|
totalPixelBytes += expected;
|
|
556
560
|
if (!Number.isSafeInteger(totalPixelBytes) || totalPixelBytes > 536870912) throw new PdfRasterError(PDF_RASTER_ERROR_CODES.limitExceeded, "limit-exceeded: PDF raster pixels exceed their aggregate limit");
|
|
561
|
+
totalManualRegions += page.manualRegions?.length ?? 0;
|
|
562
|
+
if (totalManualRegions > 1e6) throw new PdfRasterError(PDF_RASTER_ERROR_CODES.limitExceeded, "limit-exceeded: PDF raster manual regions exceed their aggregate limit");
|
|
557
563
|
}
|
|
558
564
|
const binding = loadNativeAnonymizeBinding();
|
|
559
565
|
let requestPages;
|
|
@@ -569,7 +575,8 @@ const anonymizePdfRaster = ({ document, pipeline, provider, pages, fillRgb = [
|
|
|
569
575
|
detections: result.resolvedEntities.map(({ start, end }) => ({
|
|
570
576
|
start,
|
|
571
577
|
end
|
|
572
|
-
}))
|
|
578
|
+
})),
|
|
579
|
+
manualRegions: page.manualRegions ?? []
|
|
573
580
|
};
|
|
574
581
|
});
|
|
575
582
|
} catch {
|
|
@@ -588,6 +595,6 @@ const anonymizePdfRaster = ({ document, pipeline, provider, pages, fillRgb = [
|
|
|
588
595
|
});
|
|
589
596
|
};
|
|
590
597
|
//#endregion
|
|
591
|
-
export { PDF_DOCUMENT_MAX_BYTES, PDF_INSPECTION_CONTRACT_VERSION, PDF_INSPECTION_ERROR_CODES, PDF_LOADED_PAYLOAD_MAX_BYTES, PDF_LOCAL_PROVIDER_ERROR_CODES, PDF_MAX_GLYPHS, PDF_MAX_OBJECTS, PDF_MAX_OBJECT_DEPTH, PDF_MAX_OBJECT_NODES, PDF_MAX_OBSERVED_TEXT_UTF8_BYTES, PDF_MAX_PAGES, PDF_MAX_PAGE_TEXT_UTF8_BYTES, PDF_OBSERVATIONS_JSON_MAX_BYTES, PDF_PAGE_DIMENSION_TOLERANCE_POINTS, PDF_RASTER_CONTRACT_VERSION, PDF_RASTER_ERROR_CODES, PDF_RASTER_MAX_OUTPUT_BYTES, PDF_RASTER_MAX_PAGE_BYTES, PDF_RASTER_MAX_TOTAL_BYTES, PDF_RASTER_REQUEST_JSON_MAX_BYTES, PDF_STREAM_DECOMPRESSED_MAX_BYTES, PdfInspectionError, PdfLocalProviderError, PdfRasterError, anonymizePdfRaster, inspectPdf, renderPdfWithPopplerTesseract, rewritePdfRasterFromDetections };
|
|
598
|
+
export { PDF_DOCUMENT_MAX_BYTES, PDF_INSPECTION_CONTRACT_VERSION, PDF_INSPECTION_ERROR_CODES, PDF_LOADED_PAYLOAD_MAX_BYTES, PDF_LOCAL_PROVIDER_ERROR_CODES, PDF_MAX_GLYPHS, PDF_MAX_OBJECTS, PDF_MAX_OBJECT_DEPTH, PDF_MAX_OBJECT_NODES, PDF_MAX_OBSERVED_TEXT_UTF8_BYTES, PDF_MAX_PAGES, PDF_MAX_PAGE_TEXT_UTF8_BYTES, PDF_OBSERVATIONS_JSON_MAX_BYTES, PDF_PAGE_DIMENSION_TOLERANCE_POINTS, PDF_RASTER_CERTIFICATE_CONTRACT_VERSION, PDF_RASTER_CONTRACT_VERSION, PDF_RASTER_ERROR_CODES, PDF_RASTER_MAX_MANUAL_REGIONS, PDF_RASTER_MAX_OUTPUT_BYTES, PDF_RASTER_MAX_PAGE_BYTES, PDF_RASTER_MAX_TOTAL_BYTES, PDF_RASTER_REQUEST_JSON_MAX_BYTES, PDF_STREAM_DECOMPRESSED_MAX_BYTES, PdfInspectionError, PdfLocalProviderError, PdfRasterError, anonymizePdfRaster, inspectPdf, renderPdfWithPopplerTesseract, rewritePdfRasterFromDetections };
|
|
592
599
|
|
|
593
600
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["PDF_DOCUMENT_MAX_BYTES","PDF_RASTER_MAX_PAGE_BYTES","PDF_RASTER_MAX_TOTAL_BYTES","PDF_MAX_PAGES","PDF_MAX_GLYPHS","PDF_MAX_OBSERVED_TEXT_UTF8_BYTES"],"sources":["../src/types.ts","../src/native-codec.ts","../src/local-provider.ts","../src/index.ts"],"sourcesContent":["export type PdfRect = {\n left: number;\n bottom: number;\n right: number;\n top: number;\n};\n\nexport type PdfGlyphObservation = {\n start: number;\n end: number;\n /** Bounds in normalized displayed-page PDF points, origin bottom-left. */\n bounds: PdfRect;\n source: \"embedded-text\" | \"ocr\";\n};\n\nexport type PdfPageObservation = {\n pageIndex: number;\n /** Effective visible width after page boxes, rotation, and UserUnit scaling. */\n widthPoints: number;\n /** Effective visible height after page boxes, rotation, and UserUnit scaling. */\n heightPoints: number;\n text: string;\n glyphs: readonly PdfGlyphObservation[];\n rendered: boolean;\n textLayer: \"absent\" | \"partial\" | \"complete\";\n ocr: \"not-run\" | \"partial\" | \"complete\";\n imageCount: number;\n};\n\nexport type PdfRiskInventory = {\n acroFormFieldCount: number;\n annotationCount: number;\n documentInfoEntryCount: number;\n embeddedFileCount: number;\n externalActionCount: number;\n formXObjectCount: number;\n imageObjectCount: number;\n incrementalRevisionCount: number;\n javascriptActionCount: number;\n metadataStreamCount: number;\n optionalContentGroupCount: number;\n signatureCount: number;\n trailingNonWhitespaceByteCount: number;\n unsupportedActionCount: number;\n xfaEntryCount: number;\n};\n\nexport type PdfInspectionGap =\n | \"encrypted-document\"\n | \"page-content-not-observed\"\n | \"page-not-rendered\"\n | \"partial-text-layer\"\n | \"retained-document-bytes\"\n | \"unobserved-visual-content\";\n\nexport type PdfPageInspection = {\n pageIndex: number;\n /** Effective visible width after page boxes, rotation, and UserUnit scaling. */\n widthPoints: number;\n /** Effective visible height after page boxes, rotation, and UserUnit scaling. */\n heightPoints: number;\n annotationCount: number;\n observation: PdfPageObservation | null;\n};\n\nexport type PdfInspection = {\n contractVersion: 1;\n pdfVersion: string;\n byteLength: number;\n objectCount: number;\n pageCount: number;\n encrypted: boolean;\n pages: readonly PdfPageInspection[];\n risks: PdfRiskInventory;\n coverage: {\n status: \"full\" | \"partial\";\n gaps: readonly PdfInspectionGap[];\n };\n};\n\nexport type PdfRasterProvider = {\n providerId: string;\n rendererName: string;\n rendererVersion: string;\n ocrName: string;\n ocrVersion: string;\n /** One explicit provider language pack; never an implicit mixed-language set. */\n ocrLanguage: string;\n};\n\nexport type PdfRasterPage = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n /** Lowercase SHA-256 of this page's exact opaque, row-packed RGB8 bytes. */\n pixelSha256: string;\n /** Strictly ordered, non-overlapping UTF-16 spans. */\n detections: readonly PdfRasterDetection[];\n};\n\nexport type PdfRasterDetection = { start: number; end: number };\n\nexport type PdfRasterRewrite = {\n contractVersion: 1;\n /** Lowercase SHA-256 of the exact source PDF bytes supplied to the call. */\n sourceSha256: string;\n provider: PdfRasterProvider;\n fillRgb: readonly [number, number, number];\n pages: readonly PdfRasterPage[];\n};\n\nexport type PdfRasterRewriteCertificate = {\n contractVersion: 1;\n pageCount: number;\n sourceSha256: string;\n outputSha256: string;\n provider: PdfRasterProvider;\n detectionCount: number;\n mappedRegionCount: number;\n structurePixelRewriteVerified: true;\n providerAssertedCoverage: \"complete-rendering-and-ocr-observation\";\n piiCleanGuaranteed: false;\n limitation: string;\n};\n\nexport type PdfRasterRewriteResult = {\n document: Uint8Array;\n certificate: PdfRasterRewriteCertificate;\n};\n\nexport const PDF_INSPECTION_ERROR_CODES = {\n documentLimitExceeded: \"document-limit-exceeded\",\n invalidDocument: \"invalid-document\",\n invalidObservation: \"invalid-observation\",\n observationLimitExceeded: \"observation-limit-exceeded\",\n providerFailed: \"provider-failed\",\n} as const;\n\nexport type PdfInspectionErrorCode =\n (typeof PDF_INSPECTION_ERROR_CODES)[keyof typeof PDF_INSPECTION_ERROR_CODES];\n\nexport const PDF_RASTER_ERROR_CODES = {\n detectionFailed: \"detection-failed\",\n invalidContract: \"invalid-contract\",\n limitExceeded: \"limit-exceeded\",\n sourceRejected: \"source-rejected\",\n verificationFailed: \"verification-failed\",\n} as const;\n\nexport type PdfRasterErrorCode =\n (typeof PDF_RASTER_ERROR_CODES)[keyof typeof PDF_RASTER_ERROR_CODES];\n","import type {\n PdfGlyphObservation,\n PdfInspection,\n PdfInspectionGap,\n PdfPageInspection,\n PdfPageObservation,\n PdfRasterProvider,\n PdfRasterRewriteCertificate,\n PdfRect,\n PdfRiskInventory,\n} from \"./types\";\n\ntype RequiredFields<T> = { [Key in keyof T]-?: true };\n\nconst RECT_FIELDS = {\n left: true,\n bottom: true,\n right: true,\n top: true,\n} as const satisfies RequiredFields<PdfRect>;\n\nconst GLYPH_FIELDS = {\n start: true,\n end: true,\n bounds: true,\n source: true,\n} as const satisfies RequiredFields<PdfGlyphObservation>;\n\nconst OBSERVATION_FIELDS = {\n pageIndex: true,\n widthPoints: true,\n heightPoints: true,\n text: true,\n glyphs: true,\n rendered: true,\n textLayer: true,\n ocr: true,\n imageCount: true,\n} as const satisfies RequiredFields<PdfPageObservation>;\n\nconst PAGE_FIELDS = {\n pageIndex: true,\n widthPoints: true,\n heightPoints: true,\n annotationCount: true,\n observation: true,\n} as const satisfies RequiredFields<PdfPageInspection>;\n\nconst RISK_FIELDS = {\n acroFormFieldCount: true,\n annotationCount: true,\n documentInfoEntryCount: true,\n embeddedFileCount: true,\n externalActionCount: true,\n formXObjectCount: true,\n imageObjectCount: true,\n incrementalRevisionCount: true,\n javascriptActionCount: true,\n metadataStreamCount: true,\n optionalContentGroupCount: true,\n signatureCount: true,\n trailingNonWhitespaceByteCount: true,\n unsupportedActionCount: true,\n xfaEntryCount: true,\n} as const satisfies RequiredFields<PdfRiskInventory>;\n\nconst INSPECTION_FIELDS = {\n contractVersion: true,\n pdfVersion: true,\n byteLength: true,\n objectCount: true,\n pageCount: true,\n encrypted: true,\n pages: true,\n risks: true,\n coverage: true,\n} as const satisfies RequiredFields<PdfInspection>;\n\nconst PROVIDER_FIELDS = {\n providerId: true,\n rendererName: true,\n rendererVersion: true,\n ocrName: true,\n ocrVersion: true,\n ocrLanguage: true,\n} as const satisfies RequiredFields<PdfRasterProvider>;\n\nconst CERTIFICATE_FIELDS = {\n contractVersion: true,\n pageCount: true,\n sourceSha256: true,\n outputSha256: true,\n provider: true,\n detectionCount: true,\n mappedRegionCount: true,\n structurePixelRewriteVerified: true,\n providerAssertedCoverage: true,\n piiCleanGuaranteed: true,\n limitation: true,\n} as const satisfies RequiredFields<PdfRasterRewriteCertificate>;\n\nconst COVERAGE_FIELDS = {\n status: true,\n gaps: true,\n} as const satisfies RequiredFields<PdfInspection[\"coverage\"]>;\n\nconst INSPECTION_GAPS = {\n \"encrypted-document\": true,\n \"page-content-not-observed\": true,\n \"page-not-rendered\": true,\n \"partial-text-layer\": true,\n \"retained-document-bytes\": true,\n \"unobserved-visual-content\": true,\n} as const satisfies Record<PdfInspectionGap, true>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst hasExactFields = (\n value: Record<string, unknown>,\n fields: Record<string, true>,\n): boolean => {\n const keys = Object.keys(value);\n return (\n keys.length === Object.keys(fields).length &&\n keys.every((key) => Object.hasOwn(fields, key))\n );\n};\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value);\n\nconst isNonNegativeInteger = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n\nconst isRect = (value: unknown): value is PdfRect =>\n isRecord(value) &&\n hasExactFields(value, RECT_FIELDS) &&\n isFiniteNumber(value[\"left\"]) &&\n isFiniteNumber(value[\"bottom\"]) &&\n isFiniteNumber(value[\"right\"]) &&\n isFiniteNumber(value[\"top\"]);\n\nconst isGlyph = (value: unknown): value is PdfGlyphObservation =>\n isRecord(value) &&\n hasExactFields(value, GLYPH_FIELDS) &&\n isNonNegativeInteger(value[\"start\"]) &&\n isNonNegativeInteger(value[\"end\"]) &&\n value[\"end\"] >= value[\"start\"] &&\n isRect(value[\"bounds\"]) &&\n (value[\"source\"] === \"embedded-text\" || value[\"source\"] === \"ocr\");\n\nconst isObservation = (value: unknown): value is PdfPageObservation =>\n isRecord(value) &&\n hasExactFields(value, OBSERVATION_FIELDS) &&\n isNonNegativeInteger(value[\"pageIndex\"]) &&\n isFiniteNumber(value[\"widthPoints\"]) &&\n value[\"widthPoints\"] > 0 &&\n isFiniteNumber(value[\"heightPoints\"]) &&\n value[\"heightPoints\"] > 0 &&\n typeof value[\"text\"] === \"string\" &&\n Array.isArray(value[\"glyphs\"]) &&\n value[\"glyphs\"].every(isGlyph) &&\n typeof value[\"rendered\"] === \"boolean\" &&\n (value[\"textLayer\"] === \"absent\" ||\n value[\"textLayer\"] === \"partial\" ||\n value[\"textLayer\"] === \"complete\") &&\n (value[\"ocr\"] === \"not-run\" ||\n value[\"ocr\"] === \"partial\" ||\n value[\"ocr\"] === \"complete\") &&\n isNonNegativeInteger(value[\"imageCount\"]);\n\nconst isPage = (value: unknown): value is PdfPageInspection =>\n isRecord(value) &&\n hasExactFields(value, PAGE_FIELDS) &&\n isNonNegativeInteger(value[\"pageIndex\"]) &&\n isFiniteNumber(value[\"widthPoints\"]) &&\n value[\"widthPoints\"] > 0 &&\n isFiniteNumber(value[\"heightPoints\"]) &&\n value[\"heightPoints\"] > 0 &&\n isNonNegativeInteger(value[\"annotationCount\"]) &&\n (value[\"observation\"] === null || isObservation(value[\"observation\"]));\n\nconst isRiskInventory = (value: unknown): value is PdfRiskInventory =>\n isRecord(value) &&\n hasExactFields(value, RISK_FIELDS) &&\n Object.keys(RISK_FIELDS).every((field) => isNonNegativeInteger(value[field]));\n\nconst isInspectionGap = (value: unknown): value is PdfInspectionGap =>\n typeof value === \"string\" && Object.hasOwn(INSPECTION_GAPS, value);\n\nconst isInspection = (value: unknown): value is PdfInspection =>\n isRecord(value) &&\n hasExactFields(value, INSPECTION_FIELDS) &&\n value[\"contractVersion\"] === 1 &&\n typeof value[\"pdfVersion\"] === \"string\" &&\n isNonNegativeInteger(value[\"byteLength\"]) &&\n isNonNegativeInteger(value[\"objectCount\"]) &&\n isNonNegativeInteger(value[\"pageCount\"]) &&\n typeof value[\"encrypted\"] === \"boolean\" &&\n Array.isArray(value[\"pages\"]) &&\n value[\"pages\"].length === value[\"pageCount\"] &&\n value[\"pages\"].every(isPage) &&\n value[\"pages\"].every(({ pageIndex }, index) => pageIndex === index) &&\n isRiskInventory(value[\"risks\"]) &&\n isRecord(value[\"coverage\"]) &&\n hasExactFields(value[\"coverage\"], COVERAGE_FIELDS) &&\n (value[\"coverage\"][\"status\"] === \"full\" ||\n value[\"coverage\"][\"status\"] === \"partial\") &&\n Array.isArray(value[\"coverage\"][\"gaps\"]) &&\n value[\"coverage\"][\"gaps\"].every(isInspectionGap);\n\nconst isProvider = (value: unknown): value is PdfRasterProvider =>\n isRecord(value) &&\n hasExactFields(value, PROVIDER_FIELDS) &&\n typeof value[\"providerId\"] === \"string\" &&\n typeof value[\"rendererName\"] === \"string\" &&\n typeof value[\"rendererVersion\"] === \"string\" &&\n typeof value[\"ocrName\"] === \"string\" &&\n typeof value[\"ocrVersion\"] === \"string\" &&\n typeof value[\"ocrLanguage\"] === \"string\";\n\nconst isSha256 = (value: unknown): value is string =>\n typeof value === \"string\" && /^[a-f0-9]{64}$/u.test(value);\n\nconst isCertificate = (value: unknown): value is PdfRasterRewriteCertificate =>\n isRecord(value) &&\n hasExactFields(value, CERTIFICATE_FIELDS) &&\n value[\"contractVersion\"] === 1 &&\n isNonNegativeInteger(value[\"pageCount\"]) &&\n isSha256(value[\"sourceSha256\"]) &&\n isSha256(value[\"outputSha256\"]) &&\n isProvider(value[\"provider\"]) &&\n isNonNegativeInteger(value[\"detectionCount\"]) &&\n isNonNegativeInteger(value[\"mappedRegionCount\"]) &&\n value[\"structurePixelRewriteVerified\"] === true &&\n value[\"providerAssertedCoverage\"] ===\n \"complete-rendering-and-ocr-observation\" &&\n value[\"piiCleanGuaranteed\"] === false &&\n typeof value[\"limitation\"] === \"string\";\n\nexport const decodePdfInspection = (json: string): PdfInspection => {\n const value: unknown = JSON.parse(json);\n if (!isInspection(value)) {\n throw new Error(\"Native PDF inspection does not match contract version 1\");\n }\n return value;\n};\n\nexport const decodePdfRasterRewriteCertificate = (\n json: string,\n): PdfRasterRewriteCertificate => {\n const value: unknown = JSON.parse(json);\n if (!isCertificate(value)) {\n throw new Error(\n \"Native PDF raster certificate does not match contract version 1\",\n );\n }\n return value;\n};\n","import { execFile } from \"node:child_process\";\nimport {\n lstat,\n mkdtemp,\n readFile,\n rm,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, sep } from \"node:path\";\n\nimport { loadNativeAnonymizeBinding } from \"@stll/anonymize\";\n\nimport { decodePdfInspection } from \"./native-codec\";\nimport type {\n PdfGlyphObservation,\n PdfPageObservation,\n PdfRasterProvider,\n} from \"./types\";\n\nconst LOCAL_PROVIDER_ID = \"poppler-tesseract-local\";\nconst PROCESS_OUTPUT_MAX_BYTES = 64 * 1024 * 1024;\nconst PDF_DOCUMENT_MAX_BYTES = 64 * 1024 * 1024;\nconst PDF_RASTER_MAX_PAGE_BYTES = 128 * 1024 * 1024;\nconst PDF_RASTER_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst PDF_MAX_PAGES = 10_000;\nconst PDF_MAX_GLYPHS = 5_000_000;\nconst PDF_MAX_OBSERVED_TEXT_UTF8_BYTES = 64 * 1024 * 1024;\nconst DEFAULT_DPI = 300;\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MIN_DPI = 72;\nconst MAX_DPI = 600;\nconst MIN_TIMEOUT_MS = 100;\nconst MAX_TIMEOUT_MS = 300_000;\nconst LANGUAGE_PACK_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/u;\nconst TEMP_PREFIX = \"stella-anonymize-pdf-\";\n\nexport const PDF_LOCAL_PROVIDER_ERROR_CODES = {\n cleanupFailed: \"cleanup-failed\",\n executableFailed: \"executable-failed\",\n invalidOptions: \"invalid-options\",\n invalidOutput: \"invalid-output\",\n limitExceeded: \"limit-exceeded\",\n sourceRejected: \"source-rejected\",\n} as const;\n\nexport type PdfLocalProviderErrorCode =\n (typeof PDF_LOCAL_PROVIDER_ERROR_CODES)[keyof typeof PDF_LOCAL_PROVIDER_ERROR_CODES];\n\nexport class PdfLocalProviderError extends Error {\n readonly code: PdfLocalProviderErrorCode;\n\n constructor(code: PdfLocalProviderErrorCode, message: string) {\n super(message);\n this.name = \"PdfLocalProviderError\";\n this.code = code;\n }\n}\n\nexport type RenderPdfWithPopplerTesseractOptions = {\n document: Uint8Array;\n /** One explicit installed Tesseract traineddata name, for example `eng`. */\n ocrLanguage: string;\n dpi?: number | undefined;\n pdftoppmPath?: string | undefined;\n tesseractPath?: string | undefined;\n timeoutMs?: number | undefined;\n};\n\nexport type LocalPdfRasterPage = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n pixels: Uint8Array;\n};\n\nexport type LocalPdfRasterObservation = {\n provider: PdfRasterProvider;\n pages: readonly LocalPdfRasterPage[];\n};\n\ntype ResolvedLocalProviderOptions = {\n dpi: number;\n ocrLanguage: string;\n pdftoppmPath: string;\n tesseractPath: string;\n timeoutMs: number;\n};\n\ntype ProcessResult = { stdout: Buffer; stderr: Buffer };\n\nconst providerError = (\n code: PdfLocalProviderErrorCode,\n message: string,\n): PdfLocalProviderError =>\n new PdfLocalProviderError(code, `${code}: ${message}`);\n\nconst validateOptions = (\n options: RenderPdfWithPopplerTesseractOptions,\n): ResolvedLocalProviderOptions => {\n const dpi = options.dpi ?? DEFAULT_DPI;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pdftoppmPath = options.pdftoppmPath ?? \"pdftoppm\";\n const tesseractPath = options.tesseractPath ?? \"tesseract\";\n if (\n !Number.isInteger(dpi) ||\n dpi < MIN_DPI ||\n dpi > MAX_DPI ||\n !Number.isInteger(timeoutMs) ||\n timeoutMs < MIN_TIMEOUT_MS ||\n timeoutMs > MAX_TIMEOUT_MS ||\n !LANGUAGE_PACK_PATTERN.test(options.ocrLanguage) ||\n !pdftoppmPath ||\n pdftoppmPath.includes(\"\\0\") ||\n !tesseractPath ||\n tesseractPath.includes(\"\\0\")\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOptions,\n \"local PDF provider options are invalid\",\n );\n }\n return {\n dpi,\n ocrLanguage: options.ocrLanguage,\n pdftoppmPath,\n tesseractPath,\n timeoutMs,\n };\n};\n\nconst runExecutable = (\n executable: string,\n args: readonly string[],\n timeoutMs: number,\n stage: \"OCR\" | \"renderer\" | \"version probe\",\n): Promise<ProcessResult> =>\n new Promise((resolve, reject) => {\n execFile(\n executable,\n args,\n {\n encoding: \"buffer\",\n maxBuffer: PROCESS_OUTPUT_MAX_BYTES,\n timeout: timeoutMs,\n windowsHide: true,\n },\n (error, stdout, stderr) => {\n if (error !== null) {\n reject(\n providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.executableFailed,\n `local PDF ${stage} failed`,\n ),\n );\n return;\n }\n resolve({ stdout: Buffer.from(stdout), stderr: Buffer.from(stderr) });\n },\n );\n });\n\nconst decodeUtf8 = (value: Uint8Array, context: string): string => {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(value);\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n `local PDF ${context} is not valid UTF-8`,\n );\n }\n};\n\nconst versionFrom = (\n value: Uint8Array,\n prefix: string,\n context: string,\n): string => {\n const line = decodeUtf8(value, context).split(/\\r?\\n/u, 1)[0]?.trim();\n const version = line?.startsWith(prefix)\n ? line.slice(prefix.length).trim()\n : \"\";\n if (!version || version.length > 256 || /\\p{Cc}/u.test(version)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n `local PDF ${context} is invalid`,\n );\n }\n return version;\n};\n\ntype InspectedPageGeometry = {\n heightPoints: number;\n widthPoints: number;\n};\n\nconst inspectPageGeometry = (\n document: Uint8Array,\n): readonly InspectedPageGeometry[] => {\n if (document.byteLength > PDF_DOCUMENT_MAX_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"PDF source exceeds its byte limit\",\n );\n }\n const inspect = loadNativeAnonymizeBinding().inspectPdfJson;\n if (inspect === undefined) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"native PDF inspection is unavailable\",\n );\n }\n try {\n const inspection = decodePdfInspection(inspect(document));\n if (\n inspection.encrypted === true ||\n inspection.pageCount < 1 ||\n inspection.pageCount > PDF_MAX_PAGES\n ) {\n throw new Error(\"source rejected\");\n }\n return inspection.pages.map(({ heightPoints, widthPoints }) => ({\n heightPoints,\n widthPoints,\n }));\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"PDF source is unsupported by the local raster provider\",\n );\n }\n};\n\nconst assertProjectedRasterLimits = (\n pages: readonly InspectedPageGeometry[],\n dpi: number,\n): void => {\n let totalBytes = 0;\n for (const { heightPoints, widthPoints } of pages) {\n const widthPixels = Math.ceil((widthPoints * dpi) / 72);\n const heightPixels = Math.ceil((heightPoints * dpi) / 72);\n const pageBytes = widthPixels * heightPixels * 3;\n totalBytes += pageBytes;\n if (\n !Number.isSafeInteger(widthPixels) ||\n !Number.isSafeInteger(heightPixels) ||\n widthPixels <= 0 ||\n heightPixels <= 0 ||\n !Number.isSafeInteger(pageBytes) ||\n pageBytes > PDF_RASTER_MAX_PAGE_BYTES ||\n !Number.isSafeInteger(totalBytes) ||\n totalBytes > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"PDF page geometry exceeds the selected DPI raster limits\",\n );\n }\n }\n};\n\ntype PpmPage = {\n width: number;\n height: number;\n pixels: Uint8Array;\n};\n\nconst isWhitespace = (byte: number): boolean =>\n byte === 0x09 ||\n byte === 0x0a ||\n byte === 0x0b ||\n byte === 0x0c ||\n byte === 0x0d ||\n byte === 0x20;\n\nconst ppmToken = (bytes: Uint8Array, start: number): [string, number] => {\n let offset = start;\n while (offset < bytes.length) {\n if (isWhitespace(bytes[offset] ?? -1)) {\n offset += 1;\n continue;\n }\n if (bytes[offset] === 0x23) {\n while (offset < bytes.length && bytes[offset] !== 0x0a) offset += 1;\n continue;\n }\n break;\n }\n const tokenStart = offset;\n while (\n offset < bytes.length &&\n !isWhitespace(bytes[offset] ?? -1) &&\n bytes[offset] !== 0x23\n ) {\n offset += 1;\n }\n if (tokenStart === offset) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM header\",\n );\n }\n const token = Buffer.from(bytes.subarray(tokenStart, offset)).toString(\n \"ascii\",\n );\n if (!/^[\\x21-\\x7e]+$/u.test(token)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM header\",\n );\n }\n return [token, offset];\n};\n\nconst parsePositiveInteger = (value: string): number => {\n if (!/^[1-9][0-9]*$/u.test(value)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted invalid PPM dimensions\",\n );\n }\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler PPM dimensions exceed their limit\",\n );\n }\n return parsed;\n};\n\nconst parsePpm = (bytes: Uint8Array): PpmPage => {\n const [magic, afterMagic] = ppmToken(bytes, 0);\n const [widthValue, afterWidth] = ppmToken(bytes, afterMagic);\n const [heightValue, afterHeight] = ppmToken(bytes, afterWidth);\n const [maximumValue, afterMaximum] = ppmToken(bytes, afterHeight);\n if (magic !== \"P6\" || maximumValue !== \"255\") {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler must emit binary RGB8 PPM pages\",\n );\n }\n const width = parsePositiveInteger(widthValue);\n const height = parsePositiveInteger(heightValue);\n const expected = width * height * 3;\n if (!Number.isSafeInteger(expected) || expected > PDF_RASTER_MAX_PAGE_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page pixels exceed their byte limit\",\n );\n }\n let pixelOffset = afterMaximum;\n if (!isWhitespace(bytes[pixelOffset] ?? -1)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM pixel separator\",\n );\n }\n const separator = bytes[pixelOffset];\n pixelOffset += 1;\n if (separator === 0x0d && bytes[pixelOffset] === 0x0a) pixelOffset += 1;\n if (bytes.length - pixelOffset !== expected) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted a truncated or trailing PPM page\",\n );\n }\n return { width, height, pixels: bytes.subarray(pixelOffset) };\n};\n\nconst boundedRenderedPage = async (path: string): Promise<PpmPage> => {\n const metadata = await lstat(path);\n if (!metadata.isFile() || metadata.isSymbolicLink()) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler page output must be a regular file\",\n );\n }\n if (metadata.size > PDF_RASTER_MAX_PAGE_BYTES + 1024 * 1024) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page output exceeds its byte limit\",\n );\n }\n return parsePpm(await readFile(path));\n};\n\nconst integerTsvField = (value: string | undefined): number => {\n if (value === undefined || !/^(?:0|[1-9][0-9]*)$/u.test(value)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted invalid TSV geometry\",\n );\n }\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract TSV geometry exceeds its limit\",\n );\n }\n return parsed;\n};\n\nconst parseTesseractTsv = (\n bytes: Uint8Array,\n page: PpmPage,\n pageGeometry: InspectedPageGeometry,\n pageIndex: number,\n): PdfPageObservation => {\n const lines = decodeUtf8(bytes, \"Tesseract TSV\").split(/\\r?\\n/u);\n const header = lines.shift()?.split(\"\\t\");\n if (\n header?.slice(0, 12).join(\"\\t\") !==\n \"level\\tpage_num\\tblock_num\\tpar_num\\tline_num\\tword_num\\tleft\\ttop\\twidth\\theight\\tconf\\ttext\"\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted an unsupported TSV header\",\n );\n }\n const { heightPoints, widthPoints } = pageGeometry;\n const glyphs: PdfGlyphObservation[] = [];\n let text = \"\";\n let previousLine = \"\";\n for (const line of lines) {\n if (!line) continue;\n const fields = line.split(\"\\t\");\n if (fields[0] !== \"5\") continue;\n const word = fields.slice(11).join(\"\\t\").trim();\n if (!word) continue;\n if (/\\p{Cc}/u.test(word)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted control characters in OCR text\",\n );\n }\n const lineKey = `${fields[2] ?? \"\"}/${fields[3] ?? \"\"}/${fields[4] ?? \"\"}`;\n if (text) text += lineKey === previousLine ? \" \" : \"\\n\";\n previousLine = lineKey;\n const start = text.length;\n text += word;\n const end = text.length;\n const left = integerTsvField(fields[6]);\n const top = integerTsvField(fields[7]);\n const width = integerTsvField(fields[8]);\n const height = integerTsvField(fields[9]);\n const right = left + width;\n const bottom = top + height;\n if (\n width === 0 ||\n height === 0 ||\n !Number.isSafeInteger(right) ||\n !Number.isSafeInteger(bottom) ||\n right > page.width ||\n bottom > page.height\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted out-of-page OCR geometry\",\n );\n }\n glyphs.push({\n start,\n end,\n bounds: {\n left: (left * widthPoints) / page.width,\n bottom: heightPoints - (bottom * heightPoints) / page.height,\n right: (right * widthPoints) / page.width,\n top: heightPoints - (top * heightPoints) / page.height,\n },\n source: \"ocr\",\n });\n if (glyphs.length > PDF_MAX_GLYPHS) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR glyph count exceeds its limit\",\n );\n }\n if (Buffer.byteLength(text, \"utf8\") > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR text exceeds its byte limit\",\n );\n }\n }\n return {\n pageIndex,\n widthPoints,\n heightPoints,\n text,\n glyphs,\n rendered: true,\n textLayer: \"absent\",\n ocr: \"complete\",\n imageCount: 0,\n };\n};\n\nconst safeCleanup = async (directory: string): Promise<void> => {\n const expectedPrefix = `${tmpdir()}${sep}${TEMP_PREFIX}`;\n if (!directory.startsWith(expectedPrefix)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be verified\",\n );\n }\n try {\n const metadata = await lstat(directory);\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be verified\",\n );\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n if (error instanceof PdfLocalProviderError) throw error;\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be inspected\",\n );\n }\n try {\n await rm(directory, { force: true, recursive: true });\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary files could not be removed\",\n );\n }\n};\n\nexport const renderPdfWithPopplerTesseract = async (\n options: RenderPdfWithPopplerTesseractOptions,\n): Promise<LocalPdfRasterObservation> => {\n const resolved = validateOptions(options);\n const pageGeometry = inspectPageGeometry(options.document);\n assertProjectedRasterLimits(pageGeometry, resolved.dpi);\n const pageCount = pageGeometry.length;\n const popplerVersionResult = await runExecutable(\n resolved.pdftoppmPath,\n [\"-v\"],\n resolved.timeoutMs,\n \"version probe\",\n );\n const tesseractVersionResult = await runExecutable(\n resolved.tesseractPath,\n [\"--version\"],\n resolved.timeoutMs,\n \"version probe\",\n );\n const rendererVersion = versionFrom(\n popplerVersionResult.stderr.length > 0\n ? popplerVersionResult.stderr\n : popplerVersionResult.stdout,\n \"pdftoppm version \",\n \"Poppler version\",\n );\n const ocrVersion = versionFrom(\n tesseractVersionResult.stdout.length > 0\n ? tesseractVersionResult.stdout\n : tesseractVersionResult.stderr,\n \"tesseract \",\n \"Tesseract version\",\n );\n const directory = await mkdtemp(join(tmpdir(), TEMP_PREFIX));\n try {\n const sourcePath = join(directory, \"source.pdf\");\n const outputPrefix = join(directory, \"page\");\n await writeFile(sourcePath, options.document, { flag: \"wx\", mode: 0o600 });\n const pages: LocalPdfRasterPage[] = [];\n let totalPixels = 0;\n let totalGlyphs = 0;\n let totalObservedTextUtf8Bytes = 0;\n for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {\n const inspectedGeometry = pageGeometry.at(pageNumber - 1);\n if (inspectedGeometry === undefined) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"PDF page geometry became unavailable\",\n );\n }\n const pageOutputPrefix = `${outputPrefix}-${pageNumber}`;\n const pagePath = `${pageOutputPrefix}.ppm`;\n await runExecutable(\n resolved.pdftoppmPath,\n [\n \"-cropbox\",\n \"-f\",\n String(pageNumber),\n \"-l\",\n String(pageNumber),\n \"-singlefile\",\n \"-r\",\n String(resolved.dpi),\n sourcePath,\n pageOutputPrefix,\n ],\n resolved.timeoutMs,\n \"renderer\",\n );\n try {\n const page = await boundedRenderedPage(pagePath);\n totalPixels += page.pixels.byteLength;\n if (\n !Number.isSafeInteger(totalPixels) ||\n totalPixels > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page pixels exceed their aggregate limit\",\n );\n }\n const ocr = await runExecutable(\n resolved.tesseractPath,\n [pagePath, \"stdout\", \"-l\", resolved.ocrLanguage, \"tsv\"],\n resolved.timeoutMs,\n \"OCR\",\n );\n const observation = parseTesseractTsv(\n ocr.stdout,\n page,\n inspectedGeometry,\n pageNumber - 1,\n );\n totalGlyphs += observation.glyphs.length;\n totalObservedTextUtf8Bytes += Buffer.byteLength(\n observation.text,\n \"utf8\",\n );\n if (\n !Number.isSafeInteger(totalGlyphs) ||\n totalGlyphs > PDF_MAX_GLYPHS ||\n !Number.isSafeInteger(totalObservedTextUtf8Bytes) ||\n totalObservedTextUtf8Bytes > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR document output exceeds its aggregate limit\",\n );\n }\n pages.push({\n observation,\n widthPixels: page.width,\n heightPixels: page.height,\n pixels: page.pixels,\n });\n } finally {\n await unlink(pagePath).catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return;\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF page raster could not be removed\",\n );\n });\n }\n }\n return {\n provider: {\n providerId: LOCAL_PROVIDER_ID,\n rendererName: \"Poppler pdftoppm\",\n rendererVersion,\n ocrName: \"Tesseract OCR\",\n ocrVersion,\n ocrLanguage: resolved.ocrLanguage,\n },\n pages,\n };\n } finally {\n await safeCleanup(directory);\n }\n};\n","import { createHash } from \"node:crypto\";\n\nimport {\n convert_external_detection_batch,\n loadNativeAnonymizeBinding,\n type ExternalDetectionBatch,\n type PreparedNativePipeline,\n} from \"@stll/anonymize\";\n\nimport {\n PDF_INSPECTION_ERROR_CODES,\n PDF_RASTER_ERROR_CODES,\n type PdfInspection,\n type PdfInspectionErrorCode,\n type PdfPageObservation,\n type PdfRasterProvider,\n type PdfRasterErrorCode,\n type PdfRasterRewrite,\n type PdfRasterRewriteResult,\n} from \"./types\";\nimport {\n decodePdfInspection,\n decodePdfRasterRewriteCertificate,\n} from \"./native-codec\";\n\nexport const PDF_INSPECTION_CONTRACT_VERSION = 1 as const;\nexport const PDF_RASTER_CONTRACT_VERSION = 1 as const;\nexport const PDF_RASTER_MAX_PAGE_BYTES = 128 * 1024 * 1024;\nexport const PDF_RASTER_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nexport const PDF_RASTER_MAX_OUTPUT_BYTES = 512 * 1024 * 1024;\nexport const PDF_RASTER_REQUEST_JSON_MAX_BYTES = 64 * 1024 * 1024;\nexport const PDF_DOCUMENT_MAX_BYTES = 64 * 1024 * 1024;\nexport const PDF_STREAM_DECOMPRESSED_MAX_BYTES = 32 * 1024 * 1024;\nexport const PDF_LOADED_PAYLOAD_MAX_BYTES = 128 * 1024 * 1024;\nexport const PDF_MAX_OBJECTS = 200_000;\nexport const PDF_MAX_OBJECT_NODES = 1_000_000;\nexport const PDF_MAX_OBJECT_DEPTH = 128;\nexport const PDF_MAX_PAGES = 10_000;\nexport const PDF_MAX_GLYPHS = 5_000_000;\nexport const PDF_MAX_PAGE_TEXT_UTF8_BYTES = 16 * 1024 * 1024;\nexport const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES = 64 * 1024 * 1024;\nexport const PDF_OBSERVATIONS_JSON_MAX_BYTES = 64 * 1024 * 1024;\n/** Renderer dimensions may differ by this many points due to numeric rounding. */\nexport const PDF_PAGE_DIMENSION_TOLERANCE_POINTS = 0.25;\n\nexport class PdfInspectionError extends Error {\n readonly code: PdfInspectionErrorCode;\n\n constructor(code: PdfInspectionErrorCode, message: string) {\n super(message);\n this.name = \"PdfInspectionError\";\n this.code = code;\n }\n}\n\nexport class PdfRasterError extends Error {\n readonly code: PdfRasterErrorCode;\n\n constructor(code: PdfRasterErrorCode, message: string) {\n super(message);\n this.name = \"PdfRasterError\";\n this.code = code;\n }\n}\n\nconst errorCode = (message: string): PdfInspectionErrorCode => {\n const code = Object.values(PDF_INSPECTION_ERROR_CODES).find((candidate) =>\n message.startsWith(`${candidate}:`),\n );\n return code ?? PDF_INSPECTION_ERROR_CODES.invalidDocument;\n};\n\nconst rasterErrorCode = (message: string): PdfRasterErrorCode => {\n const code = Object.values(PDF_RASTER_ERROR_CODES).find((candidate) =>\n message.startsWith(`${candidate}:`),\n );\n return code ?? PDF_RASTER_ERROR_CODES.verificationFailed;\n};\n\nexport type InspectPdfOptions = {\n pageObservations?: readonly PdfPageObservation[];\n};\n\nexport const inspectPdf = (\n document: Uint8Array,\n options: InspectPdfOptions = {},\n): PdfInspection => {\n const inspect = loadNativeAnonymizeBinding().inspectPdfJson;\n if (inspect === undefined) {\n throw new PdfInspectionError(\n PDF_INSPECTION_ERROR_CODES.invalidDocument,\n \"Native anonymize binding does not expose PDF inspection\",\n );\n }\n try {\n const observations = options.pageObservations;\n return decodePdfInspection(\n inspect(\n document,\n observations === undefined ? undefined : JSON.stringify(observations),\n ),\n );\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"PDF inspection failed\";\n throw new PdfInspectionError(errorCode(message), message);\n }\n};\n\nexport type RewritePdfRasterFromDetectionsOptions = {\n document: Uint8Array;\n request: PdfRasterRewrite;\n /** One opaque, row-packed RGB8 buffer per request page, in page order. */\n pagePixels: readonly Uint8Array[];\n};\n\n/**\n * Advanced rewrite-only surface. It verifies structure and destructive pixels but\n * does not run detection or certify that the result is PII-free.\n */\nexport const rewritePdfRasterFromDetections = ({\n document,\n request,\n pagePixels,\n}: RewritePdfRasterFromDetectionsOptions): PdfRasterRewriteResult => {\n const rewrite =\n loadNativeAnonymizeBinding().rewritePdfRasterFromDetectionsJson;\n if (rewrite === undefined) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.verificationFailed,\n \"Native anonymize binding does not expose PDF raster rewriting\",\n );\n }\n try {\n const result = rewrite(document, JSON.stringify(request), pagePixels);\n return {\n document: result.document,\n certificate: decodePdfRasterRewriteCertificate(result.certificateJson),\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"PDF raster rewrite failed\";\n throw new PdfRasterError(rasterErrorCode(message), message);\n }\n};\n\nexport type PdfRasterObservedPageInput = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n pixels: Uint8Array;\n /** Optional digest-bound provider batch merged through stella caller semantics. */\n externalDetectionBatch?: ExternalDetectionBatch | string | undefined;\n};\n\nexport type AnonymizePdfRasterOptions = {\n document: Uint8Array;\n pipeline: Pick<\n PreparedNativePipeline,\n \"redactText\" | \"redactTextWithCallerDetections\"\n >;\n provider: PdfRasterProvider;\n pages: readonly PdfRasterObservedPageInput[];\n fillRgb?: readonly [number, number, number] | undefined;\n};\n\nconst sha256 = (value: Uint8Array): string =>\n createHash(\"sha256\").update(value).digest(\"hex\");\n\n/** Run stella detection, merge optional external detections, then rewrite pixels. */\nexport const anonymizePdfRaster = ({\n document,\n pipeline,\n provider,\n pages,\n fillRgb = [0, 0, 0],\n}: AnonymizePdfRasterOptions): PdfRasterRewriteResult => {\n if (document.byteLength > PDF_DOCUMENT_MAX_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF source exceeds its byte limit\",\n );\n }\n if (pages.length > PDF_MAX_PAGES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page count exceeds its limit\",\n );\n }\n let totalPixelBytes = 0;\n let totalObservedTextBytes = 0;\n const textEncoder = new TextEncoder();\n for (const page of pages) {\n if (typeof page.observation?.text !== \"string\") {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.invalidContract,\n \"invalid-contract: PDF raster observed text is invalid\",\n );\n }\n const observedTextBytes = textEncoder.encode(\n page.observation.text,\n ).byteLength;\n if (observedTextBytes > PDF_MAX_PAGE_TEXT_UTF8_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page text exceeds its byte limit\",\n );\n }\n totalObservedTextBytes += observedTextBytes;\n if (totalObservedTextBytes > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster observed text exceeds its aggregate byte limit\",\n );\n }\n const { heightPixels, widthPixels } = page;\n if (\n !Number.isSafeInteger(widthPixels) ||\n !Number.isSafeInteger(heightPixels) ||\n widthPixels <= 0 ||\n heightPixels <= 0\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.invalidContract,\n \"invalid-contract: PDF raster pixel dimensions are invalid\",\n );\n }\n const expected = widthPixels * heightPixels * 3;\n if (\n !Number.isSafeInteger(expected) ||\n expected > PDF_RASTER_MAX_PAGE_BYTES ||\n page.pixels.byteLength !== expected\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page pixels exceed limits or have an invalid RGB8 length\",\n );\n }\n totalPixelBytes += expected;\n if (\n !Number.isSafeInteger(totalPixelBytes) ||\n totalPixelBytes > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster pixels exceed their aggregate limit\",\n );\n }\n }\n const binding = loadNativeAnonymizeBinding();\n let requestPages: PdfRasterRewrite[\"pages\"];\n try {\n requestPages = pages.map((page) => {\n const external =\n page.externalDetectionBatch === undefined\n ? undefined\n : convert_external_detection_batch(\n new TextEncoder().encode(page.observation.text),\n page.externalDetectionBatch,\n { binding },\n );\n const result =\n external === undefined\n ? pipeline.redactText(page.observation.text)\n : pipeline.redactTextWithCallerDetections(page.observation.text, {\n detections: external,\n });\n return {\n observation: page.observation,\n widthPixels: page.widthPixels,\n heightPixels: page.heightPixels,\n pixelSha256: sha256(page.pixels),\n detections: result.resolvedEntities.map(({ start, end }) => ({\n start,\n end,\n })),\n };\n });\n } catch {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.detectionFailed,\n \"detection-failed: PDF raster detection failed\",\n );\n }\n return rewritePdfRasterFromDetections({\n document,\n request: {\n contractVersion: PDF_RASTER_CONTRACT_VERSION,\n sourceSha256: sha256(document),\n provider,\n fillRgb,\n pages: requestPages,\n },\n pagePixels: pages.map(({ pixels }) => pixels),\n });\n};\n\nexport { PDF_INSPECTION_ERROR_CODES } from \"./types\";\nexport { PDF_RASTER_ERROR_CODES } from \"./types\";\nexport {\n PDF_LOCAL_PROVIDER_ERROR_CODES,\n PdfLocalProviderError,\n renderPdfWithPopplerTesseract,\n} from \"./local-provider\";\nexport type {\n LocalPdfRasterObservation,\n LocalPdfRasterPage,\n PdfLocalProviderErrorCode,\n RenderPdfWithPopplerTesseractOptions,\n} from \"./local-provider\";\nexport type {\n PdfGlyphObservation,\n PdfInspection,\n PdfInspectionErrorCode,\n PdfInspectionGap,\n PdfPageInspection,\n PdfPageObservation,\n PdfRect,\n PdfRiskInventory,\n PdfRasterDetection,\n PdfRasterErrorCode,\n PdfRasterPage,\n PdfRasterProvider,\n PdfRasterRewrite,\n PdfRasterRewriteCertificate,\n PdfRasterRewriteResult,\n} from \"./types\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["PDF_DOCUMENT_MAX_BYTES","PDF_RASTER_MAX_PAGE_BYTES","PDF_RASTER_MAX_TOTAL_BYTES","PDF_MAX_PAGES","PDF_MAX_GLYPHS","PDF_MAX_OBSERVED_TEXT_UTF8_BYTES"],"sources":["../src/types.ts","../src/native-codec.ts","../src/local-provider.ts","../src/index.ts"],"sourcesContent":["export type PdfRect = {\n left: number;\n bottom: number;\n right: number;\n top: number;\n};\n\nexport type PdfGlyphObservation = {\n start: number;\n end: number;\n /** Bounds in normalized displayed-page PDF points, origin bottom-left. */\n bounds: PdfRect;\n source: \"embedded-text\" | \"ocr\";\n};\n\nexport type PdfPageObservation = {\n pageIndex: number;\n /** Effective visible width after page boxes, rotation, and UserUnit scaling. */\n widthPoints: number;\n /** Effective visible height after page boxes, rotation, and UserUnit scaling. */\n heightPoints: number;\n text: string;\n glyphs: readonly PdfGlyphObservation[];\n rendered: boolean;\n textLayer: \"absent\" | \"partial\" | \"complete\";\n ocr: \"not-run\" | \"partial\" | \"complete\";\n imageCount: number;\n};\n\nexport type PdfRiskInventory = {\n acroFormFieldCount: number;\n annotationCount: number;\n documentInfoEntryCount: number;\n embeddedFileCount: number;\n externalActionCount: number;\n formXObjectCount: number;\n imageObjectCount: number;\n incrementalRevisionCount: number;\n javascriptActionCount: number;\n metadataStreamCount: number;\n optionalContentGroupCount: number;\n signatureCount: number;\n trailingNonWhitespaceByteCount: number;\n unsupportedActionCount: number;\n xfaEntryCount: number;\n};\n\nexport type PdfInspectionGap =\n | \"encrypted-document\"\n | \"page-content-not-observed\"\n | \"page-not-rendered\"\n | \"partial-text-layer\"\n | \"retained-document-bytes\"\n | \"unobserved-visual-content\";\n\nexport type PdfPageInspection = {\n pageIndex: number;\n /** Effective visible width after page boxes, rotation, and UserUnit scaling. */\n widthPoints: number;\n /** Effective visible height after page boxes, rotation, and UserUnit scaling. */\n heightPoints: number;\n annotationCount: number;\n observation: PdfPageObservation | null;\n};\n\nexport type PdfInspection = {\n contractVersion: 1;\n pdfVersion: string;\n byteLength: number;\n objectCount: number;\n pageCount: number;\n encrypted: boolean;\n pages: readonly PdfPageInspection[];\n risks: PdfRiskInventory;\n coverage: {\n status: \"full\" | \"partial\";\n gaps: readonly PdfInspectionGap[];\n };\n};\n\nexport type PdfRasterProvider = {\n providerId: string;\n rendererName: string;\n rendererVersion: string;\n ocrName: string;\n ocrVersion: string;\n /** One explicit provider language pack; never an implicit mixed-language set. */\n ocrLanguage: string;\n};\n\nexport type PdfRasterPage = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n /** Lowercase SHA-256 of this page's exact opaque, row-packed RGB8 bytes. */\n pixelSha256: string;\n /** Strictly ordered, non-overlapping UTF-16 spans. */\n detections: readonly PdfRasterDetection[];\n /** User-reviewed regions in normalized displayed-page PDF points. */\n manualRegions?: readonly PdfRect[];\n};\n\nexport type PdfRasterDetection = { start: number; end: number };\n\nexport type PdfRasterRewrite = {\n contractVersion: 1;\n /** Lowercase SHA-256 of the exact source PDF bytes supplied to the call. */\n sourceSha256: string;\n provider: PdfRasterProvider;\n fillRgb: readonly [number, number, number];\n pages: readonly PdfRasterPage[];\n};\n\nexport const PDF_RASTER_CERTIFICATE_CONTRACT_VERSION = 2 as const;\n\nexport type PdfRasterRewriteCertificate = {\n contractVersion: typeof PDF_RASTER_CERTIFICATE_CONTRACT_VERSION;\n pageCount: number;\n sourceSha256: string;\n outputSha256: string;\n provider: PdfRasterProvider;\n detectionCount: number;\n manualRegionCount: number;\n mappedRegionCount: number;\n structurePixelRewriteVerified: true;\n providerAssertedCoverage: \"complete-rendering-and-ocr-observation\";\n piiCleanGuaranteed: false;\n limitation: string;\n};\n\nexport type PdfRasterRewriteResult = {\n document: Uint8Array;\n certificate: PdfRasterRewriteCertificate;\n};\n\nexport const PDF_INSPECTION_ERROR_CODES = {\n documentLimitExceeded: \"document-limit-exceeded\",\n invalidDocument: \"invalid-document\",\n invalidObservation: \"invalid-observation\",\n observationLimitExceeded: \"observation-limit-exceeded\",\n providerFailed: \"provider-failed\",\n} as const;\n\nexport type PdfInspectionErrorCode =\n (typeof PDF_INSPECTION_ERROR_CODES)[keyof typeof PDF_INSPECTION_ERROR_CODES];\n\nexport const PDF_RASTER_ERROR_CODES = {\n detectionFailed: \"detection-failed\",\n invalidContract: \"invalid-contract\",\n limitExceeded: \"limit-exceeded\",\n sourceRejected: \"source-rejected\",\n verificationFailed: \"verification-failed\",\n} as const;\n\nexport type PdfRasterErrorCode =\n (typeof PDF_RASTER_ERROR_CODES)[keyof typeof PDF_RASTER_ERROR_CODES];\n","import { PDF_RASTER_CERTIFICATE_CONTRACT_VERSION } from \"./types\";\nimport type {\n PdfGlyphObservation,\n PdfInspection,\n PdfInspectionGap,\n PdfPageInspection,\n PdfPageObservation,\n PdfRasterProvider,\n PdfRasterRewriteCertificate,\n PdfRect,\n PdfRiskInventory,\n} from \"./types\";\n\ntype RequiredFields<T> = { [Key in keyof T]-?: true };\n\nconst RECT_FIELDS = {\n left: true,\n bottom: true,\n right: true,\n top: true,\n} as const satisfies RequiredFields<PdfRect>;\n\nconst GLYPH_FIELDS = {\n start: true,\n end: true,\n bounds: true,\n source: true,\n} as const satisfies RequiredFields<PdfGlyphObservation>;\n\nconst OBSERVATION_FIELDS = {\n pageIndex: true,\n widthPoints: true,\n heightPoints: true,\n text: true,\n glyphs: true,\n rendered: true,\n textLayer: true,\n ocr: true,\n imageCount: true,\n} as const satisfies RequiredFields<PdfPageObservation>;\n\nconst PAGE_FIELDS = {\n pageIndex: true,\n widthPoints: true,\n heightPoints: true,\n annotationCount: true,\n observation: true,\n} as const satisfies RequiredFields<PdfPageInspection>;\n\nconst RISK_FIELDS = {\n acroFormFieldCount: true,\n annotationCount: true,\n documentInfoEntryCount: true,\n embeddedFileCount: true,\n externalActionCount: true,\n formXObjectCount: true,\n imageObjectCount: true,\n incrementalRevisionCount: true,\n javascriptActionCount: true,\n metadataStreamCount: true,\n optionalContentGroupCount: true,\n signatureCount: true,\n trailingNonWhitespaceByteCount: true,\n unsupportedActionCount: true,\n xfaEntryCount: true,\n} as const satisfies RequiredFields<PdfRiskInventory>;\n\nconst INSPECTION_FIELDS = {\n contractVersion: true,\n pdfVersion: true,\n byteLength: true,\n objectCount: true,\n pageCount: true,\n encrypted: true,\n pages: true,\n risks: true,\n coverage: true,\n} as const satisfies RequiredFields<PdfInspection>;\n\nconst PROVIDER_FIELDS = {\n providerId: true,\n rendererName: true,\n rendererVersion: true,\n ocrName: true,\n ocrVersion: true,\n ocrLanguage: true,\n} as const satisfies RequiredFields<PdfRasterProvider>;\n\nconst CERTIFICATE_FIELDS = {\n contractVersion: true,\n pageCount: true,\n sourceSha256: true,\n outputSha256: true,\n provider: true,\n detectionCount: true,\n manualRegionCount: true,\n mappedRegionCount: true,\n structurePixelRewriteVerified: true,\n providerAssertedCoverage: true,\n piiCleanGuaranteed: true,\n limitation: true,\n} as const satisfies RequiredFields<PdfRasterRewriteCertificate>;\n\nconst COVERAGE_FIELDS = {\n status: true,\n gaps: true,\n} as const satisfies RequiredFields<PdfInspection[\"coverage\"]>;\n\nconst INSPECTION_GAPS = {\n \"encrypted-document\": true,\n \"page-content-not-observed\": true,\n \"page-not-rendered\": true,\n \"partial-text-layer\": true,\n \"retained-document-bytes\": true,\n \"unobserved-visual-content\": true,\n} as const satisfies Record<PdfInspectionGap, true>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst hasExactFields = (\n value: Record<string, unknown>,\n fields: Record<string, true>,\n): boolean => {\n const keys = Object.keys(value);\n return (\n keys.length === Object.keys(fields).length &&\n keys.every((key) => Object.hasOwn(fields, key))\n );\n};\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value);\n\nconst isNonNegativeInteger = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n\nconst isRect = (value: unknown): value is PdfRect =>\n isRecord(value) &&\n hasExactFields(value, RECT_FIELDS) &&\n isFiniteNumber(value[\"left\"]) &&\n isFiniteNumber(value[\"bottom\"]) &&\n isFiniteNumber(value[\"right\"]) &&\n isFiniteNumber(value[\"top\"]);\n\nconst isGlyph = (value: unknown): value is PdfGlyphObservation =>\n isRecord(value) &&\n hasExactFields(value, GLYPH_FIELDS) &&\n isNonNegativeInteger(value[\"start\"]) &&\n isNonNegativeInteger(value[\"end\"]) &&\n value[\"end\"] >= value[\"start\"] &&\n isRect(value[\"bounds\"]) &&\n (value[\"source\"] === \"embedded-text\" || value[\"source\"] === \"ocr\");\n\nconst isObservation = (value: unknown): value is PdfPageObservation =>\n isRecord(value) &&\n hasExactFields(value, OBSERVATION_FIELDS) &&\n isNonNegativeInteger(value[\"pageIndex\"]) &&\n isFiniteNumber(value[\"widthPoints\"]) &&\n value[\"widthPoints\"] > 0 &&\n isFiniteNumber(value[\"heightPoints\"]) &&\n value[\"heightPoints\"] > 0 &&\n typeof value[\"text\"] === \"string\" &&\n Array.isArray(value[\"glyphs\"]) &&\n value[\"glyphs\"].every(isGlyph) &&\n typeof value[\"rendered\"] === \"boolean\" &&\n (value[\"textLayer\"] === \"absent\" ||\n value[\"textLayer\"] === \"partial\" ||\n value[\"textLayer\"] === \"complete\") &&\n (value[\"ocr\"] === \"not-run\" ||\n value[\"ocr\"] === \"partial\" ||\n value[\"ocr\"] === \"complete\") &&\n isNonNegativeInteger(value[\"imageCount\"]);\n\nconst isPage = (value: unknown): value is PdfPageInspection =>\n isRecord(value) &&\n hasExactFields(value, PAGE_FIELDS) &&\n isNonNegativeInteger(value[\"pageIndex\"]) &&\n isFiniteNumber(value[\"widthPoints\"]) &&\n value[\"widthPoints\"] > 0 &&\n isFiniteNumber(value[\"heightPoints\"]) &&\n value[\"heightPoints\"] > 0 &&\n isNonNegativeInteger(value[\"annotationCount\"]) &&\n (value[\"observation\"] === null || isObservation(value[\"observation\"]));\n\nconst isRiskInventory = (value: unknown): value is PdfRiskInventory =>\n isRecord(value) &&\n hasExactFields(value, RISK_FIELDS) &&\n Object.keys(RISK_FIELDS).every((field) => isNonNegativeInteger(value[field]));\n\nconst isInspectionGap = (value: unknown): value is PdfInspectionGap =>\n typeof value === \"string\" && Object.hasOwn(INSPECTION_GAPS, value);\n\nconst isInspection = (value: unknown): value is PdfInspection =>\n isRecord(value) &&\n hasExactFields(value, INSPECTION_FIELDS) &&\n value[\"contractVersion\"] === 1 &&\n typeof value[\"pdfVersion\"] === \"string\" &&\n isNonNegativeInteger(value[\"byteLength\"]) &&\n isNonNegativeInteger(value[\"objectCount\"]) &&\n isNonNegativeInteger(value[\"pageCount\"]) &&\n typeof value[\"encrypted\"] === \"boolean\" &&\n Array.isArray(value[\"pages\"]) &&\n value[\"pages\"].length === value[\"pageCount\"] &&\n value[\"pages\"].every(isPage) &&\n value[\"pages\"].every(({ pageIndex }, index) => pageIndex === index) &&\n isRiskInventory(value[\"risks\"]) &&\n isRecord(value[\"coverage\"]) &&\n hasExactFields(value[\"coverage\"], COVERAGE_FIELDS) &&\n (value[\"coverage\"][\"status\"] === \"full\" ||\n value[\"coverage\"][\"status\"] === \"partial\") &&\n Array.isArray(value[\"coverage\"][\"gaps\"]) &&\n value[\"coverage\"][\"gaps\"].every(isInspectionGap);\n\nconst isProvider = (value: unknown): value is PdfRasterProvider =>\n isRecord(value) &&\n hasExactFields(value, PROVIDER_FIELDS) &&\n typeof value[\"providerId\"] === \"string\" &&\n typeof value[\"rendererName\"] === \"string\" &&\n typeof value[\"rendererVersion\"] === \"string\" &&\n typeof value[\"ocrName\"] === \"string\" &&\n typeof value[\"ocrVersion\"] === \"string\" &&\n typeof value[\"ocrLanguage\"] === \"string\";\n\nconst isSha256 = (value: unknown): value is string =>\n typeof value === \"string\" && /^[a-f0-9]{64}$/u.test(value);\n\nconst isCertificate = (value: unknown): value is PdfRasterRewriteCertificate =>\n isRecord(value) &&\n hasExactFields(value, CERTIFICATE_FIELDS) &&\n value[\"contractVersion\"] === PDF_RASTER_CERTIFICATE_CONTRACT_VERSION &&\n isNonNegativeInteger(value[\"pageCount\"]) &&\n isSha256(value[\"sourceSha256\"]) &&\n isSha256(value[\"outputSha256\"]) &&\n isProvider(value[\"provider\"]) &&\n isNonNegativeInteger(value[\"detectionCount\"]) &&\n isNonNegativeInteger(value[\"manualRegionCount\"]) &&\n isNonNegativeInteger(value[\"mappedRegionCount\"]) &&\n value[\"structurePixelRewriteVerified\"] === true &&\n value[\"providerAssertedCoverage\"] ===\n \"complete-rendering-and-ocr-observation\" &&\n value[\"piiCleanGuaranteed\"] === false &&\n typeof value[\"limitation\"] === \"string\";\n\nexport const decodePdfInspection = (json: string): PdfInspection => {\n const value: unknown = JSON.parse(json);\n if (!isInspection(value)) {\n throw new Error(\"Native PDF inspection does not match contract version 1\");\n }\n return value;\n};\n\nexport const decodePdfRasterRewriteCertificate = (\n json: string,\n): PdfRasterRewriteCertificate => {\n const value: unknown = JSON.parse(json);\n if (!isCertificate(value)) {\n throw new Error(\n `Native PDF raster certificate does not match contract version ${PDF_RASTER_CERTIFICATE_CONTRACT_VERSION}`,\n );\n }\n return value;\n};\n","import { execFile } from \"node:child_process\";\nimport {\n lstat,\n mkdtemp,\n readFile,\n rm,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, sep } from \"node:path\";\n\nimport { loadNativeAnonymizeBinding } from \"@stll/anonymize\";\n\nimport { decodePdfInspection } from \"./native-codec\";\nimport type {\n PdfGlyphObservation,\n PdfPageObservation,\n PdfRasterProvider,\n} from \"./types\";\n\nconst LOCAL_PROVIDER_ID = \"poppler-tesseract-local\";\nconst PROCESS_OUTPUT_MAX_BYTES = 64 * 1024 * 1024;\nconst PDF_DOCUMENT_MAX_BYTES = 64 * 1024 * 1024;\nconst PDF_RASTER_MAX_PAGE_BYTES = 128 * 1024 * 1024;\nconst PDF_RASTER_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst PDF_MAX_PAGES = 10_000;\nconst PDF_MAX_GLYPHS = 5_000_000;\nconst PDF_MAX_OBSERVED_TEXT_UTF8_BYTES = 64 * 1024 * 1024;\nconst DEFAULT_DPI = 300;\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MIN_DPI = 72;\nconst MAX_DPI = 600;\nconst MIN_TIMEOUT_MS = 100;\nconst MAX_TIMEOUT_MS = 300_000;\nconst LANGUAGE_PACK_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/u;\nconst TEMP_PREFIX = \"stella-anonymize-pdf-\";\n\nexport const PDF_LOCAL_PROVIDER_ERROR_CODES = {\n cleanupFailed: \"cleanup-failed\",\n executableFailed: \"executable-failed\",\n invalidOptions: \"invalid-options\",\n invalidOutput: \"invalid-output\",\n limitExceeded: \"limit-exceeded\",\n sourceRejected: \"source-rejected\",\n} as const;\n\nexport type PdfLocalProviderErrorCode =\n (typeof PDF_LOCAL_PROVIDER_ERROR_CODES)[keyof typeof PDF_LOCAL_PROVIDER_ERROR_CODES];\n\nexport class PdfLocalProviderError extends Error {\n readonly code: PdfLocalProviderErrorCode;\n\n constructor(code: PdfLocalProviderErrorCode, message: string) {\n super(message);\n this.name = \"PdfLocalProviderError\";\n this.code = code;\n }\n}\n\nexport type RenderPdfWithPopplerTesseractOptions = {\n document: Uint8Array;\n /** One explicit installed Tesseract traineddata name, for example `eng`. */\n ocrLanguage: string;\n dpi?: number | undefined;\n pdftoppmPath?: string | undefined;\n tesseractPath?: string | undefined;\n timeoutMs?: number | undefined;\n};\n\nexport type LocalPdfRasterPage = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n pixels: Uint8Array;\n};\n\nexport type LocalPdfRasterObservation = {\n provider: PdfRasterProvider;\n pages: readonly LocalPdfRasterPage[];\n};\n\ntype ResolvedLocalProviderOptions = {\n dpi: number;\n ocrLanguage: string;\n pdftoppmPath: string;\n tesseractPath: string;\n timeoutMs: number;\n};\n\ntype ProcessResult = { stdout: Buffer; stderr: Buffer };\n\nconst providerError = (\n code: PdfLocalProviderErrorCode,\n message: string,\n): PdfLocalProviderError =>\n new PdfLocalProviderError(code, `${code}: ${message}`);\n\nconst validateOptions = (\n options: RenderPdfWithPopplerTesseractOptions,\n): ResolvedLocalProviderOptions => {\n const dpi = options.dpi ?? DEFAULT_DPI;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pdftoppmPath = options.pdftoppmPath ?? \"pdftoppm\";\n const tesseractPath = options.tesseractPath ?? \"tesseract\";\n if (\n !Number.isInteger(dpi) ||\n dpi < MIN_DPI ||\n dpi > MAX_DPI ||\n !Number.isInteger(timeoutMs) ||\n timeoutMs < MIN_TIMEOUT_MS ||\n timeoutMs > MAX_TIMEOUT_MS ||\n !LANGUAGE_PACK_PATTERN.test(options.ocrLanguage) ||\n !pdftoppmPath ||\n pdftoppmPath.includes(\"\\0\") ||\n !tesseractPath ||\n tesseractPath.includes(\"\\0\")\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOptions,\n \"local PDF provider options are invalid\",\n );\n }\n return {\n dpi,\n ocrLanguage: options.ocrLanguage,\n pdftoppmPath,\n tesseractPath,\n timeoutMs,\n };\n};\n\nconst runExecutable = (\n executable: string,\n args: readonly string[],\n timeoutMs: number,\n stage: \"OCR\" | \"renderer\" | \"version probe\",\n): Promise<ProcessResult> =>\n new Promise((resolve, reject) => {\n execFile(\n executable,\n args,\n {\n encoding: \"buffer\",\n maxBuffer: PROCESS_OUTPUT_MAX_BYTES,\n timeout: timeoutMs,\n windowsHide: true,\n },\n (error, stdout, stderr) => {\n if (error !== null) {\n reject(\n providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.executableFailed,\n `local PDF ${stage} failed`,\n ),\n );\n return;\n }\n resolve({ stdout: Buffer.from(stdout), stderr: Buffer.from(stderr) });\n },\n );\n });\n\nconst decodeUtf8 = (value: Uint8Array, context: string): string => {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(value);\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n `local PDF ${context} is not valid UTF-8`,\n );\n }\n};\n\nconst versionFrom = (\n value: Uint8Array,\n prefix: string,\n context: string,\n): string => {\n const line = decodeUtf8(value, context).split(/\\r?\\n/u, 1)[0]?.trim();\n const version = line?.startsWith(prefix)\n ? line.slice(prefix.length).trim()\n : \"\";\n if (!version || version.length > 256 || /\\p{Cc}/u.test(version)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n `local PDF ${context} is invalid`,\n );\n }\n return version;\n};\n\ntype InspectedPageGeometry = {\n heightPoints: number;\n widthPoints: number;\n};\n\nconst inspectPageGeometry = (\n document: Uint8Array,\n): readonly InspectedPageGeometry[] => {\n if (document.byteLength > PDF_DOCUMENT_MAX_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"PDF source exceeds its byte limit\",\n );\n }\n const inspect = loadNativeAnonymizeBinding().inspectPdfJson;\n if (inspect === undefined) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"native PDF inspection is unavailable\",\n );\n }\n try {\n const inspection = decodePdfInspection(inspect(document));\n if (\n inspection.encrypted === true ||\n inspection.pageCount < 1 ||\n inspection.pageCount > PDF_MAX_PAGES\n ) {\n throw new Error(\"source rejected\");\n }\n return inspection.pages.map(({ heightPoints, widthPoints }) => ({\n heightPoints,\n widthPoints,\n }));\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"PDF source is unsupported by the local raster provider\",\n );\n }\n};\n\nconst assertProjectedRasterLimits = (\n pages: readonly InspectedPageGeometry[],\n dpi: number,\n): void => {\n let totalBytes = 0;\n for (const { heightPoints, widthPoints } of pages) {\n const widthPixels = Math.ceil((widthPoints * dpi) / 72);\n const heightPixels = Math.ceil((heightPoints * dpi) / 72);\n const pageBytes = widthPixels * heightPixels * 3;\n totalBytes += pageBytes;\n if (\n !Number.isSafeInteger(widthPixels) ||\n !Number.isSafeInteger(heightPixels) ||\n widthPixels <= 0 ||\n heightPixels <= 0 ||\n !Number.isSafeInteger(pageBytes) ||\n pageBytes > PDF_RASTER_MAX_PAGE_BYTES ||\n !Number.isSafeInteger(totalBytes) ||\n totalBytes > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"PDF page geometry exceeds the selected DPI raster limits\",\n );\n }\n }\n};\n\ntype PpmPage = {\n width: number;\n height: number;\n pixels: Uint8Array;\n};\n\nconst isWhitespace = (byte: number): boolean =>\n byte === 0x09 ||\n byte === 0x0a ||\n byte === 0x0b ||\n byte === 0x0c ||\n byte === 0x0d ||\n byte === 0x20;\n\nconst ppmToken = (bytes: Uint8Array, start: number): [string, number] => {\n let offset = start;\n while (offset < bytes.length) {\n if (isWhitespace(bytes[offset] ?? -1)) {\n offset += 1;\n continue;\n }\n if (bytes[offset] === 0x23) {\n while (offset < bytes.length && bytes[offset] !== 0x0a) offset += 1;\n continue;\n }\n break;\n }\n const tokenStart = offset;\n while (\n offset < bytes.length &&\n !isWhitespace(bytes[offset] ?? -1) &&\n bytes[offset] !== 0x23\n ) {\n offset += 1;\n }\n if (tokenStart === offset) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM header\",\n );\n }\n const token = Buffer.from(bytes.subarray(tokenStart, offset)).toString(\n \"ascii\",\n );\n if (!/^[\\x21-\\x7e]+$/u.test(token)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM header\",\n );\n }\n return [token, offset];\n};\n\nconst parsePositiveInteger = (value: string): number => {\n if (!/^[1-9][0-9]*$/u.test(value)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted invalid PPM dimensions\",\n );\n }\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler PPM dimensions exceed their limit\",\n );\n }\n return parsed;\n};\n\nconst parsePpm = (bytes: Uint8Array): PpmPage => {\n const [magic, afterMagic] = ppmToken(bytes, 0);\n const [widthValue, afterWidth] = ppmToken(bytes, afterMagic);\n const [heightValue, afterHeight] = ppmToken(bytes, afterWidth);\n const [maximumValue, afterMaximum] = ppmToken(bytes, afterHeight);\n if (magic !== \"P6\" || maximumValue !== \"255\") {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler must emit binary RGB8 PPM pages\",\n );\n }\n const width = parsePositiveInteger(widthValue);\n const height = parsePositiveInteger(heightValue);\n const expected = width * height * 3;\n if (!Number.isSafeInteger(expected) || expected > PDF_RASTER_MAX_PAGE_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page pixels exceed their byte limit\",\n );\n }\n let pixelOffset = afterMaximum;\n if (!isWhitespace(bytes[pixelOffset] ?? -1)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted an invalid PPM pixel separator\",\n );\n }\n const separator = bytes[pixelOffset];\n pixelOffset += 1;\n if (separator === 0x0d && bytes[pixelOffset] === 0x0a) pixelOffset += 1;\n if (bytes.length - pixelOffset !== expected) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler emitted a truncated or trailing PPM page\",\n );\n }\n return { width, height, pixels: bytes.subarray(pixelOffset) };\n};\n\nconst boundedRenderedPage = async (path: string): Promise<PpmPage> => {\n const metadata = await lstat(path);\n if (!metadata.isFile() || metadata.isSymbolicLink()) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Poppler page output must be a regular file\",\n );\n }\n if (metadata.size > PDF_RASTER_MAX_PAGE_BYTES + 1024 * 1024) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page output exceeds its byte limit\",\n );\n }\n return parsePpm(await readFile(path));\n};\n\nconst integerTsvField = (value: string | undefined): number => {\n if (value === undefined || !/^(?:0|[1-9][0-9]*)$/u.test(value)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted invalid TSV geometry\",\n );\n }\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract TSV geometry exceeds its limit\",\n );\n }\n return parsed;\n};\n\nconst parseTesseractTsv = (\n bytes: Uint8Array,\n page: PpmPage,\n pageGeometry: InspectedPageGeometry,\n pageIndex: number,\n): PdfPageObservation => {\n const lines = decodeUtf8(bytes, \"Tesseract TSV\").split(/\\r?\\n/u);\n const header = lines.shift()?.split(\"\\t\");\n if (\n header?.slice(0, 12).join(\"\\t\") !==\n \"level\\tpage_num\\tblock_num\\tpar_num\\tline_num\\tword_num\\tleft\\ttop\\twidth\\theight\\tconf\\ttext\"\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted an unsupported TSV header\",\n );\n }\n const { heightPoints, widthPoints } = pageGeometry;\n const glyphs: PdfGlyphObservation[] = [];\n let text = \"\";\n let previousLine = \"\";\n for (const line of lines) {\n if (!line) continue;\n const fields = line.split(\"\\t\");\n if (fields[0] !== \"5\") continue;\n const word = fields.slice(11).join(\"\\t\").trim();\n if (!word) continue;\n if (/\\p{Cc}/u.test(word)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted control characters in OCR text\",\n );\n }\n const lineKey = `${fields[2] ?? \"\"}/${fields[3] ?? \"\"}/${fields[4] ?? \"\"}`;\n if (text) text += lineKey === previousLine ? \" \" : \"\\n\";\n previousLine = lineKey;\n const start = text.length;\n text += word;\n const end = text.length;\n const left = integerTsvField(fields[6]);\n const top = integerTsvField(fields[7]);\n const width = integerTsvField(fields[8]);\n const height = integerTsvField(fields[9]);\n const right = left + width;\n const bottom = top + height;\n if (\n width === 0 ||\n height === 0 ||\n !Number.isSafeInteger(right) ||\n !Number.isSafeInteger(bottom) ||\n right > page.width ||\n bottom > page.height\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.invalidOutput,\n \"Tesseract emitted out-of-page OCR geometry\",\n );\n }\n glyphs.push({\n start,\n end,\n bounds: {\n left: (left * widthPoints) / page.width,\n bottom: heightPoints - (bottom * heightPoints) / page.height,\n right: (right * widthPoints) / page.width,\n top: heightPoints - (top * heightPoints) / page.height,\n },\n source: \"ocr\",\n });\n if (glyphs.length > PDF_MAX_GLYPHS) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR glyph count exceeds its limit\",\n );\n }\n if (Buffer.byteLength(text, \"utf8\") > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR text exceeds its byte limit\",\n );\n }\n }\n return {\n pageIndex,\n widthPoints,\n heightPoints,\n text,\n glyphs,\n rendered: true,\n textLayer: \"absent\",\n ocr: \"complete\",\n imageCount: 0,\n };\n};\n\nconst safeCleanup = async (directory: string): Promise<void> => {\n const expectedPrefix = `${tmpdir()}${sep}${TEMP_PREFIX}`;\n if (!directory.startsWith(expectedPrefix)) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be verified\",\n );\n }\n try {\n const metadata = await lstat(directory);\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be verified\",\n );\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n if (error instanceof PdfLocalProviderError) throw error;\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary directory could not be inspected\",\n );\n }\n try {\n await rm(directory, { force: true, recursive: true });\n } catch {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF temporary files could not be removed\",\n );\n }\n};\n\nexport const renderPdfWithPopplerTesseract = async (\n options: RenderPdfWithPopplerTesseractOptions,\n): Promise<LocalPdfRasterObservation> => {\n const resolved = validateOptions(options);\n const pageGeometry = inspectPageGeometry(options.document);\n assertProjectedRasterLimits(pageGeometry, resolved.dpi);\n const pageCount = pageGeometry.length;\n const popplerVersionResult = await runExecutable(\n resolved.pdftoppmPath,\n [\"-v\"],\n resolved.timeoutMs,\n \"version probe\",\n );\n const tesseractVersionResult = await runExecutable(\n resolved.tesseractPath,\n [\"--version\"],\n resolved.timeoutMs,\n \"version probe\",\n );\n const rendererVersion = versionFrom(\n popplerVersionResult.stderr.length > 0\n ? popplerVersionResult.stderr\n : popplerVersionResult.stdout,\n \"pdftoppm version \",\n \"Poppler version\",\n );\n const ocrVersion = versionFrom(\n tesseractVersionResult.stdout.length > 0\n ? tesseractVersionResult.stdout\n : tesseractVersionResult.stderr,\n \"tesseract \",\n \"Tesseract version\",\n );\n const directory = await mkdtemp(join(tmpdir(), TEMP_PREFIX));\n try {\n const sourcePath = join(directory, \"source.pdf\");\n const outputPrefix = join(directory, \"page\");\n await writeFile(sourcePath, options.document, { flag: \"wx\", mode: 0o600 });\n const pages: LocalPdfRasterPage[] = [];\n let totalPixels = 0;\n let totalGlyphs = 0;\n let totalObservedTextUtf8Bytes = 0;\n for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {\n const inspectedGeometry = pageGeometry.at(pageNumber - 1);\n if (inspectedGeometry === undefined) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.sourceRejected,\n \"PDF page geometry became unavailable\",\n );\n }\n const pageOutputPrefix = `${outputPrefix}-${pageNumber}`;\n const pagePath = `${pageOutputPrefix}.ppm`;\n await runExecutable(\n resolved.pdftoppmPath,\n [\n \"-cropbox\",\n \"-f\",\n String(pageNumber),\n \"-l\",\n String(pageNumber),\n \"-singlefile\",\n \"-r\",\n String(resolved.dpi),\n sourcePath,\n pageOutputPrefix,\n ],\n resolved.timeoutMs,\n \"renderer\",\n );\n try {\n const page = await boundedRenderedPage(pagePath);\n totalPixels += page.pixels.byteLength;\n if (\n !Number.isSafeInteger(totalPixels) ||\n totalPixels > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Poppler page pixels exceed their aggregate limit\",\n );\n }\n const ocr = await runExecutable(\n resolved.tesseractPath,\n [pagePath, \"stdout\", \"-l\", resolved.ocrLanguage, \"tsv\"],\n resolved.timeoutMs,\n \"OCR\",\n );\n const observation = parseTesseractTsv(\n ocr.stdout,\n page,\n inspectedGeometry,\n pageNumber - 1,\n );\n totalGlyphs += observation.glyphs.length;\n totalObservedTextUtf8Bytes += Buffer.byteLength(\n observation.text,\n \"utf8\",\n );\n if (\n !Number.isSafeInteger(totalGlyphs) ||\n totalGlyphs > PDF_MAX_GLYPHS ||\n !Number.isSafeInteger(totalObservedTextUtf8Bytes) ||\n totalObservedTextUtf8Bytes > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES\n ) {\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.limitExceeded,\n \"Tesseract OCR document output exceeds its aggregate limit\",\n );\n }\n pages.push({\n observation,\n widthPixels: page.width,\n heightPixels: page.height,\n pixels: page.pixels,\n });\n } finally {\n await unlink(pagePath).catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return;\n throw providerError(\n PDF_LOCAL_PROVIDER_ERROR_CODES.cleanupFailed,\n \"local PDF page raster could not be removed\",\n );\n });\n }\n }\n return {\n provider: {\n providerId: LOCAL_PROVIDER_ID,\n rendererName: \"Poppler pdftoppm\",\n rendererVersion,\n ocrName: \"Tesseract OCR\",\n ocrVersion,\n ocrLanguage: resolved.ocrLanguage,\n },\n pages,\n };\n } finally {\n await safeCleanup(directory);\n }\n};\n","import { createHash } from \"node:crypto\";\n\nimport {\n convert_external_detection_batch,\n loadNativeAnonymizeBinding,\n type ExternalDetectionBatch,\n type PreparedNativePipeline,\n} from \"@stll/anonymize\";\n\nimport {\n PDF_INSPECTION_ERROR_CODES,\n PDF_RASTER_ERROR_CODES,\n type PdfInspection,\n type PdfInspectionErrorCode,\n type PdfPageObservation,\n type PdfRect,\n type PdfRasterProvider,\n type PdfRasterErrorCode,\n type PdfRasterRewrite,\n type PdfRasterRewriteResult,\n} from \"./types\";\nimport {\n decodePdfInspection,\n decodePdfRasterRewriteCertificate,\n} from \"./native-codec\";\n\nexport const PDF_INSPECTION_CONTRACT_VERSION = 1 as const;\nexport const PDF_RASTER_CONTRACT_VERSION = 1 as const;\nexport const PDF_RASTER_MAX_PAGE_BYTES = 128 * 1024 * 1024;\nexport const PDF_RASTER_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nexport const PDF_RASTER_MAX_MANUAL_REGIONS = 1_000_000;\nexport const PDF_RASTER_MAX_OUTPUT_BYTES = 512 * 1024 * 1024;\nexport const PDF_RASTER_REQUEST_JSON_MAX_BYTES = 64 * 1024 * 1024;\nexport const PDF_DOCUMENT_MAX_BYTES = 64 * 1024 * 1024;\nexport const PDF_STREAM_DECOMPRESSED_MAX_BYTES = 32 * 1024 * 1024;\nexport const PDF_LOADED_PAYLOAD_MAX_BYTES = 128 * 1024 * 1024;\nexport const PDF_MAX_OBJECTS = 200_000;\nexport const PDF_MAX_OBJECT_NODES = 1_000_000;\nexport const PDF_MAX_OBJECT_DEPTH = 128;\nexport const PDF_MAX_PAGES = 10_000;\nexport const PDF_MAX_GLYPHS = 5_000_000;\nexport const PDF_MAX_PAGE_TEXT_UTF8_BYTES = 16 * 1024 * 1024;\nexport const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES = 64 * 1024 * 1024;\nexport const PDF_OBSERVATIONS_JSON_MAX_BYTES = 64 * 1024 * 1024;\n/** Renderer dimensions may differ by this many points due to numeric rounding. */\nexport const PDF_PAGE_DIMENSION_TOLERANCE_POINTS = 0.25;\n\nexport class PdfInspectionError extends Error {\n readonly code: PdfInspectionErrorCode;\n\n constructor(code: PdfInspectionErrorCode, message: string) {\n super(message);\n this.name = \"PdfInspectionError\";\n this.code = code;\n }\n}\n\nexport class PdfRasterError extends Error {\n readonly code: PdfRasterErrorCode;\n\n constructor(code: PdfRasterErrorCode, message: string) {\n super(message);\n this.name = \"PdfRasterError\";\n this.code = code;\n }\n}\n\nconst errorCode = (message: string): PdfInspectionErrorCode => {\n const code = Object.values(PDF_INSPECTION_ERROR_CODES).find((candidate) =>\n message.startsWith(`${candidate}:`),\n );\n return code ?? PDF_INSPECTION_ERROR_CODES.invalidDocument;\n};\n\nconst rasterErrorCode = (message: string): PdfRasterErrorCode => {\n const code = Object.values(PDF_RASTER_ERROR_CODES).find((candidate) =>\n message.startsWith(`${candidate}:`),\n );\n return code ?? PDF_RASTER_ERROR_CODES.verificationFailed;\n};\n\nexport type InspectPdfOptions = {\n pageObservations?: readonly PdfPageObservation[];\n};\n\nexport const inspectPdf = (\n document: Uint8Array,\n options: InspectPdfOptions = {},\n): PdfInspection => {\n const inspect = loadNativeAnonymizeBinding().inspectPdfJson;\n if (inspect === undefined) {\n throw new PdfInspectionError(\n PDF_INSPECTION_ERROR_CODES.invalidDocument,\n \"Native anonymize binding does not expose PDF inspection\",\n );\n }\n try {\n const observations = options.pageObservations;\n return decodePdfInspection(\n inspect(\n document,\n observations === undefined ? undefined : JSON.stringify(observations),\n ),\n );\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"PDF inspection failed\";\n throw new PdfInspectionError(errorCode(message), message);\n }\n};\n\nexport type RewritePdfRasterFromDetectionsOptions = {\n document: Uint8Array;\n request: PdfRasterRewrite;\n /** One opaque, row-packed RGB8 buffer per request page, in page order. */\n pagePixels: readonly Uint8Array[];\n};\n\n/**\n * Advanced rewrite-only surface. It verifies structure and destructive pixels but\n * does not run detection or certify that the result is PII-free.\n */\nexport const rewritePdfRasterFromDetections = ({\n document,\n request,\n pagePixels,\n}: RewritePdfRasterFromDetectionsOptions): PdfRasterRewriteResult => {\n const rewrite =\n loadNativeAnonymizeBinding().rewritePdfRasterFromDetectionsJson;\n if (rewrite === undefined) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.verificationFailed,\n \"Native anonymize binding does not expose PDF raster rewriting\",\n );\n }\n try {\n const result = rewrite(document, JSON.stringify(request), pagePixels);\n return {\n document: result.document,\n certificate: decodePdfRasterRewriteCertificate(result.certificateJson),\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"PDF raster rewrite failed\";\n throw new PdfRasterError(rasterErrorCode(message), message);\n }\n};\n\nexport type PdfRasterObservedPageInput = {\n observation: PdfPageObservation;\n widthPixels: number;\n heightPixels: number;\n pixels: Uint8Array;\n /** Optional digest-bound provider batch merged through stella caller semantics. */\n externalDetectionBatch?: ExternalDetectionBatch | string | undefined;\n /** User-reviewed regions in normalized displayed-page PDF points. */\n manualRegions?: readonly PdfRect[] | undefined;\n};\n\nexport type AnonymizePdfRasterOptions = {\n document: Uint8Array;\n pipeline: Pick<\n PreparedNativePipeline,\n \"redactText\" | \"redactTextWithCallerDetections\"\n >;\n provider: PdfRasterProvider;\n pages: readonly PdfRasterObservedPageInput[];\n fillRgb?: readonly [number, number, number] | undefined;\n};\n\nconst sha256 = (value: Uint8Array): string =>\n createHash(\"sha256\").update(value).digest(\"hex\");\n\n/** Run stella detection, merge optional external detections, then rewrite pixels. */\nexport const anonymizePdfRaster = ({\n document,\n pipeline,\n provider,\n pages,\n fillRgb = [0, 0, 0],\n}: AnonymizePdfRasterOptions): PdfRasterRewriteResult => {\n if (document.byteLength > PDF_DOCUMENT_MAX_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF source exceeds its byte limit\",\n );\n }\n if (pages.length > PDF_MAX_PAGES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page count exceeds its limit\",\n );\n }\n let totalPixelBytes = 0;\n let totalObservedTextBytes = 0;\n let totalManualRegions = 0;\n const textEncoder = new TextEncoder();\n for (const page of pages) {\n if (typeof page.observation?.text !== \"string\") {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.invalidContract,\n \"invalid-contract: PDF raster observed text is invalid\",\n );\n }\n const observedTextBytes = textEncoder.encode(\n page.observation.text,\n ).byteLength;\n if (observedTextBytes > PDF_MAX_PAGE_TEXT_UTF8_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page text exceeds its byte limit\",\n );\n }\n totalObservedTextBytes += observedTextBytes;\n if (totalObservedTextBytes > PDF_MAX_OBSERVED_TEXT_UTF8_BYTES) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster observed text exceeds its aggregate byte limit\",\n );\n }\n const { heightPixels, widthPixels } = page;\n if (\n !Number.isSafeInteger(widthPixels) ||\n !Number.isSafeInteger(heightPixels) ||\n widthPixels <= 0 ||\n heightPixels <= 0\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.invalidContract,\n \"invalid-contract: PDF raster pixel dimensions are invalid\",\n );\n }\n const expected = widthPixels * heightPixels * 3;\n if (\n !Number.isSafeInteger(expected) ||\n expected > PDF_RASTER_MAX_PAGE_BYTES ||\n page.pixels.byteLength !== expected\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster page pixels exceed limits or have an invalid RGB8 length\",\n );\n }\n totalPixelBytes += expected;\n if (\n !Number.isSafeInteger(totalPixelBytes) ||\n totalPixelBytes > PDF_RASTER_MAX_TOTAL_BYTES\n ) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster pixels exceed their aggregate limit\",\n );\n }\n totalManualRegions += page.manualRegions?.length ?? 0;\n if (totalManualRegions > PDF_RASTER_MAX_MANUAL_REGIONS) {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.limitExceeded,\n \"limit-exceeded: PDF raster manual regions exceed their aggregate limit\",\n );\n }\n }\n const binding = loadNativeAnonymizeBinding();\n let requestPages: PdfRasterRewrite[\"pages\"];\n try {\n requestPages = pages.map((page) => {\n const external =\n page.externalDetectionBatch === undefined\n ? undefined\n : convert_external_detection_batch(\n new TextEncoder().encode(page.observation.text),\n page.externalDetectionBatch,\n { binding },\n );\n const result =\n external === undefined\n ? pipeline.redactText(page.observation.text)\n : pipeline.redactTextWithCallerDetections(page.observation.text, {\n detections: external,\n });\n return {\n observation: page.observation,\n widthPixels: page.widthPixels,\n heightPixels: page.heightPixels,\n pixelSha256: sha256(page.pixels),\n detections: result.resolvedEntities.map(({ start, end }) => ({\n start,\n end,\n })),\n manualRegions: page.manualRegions ?? [],\n };\n });\n } catch {\n throw new PdfRasterError(\n PDF_RASTER_ERROR_CODES.detectionFailed,\n \"detection-failed: PDF raster detection failed\",\n );\n }\n return rewritePdfRasterFromDetections({\n document,\n request: {\n contractVersion: PDF_RASTER_CONTRACT_VERSION,\n sourceSha256: sha256(document),\n provider,\n fillRgb,\n pages: requestPages,\n },\n pagePixels: pages.map(({ pixels }) => pixels),\n });\n};\n\nexport { PDF_INSPECTION_ERROR_CODES } from \"./types\";\nexport { PDF_RASTER_ERROR_CODES } from \"./types\";\nexport { PDF_RASTER_CERTIFICATE_CONTRACT_VERSION } from \"./types\";\nexport {\n PDF_LOCAL_PROVIDER_ERROR_CODES,\n PdfLocalProviderError,\n renderPdfWithPopplerTesseract,\n} from \"./local-provider\";\nexport type {\n LocalPdfRasterObservation,\n LocalPdfRasterPage,\n PdfLocalProviderErrorCode,\n RenderPdfWithPopplerTesseractOptions,\n} from \"./local-provider\";\nexport type {\n PdfGlyphObservation,\n PdfInspection,\n PdfInspectionErrorCode,\n PdfInspectionGap,\n PdfPageInspection,\n PdfPageObservation,\n PdfRect,\n PdfRiskInventory,\n PdfRasterDetection,\n PdfRasterErrorCode,\n PdfRasterPage,\n PdfRasterProvider,\n PdfRasterRewrite,\n PdfRasterRewriteCertificate,\n PdfRasterRewriteResult,\n} from \"./types\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/anonymize-pdf",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Fail-closed PDF coverage and risk inspection contracts for stella anonymization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"format": "oxfmt ."
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@stll/anonymize": "
|
|
35
|
+
"@stll/anonymize": "3.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^26.2.0",
|
|
39
|
-
"bun-types": "1.4.
|
|
39
|
+
"bun-types": "1.4.1",
|
|
40
40
|
"tsdown": "0.22.14",
|
|
41
41
|
"typescript": "7.0.2"
|
|
42
42
|
}
|