@rightkit/document-core 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +31 -7
  3. package/dist/app/chrome.js +1 -1
  4. package/dist/app/documentPrinting.d.ts +0 -6
  5. package/dist/app/documentPrinting.js +0 -18
  6. package/dist/app/shell/nativeMenu.d.ts +3 -2
  7. package/dist/app/shell/nativeMenu.js +8 -5
  8. package/dist/documents/perfEventCounters.d.ts +0 -8
  9. package/dist/documents/perfEventCounters.js +2 -1
  10. package/dist/documents/preview/previewFrame.d.ts +2 -1
  11. package/dist/documents/preview/previewFrame.js +9 -7
  12. package/dist/documents/searchUtils.js +1 -1
  13. package/dist/host.d.ts +36 -0
  14. package/dist/host.js +54 -0
  15. package/dist/index.d.ts +1 -50
  16. package/dist/index.js +1 -50
  17. package/dist/settings/themes.js +1 -1
  18. package/dist/state/bridgeEvents.d.ts +1 -1
  19. package/dist/state/bridgeEvents.js +7 -4
  20. package/dist/state/recentUrls.js +4 -3
  21. package/dist/state/tauriBridge.d.ts +3 -61
  22. package/dist/state/tauriBridge.js +8 -297
  23. package/dist/styles.css +2 -2
  24. package/package.json +25 -98
  25. package/dist/app/shortcutChords.d.ts +0 -6
  26. package/dist/app/shortcutChords.js +0 -14
  27. package/dist/app/useCloseFindOnSurfaceChange.d.ts +0 -14
  28. package/dist/app/useCloseFindOnSurfaceChange.js +0 -23
  29. package/dist/app/useEditText.d.ts +0 -6
  30. package/dist/app/useEditText.js +0 -10
  31. package/dist/appName.d.ts +0 -2
  32. package/dist/appName.js +0 -8
  33. package/dist/documents/FullscreenIcon.d.ts +0 -4
  34. package/dist/documents/FullscreenIcon.js +0 -7
  35. package/dist/documents/mdx/mdxRuntimeScript.d.ts +0 -2
  36. package/dist/documents/mdx/mdxRuntimeScript.js +0 -3
  37. package/dist/documents/mdx/mdxRuntimeScript.txt +0 -584
  38. package/dist/documents/pdf/MacPdfReadPane.d.ts +0 -23
  39. package/dist/documents/pdf/MacPdfReadPane.js +0 -708
  40. package/dist/documents/pdf/NativePdfDocument.d.ts +0 -9
  41. package/dist/documents/pdf/NativePdfDocument.js +0 -41
  42. package/dist/documents/pdf/PdfInlineTextEditor.d.ts +0 -53
  43. package/dist/documents/pdf/PdfInlineTextEditor.js +0 -225
  44. package/dist/documents/pdf/PdfOcrLayer.d.ts +0 -4
  45. package/dist/documents/pdf/PdfOcrLayer.js +0 -30
  46. package/dist/documents/pdf/PdfOutline.d.ts +0 -6
  47. package/dist/documents/pdf/PdfOutline.js +0 -12
  48. package/dist/documents/pdf/PdfPasswordPrompt.d.ts +0 -5
  49. package/dist/documents/pdf/PdfPasswordPrompt.js +0 -24
  50. package/dist/documents/pdf/PdfThumbnails.d.ts +0 -8
  51. package/dist/documents/pdf/PdfThumbnails.js +0 -201
  52. package/dist/documents/pdf/PdfToolbar.d.ts +0 -47
  53. package/dist/documents/pdf/PdfToolbar.js +0 -76
  54. package/dist/documents/pdf/PdfViewer.d.ts +0 -36
  55. package/dist/documents/pdf/PdfViewer.js +0 -1522
  56. package/dist/documents/pdf/PdfViewerBody.d.ts +0 -22
  57. package/dist/documents/pdf/PdfViewerBody.js +0 -42
  58. package/dist/documents/pdf/macPdfNativeBridge.d.ts +0 -118
  59. package/dist/documents/pdf/macPdfNativeBridge.js +0 -134
  60. package/dist/documents/pdf/nearestVisiblePdfPage.d.ts +0 -2
  61. package/dist/documents/pdf/nearestVisiblePdfPage.js +0 -22
  62. package/dist/documents/pdf/pdfBench.d.ts +0 -88
  63. package/dist/documents/pdf/pdfBench.js +0 -535
  64. package/dist/documents/pdf/pdfBenchAutopilot.d.ts +0 -48
  65. package/dist/documents/pdf/pdfBenchAutopilot.js +0 -154
  66. package/dist/documents/pdf/pdfBenchTransport.d.ts +0 -21
  67. package/dist/documents/pdf/pdfBenchTransport.js +0 -233
  68. package/dist/documents/pdf/pdfEditModel.d.ts +0 -294
  69. package/dist/documents/pdf/pdfEditModel.js +0 -105
  70. package/dist/documents/pdf/pdfEditor.d.ts +0 -100
  71. package/dist/documents/pdf/pdfEditor.js +0 -68
  72. package/dist/documents/pdf/pdfOcr.d.ts +0 -36
  73. package/dist/documents/pdf/pdfOcr.js +0 -88
  74. package/dist/documents/pdf/pdfOcrEdit.d.ts +0 -32
  75. package/dist/documents/pdf/pdfOcrEdit.js +0 -138
  76. package/dist/documents/pdf/pdfPrinting.d.ts +0 -28
  77. package/dist/documents/pdf/pdfPrinting.js +0 -110
  78. package/dist/documents/pdf/pdfSave.d.ts +0 -87
  79. package/dist/documents/pdf/pdfSave.js +0 -250
  80. package/dist/documents/pdf/pdfShared.d.ts +0 -16
  81. package/dist/documents/pdf/pdfShared.js +0 -20
  82. package/dist/documents/pdf/pdfToMarkdown.d.ts +0 -11
  83. package/dist/documents/pdf/pdfToMarkdown.js +0 -67
  84. package/dist/documents/pdf/pdfjsLibGlobal.d.ts +0 -1
  85. package/dist/documents/pdf/pdfjsLibGlobal.js +0 -12
  86. package/dist/documents/pdf/toolbarIcons.d.ts +0 -18
  87. package/dist/documents/pdf/toolbarIcons.js +0 -31
  88. package/dist/documents/pdf/usePdfDocumentLoader.d.ts +0 -40
  89. package/dist/documents/pdf/usePdfDocumentLoader.js +0 -243
  90. package/dist/documents/pdf/usePdfEditSession.d.ts +0 -88
  91. package/dist/documents/pdf/usePdfEditSession.js +0 -341
  92. package/dist/documents/pdf/usePdfEditor.d.ts +0 -59
  93. package/dist/documents/pdf/usePdfEditor.js +0 -317
  94. package/dist/documents/pdf/usePdfFit.d.ts +0 -19
  95. package/dist/documents/pdf/usePdfFit.js +0 -55
  96. package/dist/documents/pdf/usePdfOcr.d.ts +0 -38
  97. package/dist/documents/pdf/usePdfOcr.js +0 -337
  98. package/dist/documents/pdf/usePdfPreviewRecompose.d.ts +0 -28
  99. package/dist/documents/pdf/usePdfPreviewRecompose.js +0 -256
  100. package/dist/documents/pdf/usePdfSavePlan.d.ts +0 -61
  101. package/dist/documents/pdf/usePdfSavePlan.js +0 -303
  102. package/dist/documents/pdf/usePdfSearch.d.ts +0 -31
  103. package/dist/documents/pdf/usePdfSearch.js +0 -367
  104. package/dist/documents/pdf/usePdfViewControls.d.ts +0 -72
  105. package/dist/documents/pdf/usePdfViewControls.js +0 -152
  106. package/dist/documents/scopedSelectAll.d.ts +0 -5
  107. package/dist/documents/scopedSelectAll.js +0 -77
  108. package/dist/documents/txt/cmScroll.d.ts +0 -11
  109. package/dist/documents/txt/cmScroll.js +0 -52
  110. package/dist/documents/useMirroredEditText.d.ts +0 -15
  111. package/dist/documents/useMirroredEditText.js +0 -29
  112. package/dist/documents/useSplitResize.d.ts +0 -7
  113. package/dist/documents/useSplitResize.js +0 -37
  114. package/dist/settings/rk-settings.css +0 -38
  115. package/dist/settings/sections/EditorSection.d.ts +0 -1
  116. package/dist/settings/sections/EditorSection.js +0 -18
  117. package/dist/settings/sections/FileAssociationsSection.d.ts +0 -1
  118. package/dist/settings/sections/FileAssociationsSection.js +0 -5
  119. package/dist/settings/sections/MacFileAssociationsBlock.d.ts +0 -33
  120. package/dist/settings/sections/MacFileAssociationsBlock.js +0 -151
  121. package/dist/settings/sections/ThemeSection.d.ts +0 -1
  122. package/dist/settings/sections/ThemeSection.js +0 -31
  123. package/dist/settings/sections/TypographySection.d.ts +0 -1
  124. package/dist/settings/sections/TypographySection.js +0 -19
  125. package/dist/settings/sections/onOff.d.ts +0 -11
  126. package/dist/settings/sections/onOff.js +0 -8
  127. package/dist/state/browserQa.d.ts +0 -21
  128. package/dist/state/browserQa.js +0 -303
  129. package/dist/state/browserQaDocx.d.ts +0 -3
  130. package/dist/state/browserQaDocx.js +0 -35
  131. package/dist/state/browserQaLicense.d.ts +0 -8
  132. package/dist/state/browserQaLicense.js +0 -7
  133. package/dist/state/browserQaPdf.d.ts +0 -60
  134. package/dist/state/browserQaPdf.js +0 -302
  135. package/dist/state/browserQaText.d.ts +0 -6
  136. package/dist/state/browserQaText.js +0 -48
@@ -1,294 +0,0 @@
1
- /**
2
- * Canonical frontend model for sparse PDF edits.
3
- *
4
- * This file is the frozen cross-lane seam described in `docs/PDF-EDITOR-DISPATCH.md`
5
- * ("Frozen cross-lane seams"): it owns every shared frontend type — the Rust wire-model mirrors
6
- * (`docs/PDF-EDITOR-NOW.md` §5.1), the session/command types (§6), `PdfSavePlan` (§10.3), the typed
7
- * `PdfEditError` union (§11), and the *injected-bridge* function signatures other lanes accept by
8
- * injection ahead of the real `tauriBridge.ts` implementations landing at Dispatch D2.
9
- *
10
- * PDF pages are fixed-layout scenes, not word-processing documents. Existing content therefore
11
- * enters the editor as small, source-backed "islands" reported by the Rust inspector
12
- * (`inspect_pdf_page`, §5.2). Every edit command retains a stable source locator (§5.1) so
13
- * persistence (§9) can patch only changed content instead of clearing and reconstructing a page.
14
- *
15
- * This is a contract-definition file: types plus small pure helpers. Session lifecycle, draft
16
- * commit/cancel orchestration, and the real bridge live elsewhere (`usePdfEditSession.ts`,
17
- * `pdfSave.ts`, `tauriBridge.ts` — see `docs/PDF-EDITOR-NOW.md` §12).
18
- */
19
- /** Axis-aligned rectangle in PDF user-space units (origin/orientation follow the page's own
20
- * coordinate system, pre-viewport-transform). Used for available-bounds checks (§8's
21
- * `available.contains(run.bounds)`) and for the draft's page-slot placement (§6.1's
22
- * `pdfRectToViewport(session.draft.rect, viewport)`). */
23
- export interface PdfRect {
24
- x: number;
25
- y: number;
26
- width: number;
27
- height: number;
28
- }
29
- /** A single PDF user-space point, e.g. the clicked anchor for Add Text (§6 `PdfAddText.anchor`). */
30
- export interface PdfPoint {
31
- x: number;
32
- y: number;
33
- }
34
- /** Four-number tuple shape shared by `mediaBox`, `cropBox` (§5.1), and an island's `baseline`
35
- * segment — all serialize from Rust `[f64; 4]`. */
36
- export type PdfQuad4 = [number, number, number, number];
37
- /** Eight-number tuple shape for one glyph-run quadrilateral (`PdfTextIsland.quads`, §5.1),
38
- * serialized from Rust `[f64; 8]` as four (x, y) corner pairs. */
39
- export type PdfQuad8 = [number, number, number, number, number, number, number, number];
40
- export interface PdfDocumentRevision {
41
- documentSha256: string;
42
- pageCount: number;
43
- pages: PdfPageGraph[];
44
- }
45
- export interface PdfPageGraph {
46
- documentSha256: string;
47
- page: number;
48
- mediaBox: PdfQuad4;
49
- cropBox: PdfQuad4;
50
- rotation: number;
51
- islands: PdfTextIsland[];
52
- }
53
- /** One editable (or explicitly-rejected) same-line visual text run (§5.3). Named identically to
54
- * the Rust wire struct it mirrors — this supersedes the prior DOM/occurrence-based
55
- * `PdfTextIsland` from the superseded attempt; there is no backward-compat alias. */
56
- export interface PdfTextIsland {
57
- id: string;
58
- text: string;
59
- quads: PdfQuad8[];
60
- baseline: PdfQuad4;
61
- appearance: PdfTextAppearance;
62
- locator: PdfSourceLocator;
63
- editable: boolean;
64
- rejection: PdfEditError | null;
65
- }
66
- /** Stable identity for a piece of source content, independent of any DOM node or viewport state
67
- * (§4: "pdf.js DOM nodes never identify persistent source content"). */
68
- export interface PdfSourceLocator {
69
- documentSha256: string;
70
- page: number;
71
- spans: PdfSourceSpan[];
72
- islandDigest: string;
73
- }
74
- /** One exact source-byte range an edit command may patch (§9.1/§9.2). `streamRef` mirrors Rust's
75
- * `(u32, u16)` object/generation tuple. */
76
- export interface PdfSourceSpan {
77
- streamRef: [number, number];
78
- contentsIndex: number;
79
- operatorIndex: number;
80
- operandIndex: number;
81
- glyphStart: number;
82
- glyphEnd: number;
83
- expectedText: string;
84
- expectedDigest: string;
85
- }
86
- /** Not specified as a concrete Rust type in §7.2 — inferred as the two catalog origins the section
87
- * narrative distinguishes ("bundled fonts such as Source Serif 4 plus eligible system fonts"). */
88
- export type PdfFontSource = "bundled" | "system";
89
- export interface PdfFontCatalogEntry {
90
- id: string;
91
- family: string;
92
- postscriptName: string | null;
93
- styles: string[];
94
- embeddable: boolean;
95
- subsettable: boolean;
96
- source: PdfFontSource;
97
- }
98
- export type PdfColor = {
99
- r: number;
100
- g: number;
101
- b: number;
102
- alpha: number;
103
- };
104
- export type PdfTextAppearance = {
105
- fontId: string;
106
- family: string;
107
- sizePt: number;
108
- color: PdfColor;
109
- };
110
- export type PdfSourceEdit = {
111
- kind: "replaceSourceText";
112
- id: string;
113
- locator: PdfSourceLocator;
114
- before: {
115
- text: string;
116
- appearance: PdfTextAppearance;
117
- };
118
- after: {
119
- text: string;
120
- appearance: PdfTextAppearance;
121
- };
122
- availableBounds: PdfRect;
123
- };
124
- export type PdfAddText = {
125
- kind: "addText";
126
- id: string;
127
- page: number;
128
- anchor: PdfPoint;
129
- text: string;
130
- appearance: PdfTextAppearance;
131
- };
132
- export type PdfOcrCorrection = {
133
- kind: "correctOcrText";
134
- id: string;
135
- page: number;
136
- lineId: string;
137
- rect: PdfRect;
138
- text: string;
139
- appearance: PdfTextAppearance;
140
- coverColor: PdfColor;
141
- backgroundProof: "nearUniform";
142
- };
143
- export type PdfEditCommand = PdfSourceEdit | PdfAddText | PdfOcrCorrection;
144
- /** Narrows `command` to `PdfSourceEdit`. Trivial given the `kind` discriminant, but kept as a named
145
- * helper so call sites read intent rather than re-deriving the literal each time. */
146
- export declare function isPdfSourceEdit(command: PdfEditCommand): command is PdfSourceEdit;
147
- /** Narrows `command` to `PdfAddText`. */
148
- export declare function isPdfAddText(command: PdfEditCommand): command is PdfAddText;
149
- export declare function isPdfOcrCorrection(command: PdfEditCommand): command is PdfOcrCorrection;
150
- export type PdfEditSession = {
151
- mode: "view" | "edit";
152
- tool: "selectText" | "addText" | "highlight" | "ink" | "image";
153
- selection: PdfSelection | null;
154
- draft: PdfTextDraft | null;
155
- sourceCommands: readonly PdfEditCommand[];
156
- sourceDigest: string;
157
- savedSourceDigest: string;
158
- annotationDirty: boolean;
159
- };
160
- /** The currently selected existing text island (§3.2). Not specified as a concrete shape in the
161
- * contract text beyond "selection"; inferred as enough identity + geometry to drive highlight
162
- * rendering and to seed a draft when the user starts editing it. */
163
- export interface PdfSelection {
164
- page: number;
165
- islandId: string;
166
- locator: PdfSourceLocator;
167
- rect: PdfRect;
168
- }
169
- /** The in-progress edit surfaced by the page-slot editor (§6.1). Covers both existing-text edits
170
- * (`kind: "sourceEdit"`, seeded from a `PdfSelection`/island) and Add Text (`kind: "addText"`,
171
- * seeded from a clicked `PdfPoint`). Not given as a concrete shape in the contract text; inferred
172
- * from §6.1's `session.draft.rect` / `session.draft.page` usage and §3.3's overflow behavior
173
- * ("editor shows overflow on page & Save is disabled for that command"). Commit-time logic builds
174
- * a `PdfSourceEdit` or `PdfAddText` from these fields. */
175
- export type PdfTextDraft = {
176
- kind: "sourceEdit" | "addText" | "ocrEdit";
177
- id: string;
178
- page: number;
179
- rect: PdfRect;
180
- text: string;
181
- appearance: PdfTextAppearance;
182
- /** `sourceEdit` only: locator identifying the island being replaced. */
183
- locator: PdfSourceLocator | null;
184
- /** `sourceEdit` only: text/appearance snapshot at draft start, used to build the command's
185
- * `before` half and to detect a no-op commit. */
186
- originalText: string | null;
187
- originalAppearance: PdfTextAppearance | null;
188
- /** `sourceEdit` only: verified bounds the replacement run must stay inside (§8). */
189
- availableBounds: PdfRect | null;
190
- /** `addText` only: the clicked PDF-space anchor point. */
191
- anchor: PdfPoint | null;
192
- /** `ocrEdit` only: stable recognized-line identity & locally sampled cover color. */
193
- lineId?: string;
194
- coverColor?: PdfColor;
195
- backgroundProof?: "nearUniform";
196
- /** True once the current draft geometry has been measured to exceed `availableBounds` (§3.3).
197
- * UI disables Save for this command while true; it never auto-shrinks/clips/wraps. */
198
- overflow: boolean;
199
- };
200
- /** Narrows `draft` to a `sourceEdit` draft (editing an existing island). */
201
- export declare function isSourceEditDraft(draft: PdfTextDraft): draft is PdfTextDraft & {
202
- kind: "sourceEdit";
203
- locator: PdfSourceLocator;
204
- };
205
- /** Narrows `draft` to an `addText` draft (new text at a clicked point). */
206
- export declare function isAddTextDraft(draft: PdfTextDraft): draft is PdfTextDraft & {
207
- kind: "addText";
208
- anchor: PdfPoint;
209
- };
210
- /** Deterministic digest of an ordered command list. Two lists produce the same digest iff they
211
- * have the same commands in the same order (object key order inside each command does not
212
- * matter — `stableStringify` sorts keys). Empty history has a fixed, distinguishable digest. */
213
- export declare function computeSourceDigest(commands: readonly PdfEditCommand[]): string;
214
- /** Dirty-state derivation per §6: source edits are dirty when the live digest has diverged from
215
- * the last-saved checkpoint, OR annotations changed. This is what "survives undo across save
216
- * checkpoint" — a boolean "was written" flag would not, because undoing back to a *different*
217
- * command list than what was saved is still dirty even though something was undone. */
218
- export declare function isSessionDirty(session: Pick<PdfEditSession, "sourceDigest" | "savedSourceDigest" | "annotationDirty">): boolean;
219
- export type PdfEditErrorCode = "stale_source" | "source_digest_mismatch" | "no_unique_match" | "unsupported_transform" | "unsupported_encoding" | "missing_glyph" | "font_embedding_denied" | "text_overflow" | "malformed_content" | "encrypted_document" | "annotation_serialization_failed" | "verification_failed" | "write_conflict";
220
- export declare const PDF_EDIT_ERROR_CODES: readonly PdfEditErrorCode[];
221
- /** Typed IPC error for every fallible PDF-edit command in this contract (§5.2, §7.2, §9.4, §10.1,
222
- * §10.3). `message` carries the contextual, non-document-text detail §11 requires ("Logs include
223
- * code/page/strategy but no document text"). */
224
- export interface PdfEditError {
225
- code: PdfEditErrorCode;
226
- message: string;
227
- }
228
- /** Runtime guard for `code`, primarily useful when classifying an unknown IPC rejection (mirrors
229
- * the narrowing `parseHostError` does for `ClassifiedError` in tauriBridge.ts). */
230
- export declare function isPdfEditErrorCode(code: unknown): code is PdfEditErrorCode;
231
- /** Not given as a concrete Rust type in §10.1/§10.2 despite being referenced by
232
- * `PreparedPdfSave.expectedText` and consumed by `verifyPdfCandidate` to check extracted text
233
- * against the composed candidate. Inferred minimal shape: enough to locate which island on which
234
- * page must contain which text after the isolated re-render (§10.2). */
235
- export interface PdfExpectedTextCheck {
236
- page: number;
237
- islandId: string;
238
- expectedText: string;
239
- }
240
- export interface PreparePdfSaveRequest {
241
- sourcePath: string;
242
- expectedSourceSha256: string;
243
- /** Raw invoke body per §4 — never a JSON number array. */
244
- annotationPdfBytes: Uint8Array;
245
- sourceCommands: readonly PdfEditCommand[];
246
- }
247
- export interface PreparedPdfSave {
248
- token: string;
249
- candidateSha256: string;
250
- /** Raw `tauri::ipc::Response` body per §4. */
251
- candidateBytes: Uint8Array;
252
- affectedPages: readonly number[];
253
- expectedText: readonly PdfExpectedTextCheck[];
254
- }
255
- /** Not given as a concrete Rust type anywhere in the contract — §10.3 explicitly requires "Save
256
- * protocol... return a commit plan, not bare bytes" and states a successful commit "reloads
257
- * active pdf.js document from committed bytes, refreshes graph/revision, clears annotation
258
- * storage dirty state, & checkpoints sourceDigest." Inferred shape carries what the frontend needs
259
- * to do all of that without a second round trip: the committed path/sha, which pages changed, and
260
- * the fresh `PdfDocumentRevision` to refresh the graph from. */
261
- export interface PdfCommitResult {
262
- committedPath: string;
263
- committedSha256: string;
264
- affectedPages: readonly number[];
265
- revision: PdfDocumentRevision;
266
- /** Disk commit succeeded while newer in-memory edits remain unsaved in active document. */
267
- preservedUnsavedEdits?: boolean;
268
- }
269
- /** Exact shape from §10.3. Generic document saver (`useDocumentSaver.ts`, B8) updates
270
- * recents/fingerprints/checkpoints only after `commit` succeeds and `didCommit` has run. */
271
- export type PdfSavePlan = {
272
- commit(targetPath?: string): Promise<PdfCommitResult>;
273
- didCommit(result: PdfCommitResult): Promise<void>;
274
- };
275
- /** §5.2 `inspect_pdf_page`. */
276
- export type InspectPdfPage = (path: string, page: number) => Promise<PdfPageGraph>;
277
- /** §7.2 `list_pdf_fonts`. */
278
- export type ListPdfFonts = () => Promise<PdfFontCatalogEntry[]>;
279
- export interface ComposePdfPreviewRequest {
280
- sourcePath: string;
281
- expectedSourceSha256: string;
282
- sourceCommands: readonly PdfEditCommand[];
283
- }
284
- export interface ComposedPdfPreview {
285
- /** Raw `tauri::ipc::Response` body per §4 — memory-only candidate bytes, never persisted. */
286
- candidateBytes: Uint8Array;
287
- affectedPages: readonly number[];
288
- }
289
- /** §9.4 `compose_pdf_preview`. Memory-only: no token, no retained candidate, no writes. */
290
- export type ComposePdfPreview = (request: ComposePdfPreviewRequest) => Promise<ComposedPdfPreview>;
291
- /** §10.1 `prepare_pdf_save`. */
292
- export type PreparePdfSave = (request: PreparePdfSaveRequest) => Promise<PreparedPdfSave>;
293
- /** §10.3 `commit_pdf_save`. */
294
- export type CommitPdfSave = (token: string, targetPath?: string) => Promise<PdfCommitResult>;
@@ -1,105 +0,0 @@
1
- /**
2
- * Canonical frontend model for sparse PDF edits.
3
- *
4
- * This file is the frozen cross-lane seam described in `docs/PDF-EDITOR-DISPATCH.md`
5
- * ("Frozen cross-lane seams"): it owns every shared frontend type — the Rust wire-model mirrors
6
- * (`docs/PDF-EDITOR-NOW.md` §5.1), the session/command types (§6), `PdfSavePlan` (§10.3), the typed
7
- * `PdfEditError` union (§11), and the *injected-bridge* function signatures other lanes accept by
8
- * injection ahead of the real `tauriBridge.ts` implementations landing at Dispatch D2.
9
- *
10
- * PDF pages are fixed-layout scenes, not word-processing documents. Existing content therefore
11
- * enters the editor as small, source-backed "islands" reported by the Rust inspector
12
- * (`inspect_pdf_page`, §5.2). Every edit command retains a stable source locator (§5.1) so
13
- * persistence (§9) can patch only changed content instead of clearing and reconstructing a page.
14
- *
15
- * This is a contract-definition file: types plus small pure helpers. Session lifecycle, draft
16
- * commit/cancel orchestration, and the real bridge live elsewhere (`usePdfEditSession.ts`,
17
- * `pdfSave.ts`, `tauriBridge.ts` — see `docs/PDF-EDITOR-NOW.md` §12).
18
- */
19
- /** Narrows `command` to `PdfSourceEdit`. Trivial given the `kind` discriminant, but kept as a named
20
- * helper so call sites read intent rather than re-deriving the literal each time. */
21
- export function isPdfSourceEdit(command) {
22
- return command.kind === "replaceSourceText";
23
- }
24
- /** Narrows `command` to `PdfAddText`. */
25
- export function isPdfAddText(command) {
26
- return command.kind === "addText";
27
- }
28
- export function isPdfOcrCorrection(command) {
29
- return command.kind === "correctOcrText";
30
- }
31
- /** Narrows `draft` to a `sourceEdit` draft (editing an existing island). */
32
- export function isSourceEditDraft(draft) {
33
- return draft.kind === "sourceEdit";
34
- }
35
- /** Narrows `draft` to an `addText` draft (new text at a clicked point). */
36
- export function isAddTextDraft(draft) {
37
- return draft.kind === "addText";
38
- }
39
- // ---------------------------------------------------------------------------------------------
40
- // Digest / dirty-state helpers (§6)
41
- // ---------------------------------------------------------------------------------------------
42
- //
43
- // Pure, deterministic, order-sensitive. `computeSourceDigest` is the canonical way session logic
44
- // (owned by usePdfEditSession.ts) derives `PdfEditSession.sourceDigest` from the current ordered
45
- // `sourceCommands`; order sensitivity matters because undo/redo changes the array's tail and must
46
- // therefore change the digest even when only the newest command differs.
47
- function stableStringify(value) {
48
- if (value === null || typeof value !== "object") {
49
- return JSON.stringify(value);
50
- }
51
- if (Array.isArray(value)) {
52
- return `[${value.map(stableStringify).join(",")}]`;
53
- }
54
- const record = value;
55
- const keys = Object.keys(record).sort();
56
- const entries = keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`);
57
- return `{${entries.join(",")}}`;
58
- }
59
- /** FNV-1a over a UTF-16-code-unit string. Not cryptographic; only used to derive a short, stable,
60
- * collision-resistant-enough-for-UI digest of the in-memory command list. Structurally identical
61
- * to the hashing approach the superseded file used for island ids, generalized to hash any
62
- * stable-stringified value. */
63
- function fnv1a(text) {
64
- let hash = 0x811c9dc5;
65
- for (let i = 0; i < text.length; i += 1) {
66
- hash ^= text.charCodeAt(i);
67
- hash = Math.imul(hash, 0x01000193);
68
- }
69
- return (hash >>> 0).toString(16).padStart(8, "0");
70
- }
71
- /** Deterministic digest of an ordered command list. Two lists produce the same digest iff they
72
- * have the same commands in the same order (object key order inside each command does not
73
- * matter — `stableStringify` sorts keys). Empty history has a fixed, distinguishable digest. */
74
- export function computeSourceDigest(commands) {
75
- if (commands.length === 0)
76
- return "empty";
77
- return fnv1a(stableStringify(commands));
78
- }
79
- /** Dirty-state derivation per §6: source edits are dirty when the live digest has diverged from
80
- * the last-saved checkpoint, OR annotations changed. This is what "survives undo across save
81
- * checkpoint" — a boolean "was written" flag would not, because undoing back to a *different*
82
- * command list than what was saved is still dirty even though something was undone. */
83
- export function isSessionDirty(session) {
84
- return session.sourceDigest !== session.savedSourceDigest || session.annotationDirty;
85
- }
86
- export const PDF_EDIT_ERROR_CODES = [
87
- "stale_source",
88
- "source_digest_mismatch",
89
- "no_unique_match",
90
- "unsupported_transform",
91
- "unsupported_encoding",
92
- "missing_glyph",
93
- "font_embedding_denied",
94
- "text_overflow",
95
- "malformed_content",
96
- "encrypted_document",
97
- "annotation_serialization_failed",
98
- "verification_failed",
99
- "write_conflict",
100
- ];
101
- /** Runtime guard for `code`, primarily useful when classifying an unknown IPC rejection (mirrors
102
- * the narrowing `parseHostError` does for `ClassifiedError` in tauriBridge.ts). */
103
- export function isPdfEditErrorCode(code) {
104
- return typeof code === "string" && PDF_EDIT_ERROR_CODES.includes(code);
105
- }
@@ -1,100 +0,0 @@
1
- /** The editor tools this app exposes. "none" means the pure viewer (no AnnotationEditorLayer
2
- * active) — the default, matching the view-first invariant. Values mirror pdf.js's own
3
- * AnnotationEditorType numeric enum (kept here as a stable, decoupled mapping — see
4
- * ANNOTATION_EDITOR_TYPE below — so this file doesn't need the real pdfjs-dist import to be
5
- * unit-tested). */
6
- export type PdfEditorMode = "none" | "freeText" | "ink" | "highlight" | "stamp";
7
- export type PdfSaveFunction = () => Promise<Uint8Array | null>;
8
- /** Mirrors pdfjs-dist's `AnnotationEditorType` numeric values (checked against
9
- * node_modules/pdfjs-dist 6.2.108). Declared locally so pure helpers below don't need to import
10
- * the real (heavy) pdfjs-dist module. usePdfEditor.ts cross-checks these against the live
11
- * `pdfjs.AnnotationEditorType` export at runtime instead of trusting this duplication blindly. */
12
- export declare const ANNOTATION_EDITOR_TYPE: {
13
- readonly NONE: 0;
14
- readonly FREETEXT: 3;
15
- readonly HIGHLIGHT: 9;
16
- readonly STAMP: 13;
17
- readonly INK: 15;
18
- };
19
- export declare function modeToAnnotationEditorType(mode: PdfEditorMode): number;
20
- /**
21
- * pdf.js's low-level `TextLayer` renders into a caller-owned element, but
22
- * `AnnotationEditorLayer` expects the viewer-level shape `{ div }`. Keep that runtime contract
23
- * explicit so a raw `HTMLDivElement` or low-level `TextLayer` cannot be passed accidentally.
24
- */
25
- export declare function createPdfEditorTextLayerAdapter(div: HTMLDivElement): {
26
- readonly div: HTMLDivElement;
27
- };
28
- export interface PdfEditorToolDef {
29
- mode: PdfEditorMode;
30
- label: string;
31
- title: string;
32
- }
33
- export declare const PDF_EDITOR_TOOLS: PdfEditorToolDef[];
34
- /** This app's own precise contract for `AnnotationEditorUIManager.addCommands`'s single argument
35
- * (pdf.js itself types it as a loose `Object` — see comment above). Field semantics reverse-
36
- * engineered from `CommandManager#add` in node_modules/pdfjs-dist/build/pdf.mjs. */
37
- export interface PdfCommandManagerCommand {
38
- /** Applies the command. Run synchronously inside `addCommands` when `mustExec` is true, and again
39
- * on every `redo()`. */
40
- cmd: () => void;
41
- /** Reverts the command. Run on every `undo()`. */
42
- undo: () => void;
43
- /** Optional side effect run immediately after `undo`/`cmd` on `undo()`/`redo()` respectively (not
44
- * on the initial `addCommands` call itself) — `CommandManager#undo`/`#redo` both call
45
- * `post?.()` right after invoking `undo`/`cmd`. */
46
- post?: () => void;
47
- /** When true, `cmd` runs immediately inside `addCommands` (not deferred to first redo). Every
48
- * call site inside pdf.js itself passes `true`. */
49
- mustExec: boolean;
50
- /** Numeric command-type tag consulted only by `overwriteIfSameType` (in-place replacement of the
51
- * current history entry) and `cleanUndoStack(type)`; pdf.js never validates or restricts this
52
- * value itself. See SOURCE_TEXT_COMMAND below for this app's reserved tag. */
53
- type?: number;
54
- /** When true, and the entry at the manager's current history position has a matching `type`,
55
- * `addCommands` overwrites that entry in place instead of pushing a new history entry — used by
56
- * pdf.js for live-dragging param updates (e.g. a font-size slider generating many intermediate
57
- * values that should collapse to one undo step). */
58
- overwriteIfSameType?: boolean;
59
- /** Only meaningful together with `overwriteIfSameType: true` — when true, an in-place overwrite
60
- * keeps the *original* entry's `undo` callback instead of replacing it with the new one. */
61
- keepUndo?: boolean;
62
- }
63
- /** The subset of pdf.js's `AnnotationEditorUIManager` this app relies on for §6.2's unified
64
- * document history, typed precisely (see PdfCommandManagerCommand above) so call sites do not need
65
- * usePdfEditor.ts's broader `AnyUIManager` escape hatch just to push one source-text command. */
66
- export interface PdfCommandManagerHost {
67
- addCommands: (params: PdfCommandManagerCommand) => void;
68
- undo: () => void;
69
- redo: () => void;
70
- }
71
- /** This app's reserved `AnnotationEditorUIManager` command-type tag (§6.2) for source-text edits.
72
- * Checked against every command-type value pdf.js itself uses internally
73
- * (node_modules/pdfjs-dist/build/pdf.mjs): `AnnotationEditorParamsType` tops out at 41
74
- * (DRAW_STEP) and `AnnotationEditorType` tops out at 102 (COMMENT) — neither collides with
75
- * 0x5652 (22098). Collision would not corrupt history regardless (this app always passes
76
- * `overwriteIfSameType: false`, so `type` is never compared against pdf.js's own command types),
77
- * but a distinct, verified-unique value keeps entries identifiable if that ever changes. */
78
- export declare const SOURCE_TEXT_COMMAND = 22098;
79
- /** Minimal source-edit session contract `pushSourceCommand` drives: applying, reverting, and
80
- * publishing one staged edit. Kept generic over the command payload (`TCommand`) so this file does
81
- * not couple to whichever module currently owns the concrete PdfEditCommand/session-controller
82
- * shape (§6, §12 — usePdfEditSession.ts) — matching this file's existing house style of staying
83
- * dependency-free of heavier pdf.js/session types (see file header). */
84
- export interface PdfSourceCommandSession<TCommand> {
85
- /** Applies `command` to the session's staged source-edit state (e.g. append/replace it in
86
- * `sourceCommands`, recompute `sourceDigest`). */
87
- apply: (command: TCommand) => void;
88
- /** Reverts the effect of `apply(command)`. */
89
- revert: (command: TCommand) => void;
90
- /** Runs after every apply/revert reached through undo or redo — the hook for the §9.4 in-memory
91
- * preview recompose. Not invoked by `pushSourceCommand` itself on the initial push (mirrors
92
- * `CommandManager#add`, which only calls `post` from `undo()`/`redo()`, never from `add()`). */
93
- publish: () => void;
94
- }
95
- /**
96
- * Pushes one source-text edit onto pdf.js's shared `AnnotationEditorUIManager` command history
97
- * (§6.2) so source-text and annotation edits undo/redo in one chronological order instead of two
98
- * independent stacks. Do not maintain a second, independent undo stack for source edits.
99
- */
100
- export declare function pushSourceCommand<TCommand>(uiManager: PdfCommandManagerHost, session: PdfSourceCommandSession<TCommand>, command: TCommand): void;
@@ -1,68 +0,0 @@
1
- // Stage 1 PDF editing — pure helpers shared between the toolbar and usePdfEditor. Kept dependency-
2
- // free of pdfjs-dist's class exports (those are only imported where the real UIManager is built) so
3
- // this module is trivial to unit test.
4
- /** Mirrors pdfjs-dist's `AnnotationEditorType` numeric values (checked against
5
- * node_modules/pdfjs-dist 6.2.108). Declared locally so pure helpers below don't need to import
6
- * the real (heavy) pdfjs-dist module. usePdfEditor.ts cross-checks these against the live
7
- * `pdfjs.AnnotationEditorType` export at runtime instead of trusting this duplication blindly. */
8
- export const ANNOTATION_EDITOR_TYPE = {
9
- NONE: 0,
10
- FREETEXT: 3,
11
- HIGHLIGHT: 9,
12
- STAMP: 13,
13
- INK: 15,
14
- };
15
- export function modeToAnnotationEditorType(mode) {
16
- switch (mode) {
17
- case "freeText":
18
- return ANNOTATION_EDITOR_TYPE.FREETEXT;
19
- case "ink":
20
- return ANNOTATION_EDITOR_TYPE.INK;
21
- case "highlight":
22
- return ANNOTATION_EDITOR_TYPE.HIGHLIGHT;
23
- case "stamp":
24
- return ANNOTATION_EDITOR_TYPE.STAMP;
25
- default:
26
- return ANNOTATION_EDITOR_TYPE.NONE;
27
- }
28
- }
29
- /**
30
- * pdf.js's low-level `TextLayer` renders into a caller-owned element, but
31
- * `AnnotationEditorLayer` expects the viewer-level shape `{ div }`. Keep that runtime contract
32
- * explicit so a raw `HTMLDivElement` or low-level `TextLayer` cannot be passed accidentally.
33
- */
34
- export function createPdfEditorTextLayerAdapter(div) {
35
- return { div };
36
- }
37
- // "Sign" here is a drawn/typed/image stamp placed on the page — NOT cryptographic PKI signing,
38
- // which pdf.js does not implement. Keep the toolbar copy honest about that (see PdfToolbar.tsx).
39
- export const PDF_EDITOR_TOOLS = [
40
- { mode: "freeText", label: "text", title: "Add text" },
41
- { mode: "ink", label: "draw", title: "Draw (ink)" },
42
- { mode: "highlight", label: "highlight", title: "Highlight" },
43
- { mode: "stamp", label: "image", title: "Add image stamp" },
44
- ];
45
- /** This app's reserved `AnnotationEditorUIManager` command-type tag (§6.2) for source-text edits.
46
- * Checked against every command-type value pdf.js itself uses internally
47
- * (node_modules/pdfjs-dist/build/pdf.mjs): `AnnotationEditorParamsType` tops out at 41
48
- * (DRAW_STEP) and `AnnotationEditorType` tops out at 102 (COMMENT) — neither collides with
49
- * 0x5652 (22098). Collision would not corrupt history regardless (this app always passes
50
- * `overwriteIfSameType: false`, so `type` is never compared against pdf.js's own command types),
51
- * but a distinct, verified-unique value keeps entries identifiable if that ever changes. */
52
- export const SOURCE_TEXT_COMMAND = 0x5652;
53
- /**
54
- * Pushes one source-text edit onto pdf.js's shared `AnnotationEditorUIManager` command history
55
- * (§6.2) so source-text and annotation edits undo/redo in one chronological order instead of two
56
- * independent stacks. Do not maintain a second, independent undo stack for source edits.
57
- */
58
- export function pushSourceCommand(uiManager, session, command) {
59
- uiManager.addCommands({
60
- cmd: () => session.apply(command),
61
- undo: () => session.revert(command),
62
- post: () => session.publish(),
63
- mustExec: true,
64
- type: SOURCE_TEXT_COMMAND,
65
- overwriteIfSameType: false,
66
- keepUndo: false,
67
- });
68
- }
@@ -1,36 +0,0 @@
1
- import type { PDFPageProxy } from "pdfjs-dist";
2
- export type OcrRect = {
3
- x: number;
4
- y: number;
5
- width: number;
6
- height: number;
7
- };
8
- export type OcrLine = {
9
- text: string;
10
- rect: OcrRect;
11
- confidence: number | null;
12
- };
13
- /** These prefixes are a cross-language contract with src-tauri/crates/ocr/src/lib.rs; they must not drift. */
14
- export declare const WINDOWS_OCR_UNAVAILABLE_PREFIX = "windows-ocr-unavailable:";
15
- export declare const MACOS_VISION_UNAVAILABLE_PREFIX = "macos-vision-unavailable:";
16
- export declare const OCR_UNSUPPORTED_PLATFORM_PREFIX = "ocr-unsupported-platform:";
17
- /**
18
- * Fast eligibility check used while browsing. It reads only the streamed text layer, so opening
19
- * a document or changing pages never asks pdf.js to decode every page's operator list.
20
- */
21
- export declare function isTextlessPage(page: PDFPageProxy): Promise<boolean>;
22
- /**
23
- * Scanned-page recognition is offered only when there is no usable text and the page paints an
24
- * image: streamed text is authoritative because WKWebView's pdf.js worker can leave a parallel
25
- * getTextContent() request empty even while the visible streamed text layer has content, and the
26
- * image check prevents genuinely blank pages from being sent to OCR.
27
- */
28
- export declare function isProbablyScannedPage(page: PDFPageProxy): Promise<boolean>;
29
- /**
30
- * Rasterizes one PDF page at 300 DPI by default. 300 DPI is the standard floor for reliable text
31
- * recognition on scanned documents; pdf.js's default page space is 72 DPI, so the scale converts
32
- * directly from points to the requested pixel density.
33
- */
34
- export declare function renderPageToPng(page: PDFPageProxy, dpi?: number, rotation?: number): Promise<Blob>;
35
- export { ocrPage, ocrAvailable, ocrBackendMissing } from "../../state/tauriBridge.js";
36
- export declare function isBackendUnavailable(message: string): boolean;