@stll/anonymize-pdf 2.9.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/index.d.mts +41 -34
- package/dist/index.mjs +11 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
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
|
+
export 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";
|
|
@@ -114,7 +118,7 @@ type PdfRasterRewriteResult = {
|
|
|
114
118
|
document: Uint8Array;
|
|
115
119
|
certificate: PdfRasterRewriteCertificate;
|
|
116
120
|
};
|
|
117
|
-
declare const PDF_INSPECTION_ERROR_CODES: {
|
|
121
|
+
export declare const PDF_INSPECTION_ERROR_CODES: {
|
|
118
122
|
readonly documentLimitExceeded: "document-limit-exceeded";
|
|
119
123
|
readonly invalidDocument: "invalid-document";
|
|
120
124
|
readonly invalidObservation: "invalid-observation";
|
|
@@ -122,7 +126,7 @@ declare const PDF_INSPECTION_ERROR_CODES: {
|
|
|
122
126
|
readonly providerFailed: "provider-failed";
|
|
123
127
|
};
|
|
124
128
|
type PdfInspectionErrorCode = (typeof PDF_INSPECTION_ERROR_CODES)[keyof typeof PDF_INSPECTION_ERROR_CODES];
|
|
125
|
-
declare const PDF_RASTER_ERROR_CODES: {
|
|
129
|
+
export declare const PDF_RASTER_ERROR_CODES: {
|
|
126
130
|
readonly detectionFailed: "detection-failed";
|
|
127
131
|
readonly invalidContract: "invalid-contract";
|
|
128
132
|
readonly limitExceeded: "limit-exceeded";
|
|
@@ -132,7 +136,7 @@ declare const PDF_RASTER_ERROR_CODES: {
|
|
|
132
136
|
type PdfRasterErrorCode = (typeof PDF_RASTER_ERROR_CODES)[keyof typeof PDF_RASTER_ERROR_CODES];
|
|
133
137
|
//#endregion
|
|
134
138
|
//#region src/local-provider.d.ts
|
|
135
|
-
declare const PDF_LOCAL_PROVIDER_ERROR_CODES: {
|
|
139
|
+
export declare const PDF_LOCAL_PROVIDER_ERROR_CODES: {
|
|
136
140
|
readonly cleanupFailed: "cleanup-failed";
|
|
137
141
|
readonly executableFailed: "executable-failed";
|
|
138
142
|
readonly invalidOptions: "invalid-options";
|
|
@@ -141,7 +145,7 @@ declare const PDF_LOCAL_PROVIDER_ERROR_CODES: {
|
|
|
141
145
|
readonly sourceRejected: "source-rejected";
|
|
142
146
|
};
|
|
143
147
|
type PdfLocalProviderErrorCode = (typeof PDF_LOCAL_PROVIDER_ERROR_CODES)[keyof typeof PDF_LOCAL_PROVIDER_ERROR_CODES];
|
|
144
|
-
declare class PdfLocalProviderError extends Error {
|
|
148
|
+
export declare class PdfLocalProviderError extends Error {
|
|
145
149
|
readonly code: PdfLocalProviderErrorCode;
|
|
146
150
|
constructor(code: PdfLocalProviderErrorCode, message: string);
|
|
147
151
|
}
|
|
@@ -164,41 +168,42 @@ type LocalPdfRasterObservation = {
|
|
|
164
168
|
provider: PdfRasterProvider;
|
|
165
169
|
pages: readonly LocalPdfRasterPage[];
|
|
166
170
|
};
|
|
167
|
-
declare const renderPdfWithPopplerTesseract: (options: RenderPdfWithPopplerTesseractOptions) => Promise<LocalPdfRasterObservation>;
|
|
171
|
+
export declare const renderPdfWithPopplerTesseract: (options: RenderPdfWithPopplerTesseractOptions) => Promise<LocalPdfRasterObservation>;
|
|
168
172
|
//#endregion
|
|
169
173
|
//#region src/index.d.ts
|
|
170
|
-
declare const PDF_INSPECTION_CONTRACT_VERSION: 1;
|
|
171
|
-
declare const PDF_RASTER_CONTRACT_VERSION: 1;
|
|
172
|
-
declare const PDF_RASTER_MAX_PAGE_BYTES: number;
|
|
173
|
-
declare const PDF_RASTER_MAX_TOTAL_BYTES: number;
|
|
174
|
-
declare const
|
|
175
|
-
declare const
|
|
176
|
-
declare const
|
|
177
|
-
declare const
|
|
178
|
-
declare const
|
|
179
|
-
declare const
|
|
180
|
-
declare const
|
|
181
|
-
declare const
|
|
182
|
-
declare const
|
|
183
|
-
declare const
|
|
184
|
-
declare const
|
|
185
|
-
declare const
|
|
186
|
-
declare const
|
|
174
|
+
export declare const PDF_INSPECTION_CONTRACT_VERSION: 1;
|
|
175
|
+
export declare const PDF_RASTER_CONTRACT_VERSION: 1;
|
|
176
|
+
export declare const PDF_RASTER_MAX_PAGE_BYTES: number;
|
|
177
|
+
export declare const PDF_RASTER_MAX_TOTAL_BYTES: number;
|
|
178
|
+
export declare const PDF_RASTER_MAX_MANUAL_REGIONS = 1000000;
|
|
179
|
+
export declare const PDF_RASTER_MAX_OUTPUT_BYTES: number;
|
|
180
|
+
export declare const PDF_RASTER_REQUEST_JSON_MAX_BYTES: number;
|
|
181
|
+
export declare const PDF_DOCUMENT_MAX_BYTES: number;
|
|
182
|
+
export declare const PDF_STREAM_DECOMPRESSED_MAX_BYTES: number;
|
|
183
|
+
export declare const PDF_LOADED_PAYLOAD_MAX_BYTES: number;
|
|
184
|
+
export declare const PDF_MAX_OBJECTS = 200000;
|
|
185
|
+
export declare const PDF_MAX_OBJECT_NODES = 1000000;
|
|
186
|
+
export declare const PDF_MAX_OBJECT_DEPTH = 128;
|
|
187
|
+
export declare const PDF_MAX_PAGES = 10000;
|
|
188
|
+
export declare const PDF_MAX_GLYPHS = 5000000;
|
|
189
|
+
export declare const PDF_MAX_PAGE_TEXT_UTF8_BYTES: number;
|
|
190
|
+
export declare const PDF_MAX_OBSERVED_TEXT_UTF8_BYTES: number;
|
|
191
|
+
export declare const PDF_OBSERVATIONS_JSON_MAX_BYTES: number;
|
|
187
192
|
/** Renderer dimensions may differ by this many points due to numeric rounding. */
|
|
188
|
-
declare const PDF_PAGE_DIMENSION_TOLERANCE_POINTS = 0.25;
|
|
189
|
-
declare class PdfInspectionError extends Error {
|
|
193
|
+
export declare const PDF_PAGE_DIMENSION_TOLERANCE_POINTS = 0.25;
|
|
194
|
+
export declare class PdfInspectionError extends Error {
|
|
190
195
|
readonly code: PdfInspectionErrorCode;
|
|
191
196
|
constructor(code: PdfInspectionErrorCode, message: string);
|
|
192
197
|
}
|
|
193
|
-
declare class PdfRasterError extends Error {
|
|
198
|
+
export declare class PdfRasterError extends Error {
|
|
194
199
|
readonly code: PdfRasterErrorCode;
|
|
195
200
|
constructor(code: PdfRasterErrorCode, message: string);
|
|
196
201
|
}
|
|
197
|
-
type InspectPdfOptions = {
|
|
202
|
+
export type InspectPdfOptions = {
|
|
198
203
|
pageObservations?: readonly PdfPageObservation[];
|
|
199
204
|
};
|
|
200
|
-
declare const inspectPdf: (document: Uint8Array, options?: InspectPdfOptions) => PdfInspection;
|
|
201
|
-
type RewritePdfRasterFromDetectionsOptions = {
|
|
205
|
+
export declare const inspectPdf: (document: Uint8Array, options?: InspectPdfOptions) => PdfInspection;
|
|
206
|
+
export type RewritePdfRasterFromDetectionsOptions = {
|
|
202
207
|
document: Uint8Array;
|
|
203
208
|
request: PdfRasterRewrite;
|
|
204
209
|
/** One opaque, row-packed RGB8 buffer per request page, in page order. */
|
|
@@ -208,16 +213,18 @@ type RewritePdfRasterFromDetectionsOptions = {
|
|
|
208
213
|
* Advanced rewrite-only surface. It verifies structure and destructive pixels but
|
|
209
214
|
* does not run detection or certify that the result is PII-free.
|
|
210
215
|
*/
|
|
211
|
-
declare const rewritePdfRasterFromDetections: ({ document, request, pagePixels }: RewritePdfRasterFromDetectionsOptions) => PdfRasterRewriteResult;
|
|
212
|
-
type PdfRasterObservedPageInput = {
|
|
216
|
+
export declare const rewritePdfRasterFromDetections: ({ document, request, pagePixels }: RewritePdfRasterFromDetectionsOptions) => PdfRasterRewriteResult;
|
|
217
|
+
export type PdfRasterObservedPageInput = {
|
|
213
218
|
observation: PdfPageObservation;
|
|
214
219
|
widthPixels: number;
|
|
215
220
|
heightPixels: number;
|
|
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
|
-
type AnonymizePdfRasterOptions = {
|
|
227
|
+
export type AnonymizePdfRasterOptions = {
|
|
221
228
|
document: Uint8Array;
|
|
222
229
|
pipeline: Pick<PreparedNativePipeline, "redactText" | "redactTextWithCallerDetections">;
|
|
223
230
|
provider: PdfRasterProvider;
|
|
@@ -225,7 +232,7 @@ type AnonymizePdfRasterOptions = {
|
|
|
225
232
|
fillRgb?: readonly [number, number, number] | undefined;
|
|
226
233
|
};
|
|
227
234
|
/** Run stella detection, merge optional external detections, then rewrite pixels. */
|
|
228
|
-
declare const anonymizePdfRaster: ({ document, pipeline, provider, pages, fillRgb }: AnonymizePdfRasterOptions) => PdfRasterRewriteResult;
|
|
235
|
+
export declare const anonymizePdfRaster: ({ document, pipeline, provider, pages, fillRgb }: AnonymizePdfRasterOptions) => PdfRasterRewriteResult;
|
|
229
236
|
//#endregion
|
|
230
|
-
export {
|
|
237
|
+
export type { LocalPdfRasterObservation, LocalPdfRasterPage, PdfGlyphObservation, PdfInspection, PdfInspectionErrorCode, PdfInspectionGap, PdfLocalProviderErrorCode, PdfPageInspection, PdfPageObservation, PdfRasterDetection, PdfRasterErrorCode, PdfRasterPage, PdfRasterProvider, PdfRasterRewrite, PdfRasterRewriteCertificate, PdfRasterRewriteResult, PdfRect, PdfRiskInventory, RenderPdfWithPopplerTesseractOptions };
|
|
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,7 +138,7 @@ 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
|
|
@@ -464,6 +466,7 @@ const PDF_INSPECTION_CONTRACT_VERSION = 1;
|
|
|
464
466
|
const PDF_RASTER_CONTRACT_VERSION = 1;
|
|
465
467
|
const PDF_RASTER_MAX_PAGE_BYTES = 134217728;
|
|
466
468
|
const PDF_RASTER_MAX_TOTAL_BYTES = 536870912;
|
|
469
|
+
const PDF_RASTER_MAX_MANUAL_REGIONS = 1e6;
|
|
467
470
|
const PDF_RASTER_MAX_OUTPUT_BYTES = 536870912;
|
|
468
471
|
const PDF_RASTER_REQUEST_JSON_MAX_BYTES = 67108864;
|
|
469
472
|
const PDF_DOCUMENT_MAX_BYTES = 67108864;
|
|
@@ -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.1",
|
|
4
4
|
"description": "Fail-closed PDF coverage and risk inspection contracts for stella anonymization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"format": "oxfmt ."
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@stll/anonymize": "
|
|
35
|
+
"@stll/anonymize": "3.0.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^26.
|
|
39
|
-
"bun-types": "1.4.
|
|
40
|
-
"tsdown": "0.
|
|
38
|
+
"@types/node": "^26.4.1",
|
|
39
|
+
"bun-types": "1.4.2",
|
|
40
|
+
"tsdown": "0.23.0",
|
|
41
41
|
"typescript": "7.0.2"
|
|
42
42
|
}
|
|
43
43
|
}
|