pdf-oxide-fips 0.3.47

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.
Files changed (127) hide show
  1. package/LICENSE-APACHE +176 -0
  2. package/LICENSE-MIT +25 -0
  3. package/README.md +218 -0
  4. package/lib/builders/annotation-builder.d.ts +198 -0
  5. package/lib/builders/annotation-builder.js +317 -0
  6. package/lib/builders/conversion-options-builder.d.ts +106 -0
  7. package/lib/builders/conversion-options-builder.js +214 -0
  8. package/lib/builders/document-builder.d.ts +381 -0
  9. package/lib/builders/document-builder.js +770 -0
  10. package/lib/builders/index.d.ts +13 -0
  11. package/lib/builders/index.js +13 -0
  12. package/lib/builders/metadata-builder.d.ts +201 -0
  13. package/lib/builders/metadata-builder.js +285 -0
  14. package/lib/builders/pdf-builder.d.ts +216 -0
  15. package/lib/builders/pdf-builder.js +350 -0
  16. package/lib/builders/search-options-builder.d.ts +73 -0
  17. package/lib/builders/search-options-builder.js +129 -0
  18. package/lib/builders/streaming-table.d.ts +64 -0
  19. package/lib/builders/streaming-table.js +140 -0
  20. package/lib/document-editor-manager.d.ts +139 -0
  21. package/lib/document-editor-manager.js +256 -0
  22. package/lib/document-editor.d.ts +124 -0
  23. package/lib/document-editor.js +318 -0
  24. package/lib/errors.d.ts +382 -0
  25. package/lib/errors.js +1115 -0
  26. package/lib/form-field-manager.d.ts +299 -0
  27. package/lib/form-field-manager.js +568 -0
  28. package/lib/hybrid-ml-manager.d.ts +142 -0
  29. package/lib/hybrid-ml-manager.js +208 -0
  30. package/lib/index.d.ts +205 -0
  31. package/lib/index.js +693 -0
  32. package/lib/managers/accessibility-manager.d.ts +148 -0
  33. package/lib/managers/accessibility-manager.js +234 -0
  34. package/lib/managers/annotation-manager.d.ts +219 -0
  35. package/lib/managers/annotation-manager.js +359 -0
  36. package/lib/managers/barcode-manager.d.ts +82 -0
  37. package/lib/managers/barcode-manager.js +263 -0
  38. package/lib/managers/batch-manager.d.ts +185 -0
  39. package/lib/managers/batch-manager.js +385 -0
  40. package/lib/managers/cache-manager.d.ts +181 -0
  41. package/lib/managers/cache-manager.js +384 -0
  42. package/lib/managers/compliance-manager.d.ts +103 -0
  43. package/lib/managers/compliance-manager.js +453 -0
  44. package/lib/managers/content-manager.d.ts +120 -0
  45. package/lib/managers/content-manager.js +294 -0
  46. package/lib/managers/document-utility-manager.d.ts +369 -0
  47. package/lib/managers/document-utility-manager.js +730 -0
  48. package/lib/managers/dom-pdf-creator.d.ts +104 -0
  49. package/lib/managers/dom-pdf-creator.js +299 -0
  50. package/lib/managers/editing-manager.d.ts +248 -0
  51. package/lib/managers/editing-manager.js +387 -0
  52. package/lib/managers/enterprise-manager.d.ts +192 -0
  53. package/lib/managers/enterprise-manager.js +307 -0
  54. package/lib/managers/extended-managers.d.ts +122 -0
  55. package/lib/managers/extended-managers.js +664 -0
  56. package/lib/managers/extraction-manager.d.ts +246 -0
  57. package/lib/managers/extraction-manager.js +482 -0
  58. package/lib/managers/final-utilities.d.ts +127 -0
  59. package/lib/managers/final-utilities.js +657 -0
  60. package/lib/managers/hybrid-ml-advanced.d.ts +136 -0
  61. package/lib/managers/hybrid-ml-advanced.js +722 -0
  62. package/lib/managers/index.d.ts +64 -0
  63. package/lib/managers/index.js +69 -0
  64. package/lib/managers/layer-manager.d.ts +203 -0
  65. package/lib/managers/layer-manager.js +401 -0
  66. package/lib/managers/metadata-manager.d.ts +148 -0
  67. package/lib/managers/metadata-manager.js +280 -0
  68. package/lib/managers/ocr-manager.d.ts +194 -0
  69. package/lib/managers/ocr-manager.js +582 -0
  70. package/lib/managers/optimization-manager.d.ts +102 -0
  71. package/lib/managers/optimization-manager.js +213 -0
  72. package/lib/managers/outline-manager.d.ts +101 -0
  73. package/lib/managers/outline-manager.js +169 -0
  74. package/lib/managers/page-manager.d.ts +142 -0
  75. package/lib/managers/page-manager.js +235 -0
  76. package/lib/managers/pattern-detection.d.ts +169 -0
  77. package/lib/managers/pattern-detection.js +322 -0
  78. package/lib/managers/rendering-manager.d.ts +353 -0
  79. package/lib/managers/rendering-manager.js +679 -0
  80. package/lib/managers/search-manager.d.ts +235 -0
  81. package/lib/managers/search-manager.js +329 -0
  82. package/lib/managers/security-manager.d.ts +161 -0
  83. package/lib/managers/security-manager.js +292 -0
  84. package/lib/managers/signature-manager.d.ts +738 -0
  85. package/lib/managers/signature-manager.js +1509 -0
  86. package/lib/managers/streams.d.ts +262 -0
  87. package/lib/managers/streams.js +477 -0
  88. package/lib/managers/xfa-manager.d.ts +227 -0
  89. package/lib/managers/xfa-manager.js +539 -0
  90. package/lib/native-loader.d.ts +7 -0
  91. package/lib/native-loader.js +62 -0
  92. package/lib/native.d.ts +16 -0
  93. package/lib/native.js +69 -0
  94. package/lib/pdf-creator-manager.d.ts +200 -0
  95. package/lib/pdf-creator-manager.js +381 -0
  96. package/lib/properties.d.ts +79 -0
  97. package/lib/properties.js +454 -0
  98. package/lib/result-accessors-manager.d.ts +346 -0
  99. package/lib/result-accessors-manager.js +706 -0
  100. package/lib/thumbnail-manager.d.ts +121 -0
  101. package/lib/thumbnail-manager.js +205 -0
  102. package/lib/timestamp.d.ts +54 -0
  103. package/lib/timestamp.js +115 -0
  104. package/lib/tsa-client.d.ts +44 -0
  105. package/lib/tsa-client.js +67 -0
  106. package/lib/types/common.d.ts +189 -0
  107. package/lib/types/common.js +17 -0
  108. package/lib/types/document-types.d.ts +352 -0
  109. package/lib/types/document-types.js +82 -0
  110. package/lib/types/index.d.ts +5 -0
  111. package/lib/types/index.js +5 -0
  112. package/lib/types/manager-types.d.ts +179 -0
  113. package/lib/types/manager-types.js +100 -0
  114. package/lib/types/native-bindings.d.ts +439 -0
  115. package/lib/types/native-bindings.js +7 -0
  116. package/lib/workers/index.d.ts +6 -0
  117. package/lib/workers/index.js +5 -0
  118. package/lib/workers/pool.d.ts +64 -0
  119. package/lib/workers/pool.js +192 -0
  120. package/lib/workers/worker.d.ts +5 -0
  121. package/lib/workers/worker.js +99 -0
  122. package/package.json +79 -0
  123. package/prebuilds/darwin-arm64/pdf_oxide.node +0 -0
  124. package/prebuilds/darwin-x64/pdf_oxide.node +0 -0
  125. package/prebuilds/linux-arm64/pdf_oxide.node +0 -0
  126. package/prebuilds/linux-x64/pdf_oxide.node +0 -0
  127. package/prebuilds/win32-x64/pdf_oxide.node +0 -0
@@ -0,0 +1,256 @@
1
+ /**
2
+ * DocumentEditorManager for PDF document editing operations
3
+ *
4
+ * Provides methods to edit and modify PDF documents including page operations,
5
+ * content manipulation, and document merging. API is consistent with Python,
6
+ * Java, C#, Go, and Swift implementations.
7
+ */
8
+ import { EventEmitter } from 'events';
9
+ /**
10
+ * Page rotation options
11
+ */
12
+ export var PageRotation;
13
+ (function (PageRotation) {
14
+ PageRotation[PageRotation["None"] = 0] = "None";
15
+ PageRotation[PageRotation["Rotate90"] = 90] = "Rotate90";
16
+ PageRotation[PageRotation["Rotate180"] = 180] = "Rotate180";
17
+ PageRotation[PageRotation["Rotate270"] = 270] = "Rotate270";
18
+ })(PageRotation || (PageRotation = {}));
19
+ /**
20
+ * Document Editor Manager for document manipulation
21
+ *
22
+ * Provides methods to:
23
+ * - Delete, insert, and reorder pages
24
+ * - Rotate pages
25
+ * - Extract page ranges to new documents
26
+ * - Merge multiple documents
27
+ * - Track edit history
28
+ */
29
+ export class DocumentEditorManager extends EventEmitter {
30
+ constructor(document) {
31
+ super();
32
+ this.editHistory = [];
33
+ this.hasUnsavedChanges = false;
34
+ if (!document) {
35
+ throw new Error('Document is required');
36
+ }
37
+ this.document = document;
38
+ }
39
+ /**
40
+ * Deletes a page from the document
41
+ * Matches: Python deletePage(), Java deletePage(), C# DeletePage()
42
+ */
43
+ async deletePage(pageIndex) {
44
+ this.validatePageIndex(pageIndex);
45
+ try {
46
+ if (this.document?.removePage) {
47
+ this.document.removePage(pageIndex);
48
+ }
49
+ this.recordOperation('deletePage', { pageIndex });
50
+ this.emit('pageDeleted', pageIndex);
51
+ }
52
+ catch (error) {
53
+ this.emit('error', error);
54
+ throw error;
55
+ }
56
+ }
57
+ /**
58
+ * Deletes multiple pages from the document
59
+ * Matches: Python deletePages(), Java deletePages(), C# DeletePages()
60
+ */
61
+ async deletePages(pageIndices) {
62
+ // Sort in descending order to avoid index shifting issues
63
+ const sorted = [...pageIndices].sort((a, b) => b - a);
64
+ for (const pageIndex of sorted) {
65
+ await this.deletePage(pageIndex);
66
+ }
67
+ }
68
+ /**
69
+ * Inserts a blank page at the specified position
70
+ * Matches: Python insertBlankPage(), Java insertBlankPage(), C# InsertBlankPage()
71
+ */
72
+ async insertBlankPage(pageIndex, width = 612, height = 792) {
73
+ try {
74
+ if (this.document?.insertPage) {
75
+ this.document.insertPage(pageIndex, width, height);
76
+ }
77
+ this.recordOperation('insertBlankPage', { pageIndex, width, height });
78
+ this.emit('pageInserted', pageIndex);
79
+ }
80
+ catch (error) {
81
+ this.emit('error', error);
82
+ throw error;
83
+ }
84
+ }
85
+ /**
86
+ * Rotates a page by the specified angle
87
+ * Matches: Python rotatePage(), Java rotatePage(), C# RotatePage()
88
+ */
89
+ async rotatePage(pageIndex, rotation) {
90
+ this.validatePageIndex(pageIndex);
91
+ try {
92
+ if (this.document?.rotatePage) {
93
+ this.document.rotatePage(pageIndex, rotation);
94
+ }
95
+ this.recordOperation('rotatePage', { pageIndex, rotation });
96
+ this.emit('pageRotated', pageIndex, rotation);
97
+ }
98
+ catch (error) {
99
+ this.emit('error', error);
100
+ throw error;
101
+ }
102
+ }
103
+ /**
104
+ * Rotates multiple pages
105
+ * Matches: Python rotatePages(), Java rotatePages(), C# RotatePages()
106
+ */
107
+ async rotatePages(pageIndices, rotation) {
108
+ for (const pageIndex of pageIndices) {
109
+ await this.rotatePage(pageIndex, rotation);
110
+ }
111
+ }
112
+ /**
113
+ * Moves a page to a new position
114
+ * Matches: Python movePage(), Java movePage(), C# MovePage()
115
+ */
116
+ async movePage(fromIndex, toIndex) {
117
+ this.validatePageIndex(fromIndex);
118
+ this.validatePageIndex(toIndex);
119
+ try {
120
+ // Implement move by extracting and re-inserting
121
+ if (this.document?.getPage && this.document?.removePage && this.document?.insertPage) {
122
+ const page = this.document.getPage(fromIndex);
123
+ this.document.removePage(fromIndex);
124
+ // Note: After removal, toIndex may need adjustment
125
+ const adjustedIndex = toIndex > fromIndex ? toIndex - 1 : toIndex;
126
+ if (page) {
127
+ this.document.insertPage(adjustedIndex, page.getWidth?.(), page.getHeight?.());
128
+ }
129
+ }
130
+ this.recordOperation('movePage', { fromIndex, toIndex });
131
+ this.emit('pageMoved', fromIndex, toIndex);
132
+ }
133
+ catch (error) {
134
+ this.emit('error', error);
135
+ throw error;
136
+ }
137
+ }
138
+ /**
139
+ * Extracts pages to a new document
140
+ * Matches: Python extractPages(), Java extractPages(), C# ExtractPages()
141
+ */
142
+ async extractPages(config) {
143
+ const { startPage, endPage } = config;
144
+ this.validatePageIndex(startPage);
145
+ this.validatePageIndex(endPage);
146
+ // FFI call placeholder
147
+ // const newDoc = await FFI.extractPages(this.document.handle, startPage, endPage);
148
+ this.recordOperation('extractPages', { startPage, endPage });
149
+ this.emit('pagesExtracted', startPage, endPage);
150
+ return null; // Placeholder - would return new document
151
+ }
152
+ /**
153
+ * Merges multiple documents into one
154
+ * Matches: Python mergeDocuments(), Java mergeDocuments(), C# MergeDocuments()
155
+ */
156
+ static async mergeDocuments(config) {
157
+ const { documents, preserveOutlines = true, preserveAnnotations = true } = config;
158
+ if (!documents || documents.length === 0) {
159
+ throw new Error('At least one document is required for merging');
160
+ }
161
+ // FFI call placeholder
162
+ // const merged = await FFI.mergeDocuments(documents, preserveOutlines, preserveAnnotations);
163
+ return null; // Placeholder - would return merged document
164
+ }
165
+ /**
166
+ * Saves the document with all modifications
167
+ * Matches: Python save(), Java save(), C# Save()
168
+ */
169
+ async save(outputPath) {
170
+ try {
171
+ if (outputPath) {
172
+ // Save to file path
173
+ if (this.document?.save_async) {
174
+ await this.document.save_async(outputPath);
175
+ }
176
+ else if (this.document?.saveToPath) {
177
+ this.document.saveToPath(outputPath);
178
+ }
179
+ }
180
+ else {
181
+ // Save changes to current document
182
+ if (this.document?.save_async) {
183
+ await this.document.save_async(this.document.filePath || 'output.pdf');
184
+ }
185
+ }
186
+ this.hasUnsavedChanges = false;
187
+ this.emit('saved', outputPath);
188
+ }
189
+ catch (error) {
190
+ this.emit('error', error);
191
+ throw error;
192
+ }
193
+ }
194
+ /**
195
+ * Gets the edit history
196
+ * Matches: Python getEditHistory(), Java getEditHistory(), C# GetEditHistory()
197
+ */
198
+ getEditHistory() {
199
+ return [...this.editHistory];
200
+ }
201
+ /**
202
+ * Checks if there are unsaved changes
203
+ * Matches: Python hasUnsavedChanges(), Java hasUnsavedChanges(), C# HasUnsavedChanges()
204
+ */
205
+ hasChanges() {
206
+ return this.hasUnsavedChanges;
207
+ }
208
+ /**
209
+ * Undoes the last operation (if supported)
210
+ * Matches: Python undo(), Java undo(), C# Undo()
211
+ */
212
+ async undo() {
213
+ if (this.editHistory.length === 0) {
214
+ return false;
215
+ }
216
+ // Placeholder - would implement undo logic
217
+ this.editHistory.pop();
218
+ this.emit('undone');
219
+ return true;
220
+ }
221
+ /**
222
+ * Clears the edit history
223
+ * Matches: Python clearHistory(), Java clearHistory(), C# ClearHistory()
224
+ */
225
+ clearHistory() {
226
+ this.editHistory = [];
227
+ this.emit('historyCleared');
228
+ }
229
+ /**
230
+ * Gets the page count after modifications
231
+ */
232
+ getPageCount() {
233
+ try {
234
+ return this.document.pageCount || 0;
235
+ }
236
+ catch {
237
+ return 0;
238
+ }
239
+ }
240
+ // Private helper methods
241
+ validatePageIndex(pageIndex) {
242
+ const count = this.getPageCount();
243
+ if (pageIndex < 0 || pageIndex >= count) {
244
+ throw new Error(`Invalid page index: ${pageIndex}. Document has ${count} pages.`);
245
+ }
246
+ }
247
+ recordOperation(type, details) {
248
+ this.editHistory.push({
249
+ type,
250
+ timestamp: new Date(),
251
+ details,
252
+ });
253
+ this.hasUnsavedChanges = true;
254
+ }
255
+ }
256
+ export default DocumentEditorManager;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Page rotation angles valid for {@link DocumentEditor.setPageRotation}.
3
+ */
4
+ export type PageRotation = 0 | 90 | 180 | 270;
5
+ /**
6
+ * PDF editor bound to a concrete file on disk. Open via
7
+ * {@link DocumentEditor.open}; always pair with {@link close} (or use
8
+ * `using` / the explicit-resource-management protocol once it's
9
+ * stable in your toolchain).
10
+ */
11
+ export declare class DocumentEditor {
12
+ private _handle;
13
+ private _closed;
14
+ private constructor();
15
+ /** Open a PDF file for editing. */
16
+ static open(path: string): DocumentEditor;
17
+ /** Open a PDF from an in-memory buffer for editing. */
18
+ static openFromBytes(data: Buffer | Uint8Array): DocumentEditor;
19
+ /** True if the editor has been closed. Subsequent calls will throw. */
20
+ get closed(): boolean;
21
+ private _throwIfClosed;
22
+ /** Current page count. */
23
+ pageCount(): number;
24
+ /** True if the editor has unsaved modifications. */
25
+ isModified(): boolean;
26
+ setTitle(title: string): void;
27
+ setAuthor(author: string): void;
28
+ setSubject(subject: string): void;
29
+ getKeywords(): string | null;
30
+ setKeywords(keywords: string): void;
31
+ getProducer(): string;
32
+ setProducer(producer: string): void;
33
+ getCreationDate(): string;
34
+ setCreationDate(date: string): void;
35
+ /** Delete the page at `pageIndex` (zero-based). */
36
+ deletePage(pageIndex: number): void;
37
+ /** Move a page. Indices refer to positions before the move. */
38
+ movePage(fromIndex: number, toIndex: number): void;
39
+ /** Set rotation on a page (0/90/180/270). */
40
+ setPageRotation(pageIndex: number, degrees: PageRotation): void;
41
+ /**
42
+ * Append every page of another PDF to the end of this document.
43
+ */
44
+ mergeFrom(sourcePath: string): void;
45
+ /** Flatten form fields across the entire document. */
46
+ flattenForms(): void;
47
+ /**
48
+ * Return warnings collected during the last form-flattening save.
49
+ * Each entry names a widget field that had no `/AP` appearance stream;
50
+ * flattening it produces a blank rectangle.
51
+ */
52
+ flattenWarnings(): string[];
53
+ /** Flatten annotations. If `pageIndex` is omitted, flattens all pages. */
54
+ flattenAnnotations(pageIndex?: number): void;
55
+ /** Set a form field value by fully-qualified field name. */
56
+ setFormFieldValue(fieldName: string, value: string): void;
57
+ /** Import an FDF file (bytes) into the document's form. */
58
+ importFdfBytes(fdf: Buffer | Uint8Array): void;
59
+ /** Import an XFDF file (bytes) into the document's form. */
60
+ importXfdfBytes(xfdf: Buffer | Uint8Array): void;
61
+ /**
62
+ * Append every page of another PDF (supplied as bytes) to this document.
63
+ * Returns the number of pages added.
64
+ */
65
+ mergeFromBytes(data: Buffer | Uint8Array): number;
66
+ /** Embed a file attachment into the document. */
67
+ embedFile(name: string, data: Buffer | Uint8Array): void;
68
+ /** Burn in redaction annotations on a single page (zero-based). */
69
+ applyPageRedactions(pageIndex: number): void;
70
+ /** Burn in all pending redaction annotations across the document. */
71
+ applyAllRedactions(): void;
72
+ /** Rotate all pages by `degrees` (additive). */
73
+ rotateAllPages(degrees: number): void;
74
+ /** Rotate a single page by `degrees` (additive). */
75
+ rotatePageBy(pageIndex: number, degrees: number): void;
76
+ /** Get the MediaBox of a page as `{x, y, width, height}`. */
77
+ getPageMediaBox(pageIndex: number): {
78
+ x: number;
79
+ y: number;
80
+ width: number;
81
+ height: number;
82
+ };
83
+ /** Set the MediaBox of a page. */
84
+ setPageMediaBox(pageIndex: number, x: number, y: number, width: number, height: number): void;
85
+ /** Get the CropBox of a page. Returns `{x:0,y:0,width:0,height:0}` if none set. */
86
+ getPageCropBox(pageIndex: number): {
87
+ x: number;
88
+ y: number;
89
+ width: number;
90
+ height: number;
91
+ };
92
+ /** Set the CropBox of a page. */
93
+ setPageCropBox(pageIndex: number, x: number, y: number, width: number, height: number): void;
94
+ /**
95
+ * Erase rectangular regions on a page.
96
+ * `rects` is an array of `[x, y, w, h]` tuples.
97
+ */
98
+ eraseRegions(pageIndex: number, rects: [number, number, number, number][]): void;
99
+ /** Clear all pending erase-region entries for a page. */
100
+ clearEraseRegions(pageIndex: number): void;
101
+ /** Flatten form fields on a single page. */
102
+ flattenFormsOnPage(pageIndex: number): void;
103
+ /** True if the page is marked for annotation-flatten. */
104
+ isPageMarkedForFlatten(pageIndex: number): boolean;
105
+ /** Remove the flatten mark from a page. */
106
+ unmarkPageForFlatten(pageIndex: number): void;
107
+ /** True if the page is marked for redaction. */
108
+ isPageMarkedForRedaction(pageIndex: number): boolean;
109
+ /** Remove the redaction mark from a page. */
110
+ unmarkPageForRedaction(pageIndex: number): void;
111
+ /** Save the document to `path`. */
112
+ save(path: string): void;
113
+ /** Save with AES-256 encryption (user + owner passwords). */
114
+ saveEncrypted(path: string, userPassword: string, ownerPassword: string): void;
115
+ /** Extract specific pages (by 0-based index) into a new PDF returned as a Buffer. */
116
+ extractPagesToBytes(pageIndices: number[]): Buffer;
117
+ /** Save the document to an in-memory Buffer. */
118
+ saveToBytes(): Buffer;
119
+ /** Save to an in-memory Buffer with explicit compression / GC / linearize flags. */
120
+ saveToBytesWithOptions(compress: boolean, garbageCollect: boolean, linearize: boolean): Buffer;
121
+ /** Release the native handle. Safe to call multiple times. */
122
+ close(): void;
123
+ }
124
+ export default DocumentEditor;
@@ -0,0 +1,318 @@
1
+ /**
2
+ * DocumentEditor — thin TS wrapper around the N-API `editor*` exports
3
+ * in `binding.cc`. Mirrors the C# `DocumentEditor` / Go
4
+ * `DocumentEditor` surface.
5
+ *
6
+ * Every mutation is a synchronous call into the Rust core; the same
7
+ * handle is carried until {@link DocumentEditor.close}. Throws plain
8
+ * `Error` with the native message on failure.
9
+ *
10
+ * ```ts
11
+ * import { DocumentEditor } from 'pdf-oxide';
12
+ *
13
+ * const editor = DocumentEditor.open('in.pdf');
14
+ * try {
15
+ * editor.mergeFrom('other.pdf');
16
+ * editor.deletePage(0);
17
+ * editor.movePage(0, 2);
18
+ * editor.setPageRotation(0, 90);
19
+ * editor.save('out.pdf');
20
+ * } finally {
21
+ * editor.close();
22
+ * }
23
+ * ```
24
+ */
25
+ // Load the native addon via the shared prebuild-aware loader.
26
+ // Importing `./index.js` would create an ESM cycle (index.js imports
27
+ // us back), so we go through `./native.js` — same resolver, no cycle,
28
+ // resolves against `prebuilds/<triple>/pdf_oxide.node` in the
29
+ // published package.
30
+ import { loadNative } from './native.js';
31
+ const native = loadNative();
32
+ /**
33
+ * PDF editor bound to a concrete file on disk. Open via
34
+ * {@link DocumentEditor.open}; always pair with {@link close} (or use
35
+ * `using` / the explicit-resource-management protocol once it's
36
+ * stable in your toolchain).
37
+ */
38
+ export class DocumentEditor {
39
+ constructor(handle) {
40
+ this._closed = false;
41
+ this._handle = handle;
42
+ }
43
+ /** Open a PDF file for editing. */
44
+ static open(path) {
45
+ if (typeof path !== 'string' || path.length === 0) {
46
+ throw new TypeError('path must be a non-empty string');
47
+ }
48
+ const handle = native.editorOpen(path);
49
+ return new DocumentEditor(handle);
50
+ }
51
+ /** Open a PDF from an in-memory buffer for editing. */
52
+ static openFromBytes(data) {
53
+ if (!data || data.length === 0) {
54
+ throw new TypeError('data must be a non-empty Buffer or Uint8Array');
55
+ }
56
+ const handle = native.editorOpenFromBytes(data);
57
+ return new DocumentEditor(handle);
58
+ }
59
+ /** True if the editor has been closed. Subsequent calls will throw. */
60
+ get closed() {
61
+ return this._closed;
62
+ }
63
+ _throwIfClosed() {
64
+ if (this._closed)
65
+ throw new Error('DocumentEditor is closed');
66
+ }
67
+ /** Current page count. */
68
+ pageCount() {
69
+ this._throwIfClosed();
70
+ return native.editorGetPageCount(this._handle);
71
+ }
72
+ /** True if the editor has unsaved modifications. */
73
+ isModified() {
74
+ this._throwIfClosed();
75
+ return native.editorIsModified(this._handle);
76
+ }
77
+ // ----- metadata ---------------------------------------------------
78
+ setTitle(title) {
79
+ this._throwIfClosed();
80
+ native.editorSetTitle(this._handle, title);
81
+ }
82
+ setAuthor(author) {
83
+ this._throwIfClosed();
84
+ native.editorSetAuthor(this._handle, author);
85
+ }
86
+ setSubject(subject) {
87
+ this._throwIfClosed();
88
+ native.editorSetSubject(this._handle, subject);
89
+ }
90
+ getKeywords() {
91
+ this._throwIfClosed();
92
+ return native.editorGetKeywords(this._handle);
93
+ }
94
+ setKeywords(keywords) {
95
+ this._throwIfClosed();
96
+ native.editorSetKeywords(this._handle, keywords);
97
+ }
98
+ getProducer() {
99
+ this._throwIfClosed();
100
+ return native.editorGetProducer(this._handle);
101
+ }
102
+ setProducer(producer) {
103
+ this._throwIfClosed();
104
+ native.editorSetProducer(this._handle, producer);
105
+ }
106
+ getCreationDate() {
107
+ this._throwIfClosed();
108
+ return native.editorGetCreationDate(this._handle);
109
+ }
110
+ setCreationDate(date) {
111
+ this._throwIfClosed();
112
+ native.editorSetCreationDate(this._handle, date);
113
+ }
114
+ // ----- page mutations ---------------------------------------------
115
+ /** Delete the page at `pageIndex` (zero-based). */
116
+ deletePage(pageIndex) {
117
+ this._throwIfClosed();
118
+ native.editorDeletePage(this._handle, pageIndex);
119
+ }
120
+ /** Move a page. Indices refer to positions before the move. */
121
+ movePage(fromIndex, toIndex) {
122
+ this._throwIfClosed();
123
+ native.editorMovePage(this._handle, fromIndex, toIndex);
124
+ }
125
+ /** Set rotation on a page (0/90/180/270). */
126
+ setPageRotation(pageIndex, degrees) {
127
+ this._throwIfClosed();
128
+ native.editorSetPageRotation(this._handle, pageIndex, degrees);
129
+ }
130
+ // ----- document-level mutations -----------------------------------
131
+ /**
132
+ * Append every page of another PDF to the end of this document.
133
+ */
134
+ mergeFrom(sourcePath) {
135
+ this._throwIfClosed();
136
+ if (typeof sourcePath !== 'string' || sourcePath.length === 0) {
137
+ throw new TypeError('sourcePath must be a non-empty string');
138
+ }
139
+ native.editorMergeFrom(this._handle, sourcePath);
140
+ }
141
+ /** Flatten form fields across the entire document. */
142
+ flattenForms() {
143
+ this._throwIfClosed();
144
+ native.editorFlattenForms(this._handle);
145
+ }
146
+ /**
147
+ * Return warnings collected during the last form-flattening save.
148
+ * Each entry names a widget field that had no `/AP` appearance stream;
149
+ * flattening it produces a blank rectangle.
150
+ */
151
+ flattenWarnings() {
152
+ this._throwIfClosed();
153
+ return native.editorFlattenWarnings(this._handle);
154
+ }
155
+ /** Flatten annotations. If `pageIndex` is omitted, flattens all pages. */
156
+ flattenAnnotations(pageIndex) {
157
+ this._throwIfClosed();
158
+ if (pageIndex === undefined) {
159
+ native.editorFlattenAnnotations(this._handle);
160
+ }
161
+ else {
162
+ native.editorFlattenAnnotations(this._handle, pageIndex);
163
+ }
164
+ }
165
+ /** Set a form field value by fully-qualified field name. */
166
+ setFormFieldValue(fieldName, value) {
167
+ this._throwIfClosed();
168
+ native.editorSetFormFieldValue(this._handle, fieldName, value);
169
+ }
170
+ /** Import an FDF file (bytes) into the document's form. */
171
+ importFdfBytes(fdf) {
172
+ this._throwIfClosed();
173
+ native.editorImportFdfBytes(this._handle, fdf);
174
+ }
175
+ /** Import an XFDF file (bytes) into the document's form. */
176
+ importXfdfBytes(xfdf) {
177
+ this._throwIfClosed();
178
+ native.editorImportXfdfBytes(this._handle, xfdf);
179
+ }
180
+ // ----- byte-level merge / embed -----------------------------------
181
+ /**
182
+ * Append every page of another PDF (supplied as bytes) to this document.
183
+ * Returns the number of pages added.
184
+ */
185
+ mergeFromBytes(data) {
186
+ this._throwIfClosed();
187
+ return native.editorMergeFromBytes(this._handle, data);
188
+ }
189
+ /** Embed a file attachment into the document. */
190
+ embedFile(name, data) {
191
+ this._throwIfClosed();
192
+ native.editorEmbedFile(this._handle, name, data);
193
+ }
194
+ // ----- redactions -------------------------------------------------
195
+ /** Burn in redaction annotations on a single page (zero-based). */
196
+ applyPageRedactions(pageIndex) {
197
+ this._throwIfClosed();
198
+ native.editorApplyPageRedactions(this._handle, pageIndex);
199
+ }
200
+ /** Burn in all pending redaction annotations across the document. */
201
+ applyAllRedactions() {
202
+ this._throwIfClosed();
203
+ native.editorApplyAllRedactions(this._handle);
204
+ }
205
+ // ----- rotation (additive) ----------------------------------------
206
+ /** Rotate all pages by `degrees` (additive). */
207
+ rotateAllPages(degrees) {
208
+ this._throwIfClosed();
209
+ native.editorRotateAllPages(this._handle, degrees);
210
+ }
211
+ /** Rotate a single page by `degrees` (additive). */
212
+ rotatePageBy(pageIndex, degrees) {
213
+ this._throwIfClosed();
214
+ native.editorRotatePageBy(this._handle, pageIndex, degrees);
215
+ }
216
+ // ----- page boxes -------------------------------------------------
217
+ /** Get the MediaBox of a page as `{x, y, width, height}`. */
218
+ getPageMediaBox(pageIndex) {
219
+ this._throwIfClosed();
220
+ return native.editorGetPageMediaBox(this._handle, pageIndex);
221
+ }
222
+ /** Set the MediaBox of a page. */
223
+ setPageMediaBox(pageIndex, x, y, width, height) {
224
+ this._throwIfClosed();
225
+ native.editorSetPageMediaBox(this._handle, pageIndex, x, y, width, height);
226
+ }
227
+ /** Get the CropBox of a page. Returns `{x:0,y:0,width:0,height:0}` if none set. */
228
+ getPageCropBox(pageIndex) {
229
+ this._throwIfClosed();
230
+ return native.editorGetPageCropBox(this._handle, pageIndex);
231
+ }
232
+ /** Set the CropBox of a page. */
233
+ setPageCropBox(pageIndex, x, y, width, height) {
234
+ this._throwIfClosed();
235
+ native.editorSetPageCropBox(this._handle, pageIndex, x, y, width, height);
236
+ }
237
+ // ----- erase regions ----------------------------------------------
238
+ /**
239
+ * Erase rectangular regions on a page.
240
+ * `rects` is an array of `[x, y, w, h]` tuples.
241
+ */
242
+ eraseRegions(pageIndex, rects) {
243
+ this._throwIfClosed();
244
+ native.editorEraseRegions(this._handle, pageIndex, rects);
245
+ }
246
+ /** Clear all pending erase-region entries for a page. */
247
+ clearEraseRegions(pageIndex) {
248
+ this._throwIfClosed();
249
+ native.editorClearEraseRegions(this._handle, pageIndex);
250
+ }
251
+ // ----- form flattening on single page ------------------------------
252
+ /** Flatten form fields on a single page. */
253
+ flattenFormsOnPage(pageIndex) {
254
+ this._throwIfClosed();
255
+ native.editorFlattenFormsOnPage(this._handle, pageIndex);
256
+ }
257
+ // ----- page-mark state queries ------------------------------------
258
+ /** True if the page is marked for annotation-flatten. */
259
+ isPageMarkedForFlatten(pageIndex) {
260
+ this._throwIfClosed();
261
+ return native.editorIsPageMarkedForFlatten(this._handle, pageIndex);
262
+ }
263
+ /** Remove the flatten mark from a page. */
264
+ unmarkPageForFlatten(pageIndex) {
265
+ this._throwIfClosed();
266
+ native.editorUnmarkPageForFlatten(this._handle, pageIndex);
267
+ }
268
+ /** True if the page is marked for redaction. */
269
+ isPageMarkedForRedaction(pageIndex) {
270
+ this._throwIfClosed();
271
+ return native.editorIsPageMarkedForRedaction(this._handle, pageIndex);
272
+ }
273
+ /** Remove the redaction mark from a page. */
274
+ unmarkPageForRedaction(pageIndex) {
275
+ this._throwIfClosed();
276
+ native.editorUnmarkPageForRedaction(this._handle, pageIndex);
277
+ }
278
+ // ----- save paths -------------------------------------------------
279
+ /** Save the document to `path`. */
280
+ save(path) {
281
+ this._throwIfClosed();
282
+ if (typeof path !== 'string' || path.length === 0) {
283
+ throw new TypeError('path must be a non-empty string');
284
+ }
285
+ native.editorSave(this._handle, path);
286
+ }
287
+ /** Save with AES-256 encryption (user + owner passwords). */
288
+ saveEncrypted(path, userPassword, ownerPassword) {
289
+ this._throwIfClosed();
290
+ native.editorSaveEncrypted(this._handle, path, userPassword, ownerPassword);
291
+ }
292
+ /** Extract specific pages (by 0-based index) into a new PDF returned as a Buffer. */
293
+ extractPagesToBytes(pageIndices) {
294
+ this._throwIfClosed();
295
+ return native.editorExtractPagesToBytes(this._handle, pageIndices);
296
+ }
297
+ /** Save the document to an in-memory Buffer. */
298
+ saveToBytes() {
299
+ this._throwIfClosed();
300
+ return native.editorSaveToBytes(this._handle);
301
+ }
302
+ /** Save to an in-memory Buffer with explicit compression / GC / linearize flags. */
303
+ saveToBytesWithOptions(compress, garbageCollect, linearize) {
304
+ this._throwIfClosed();
305
+ return native.editorSaveToBytesWithOptions(this._handle, compress, garbageCollect, linearize);
306
+ }
307
+ // ----- lifecycle --------------------------------------------------
308
+ /** Release the native handle. Safe to call multiple times. */
309
+ close() {
310
+ if (!this._closed) {
311
+ if (native.editorFree) {
312
+ native.editorFree(this._handle);
313
+ }
314
+ this._closed = true;
315
+ }
316
+ }
317
+ }
318
+ export default DocumentEditor;