@rightkit/document-core 0.1.2 → 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 (126) hide show
  1. package/CHANGELOG.md +23 -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 -46
  16. package/dist/index.js +1 -46
  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 -47
  22. package/dist/state/tauriBridge.js +6 -162
  23. package/dist/styles.css +2 -2
  24. package/package.json +16 -87
  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 -287
  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
@@ -71,7 +71,7 @@ export declare function readRelativeScript(docPath: string, rel: string, rootPat
71
71
  * rejection (escapes the granted root, not an openable type). The grant is brokered in Rust. */
72
72
  export declare function grantRelativeFile(docPath: string, rel: string, rootPath?: string, siteToken?: string): Promise<string | null>;
73
73
  /** Infer and grant this HTML tab's site root (nearest enclosing project directory), returning the
74
- * opaque token that backs `viewright-site://` subresource URLs plus the granted directory for
74
+ * opaque token that backs `<host id>-site://` subresource URLs plus the granted directory for
75
75
  * display. Returns null outside Tauri, so browser/dev/test builds fall back to inlining. */
76
76
  export declare function grantSiteRoot(docPath: string): Promise<{
77
77
  token: string;
@@ -103,6 +103,7 @@ export declare function revokePath(path: string): Promise<void>;
103
103
  /** Write text, preserving the file's `encoding` (default UTF-8). Returns actual encoding plus the
104
104
  * committed source SHA-256; in-place callers send the prior SHA for stale-source protection. */
105
105
  export declare function writeDocument(path: string, content: string, encoding?: string, expectedSourceSha256?: string): Promise<WriteDocumentResult>;
106
+ export declare function byteArrayToBase64(bytes: Uint8Array): string;
106
107
  export declare function writeDocumentBytes(path: string, data: ArrayBuffer): Promise<void>;
107
108
  /** Copy an already-authorized document to a user-selected write target without decoding or
108
109
  * reserializing its bytes. The desktop command owns both broker checks and the filesystem copy so
@@ -111,51 +112,6 @@ export declare function copyDocument(sourcePath: string, targetPath: string): Pr
111
112
  /** Open a web/mail link in the system browser (never navigate the app webview away). */
112
113
  export declare function openExternal(url: string): Promise<void>;
113
114
  export declare function editImageExternal(path: string): Promise<void>;
114
- import type { ComposePdfPreview, CommitPdfSave, InspectPdfPage, ListPdfFonts, PreparePdfSave } from "../documents/pdf/pdfEditModel.js";
115
- import type { OcrLine } from "../documents/pdf/pdfOcr.js";
116
- /** OCR one rasterized PDF page. The PNG is the raw request body, not JSON metadata. */
117
- export declare const ocrPage: (png: ArrayBuffer | Uint8Array) => Promise<OcrLine[]>;
118
- /** Probe whether native OCR can be offered. This deliberately returns false outside Tauri instead
119
- * of using requireTauriForPdfEdit: callers use it to decide whether to offer recognition at all.
120
- * Non-throwing contract: a backend/IPC failure resolves false. */
121
- export declare const ocrAvailable: () => Promise<boolean>;
122
- export declare const ocrBackendMissing: () => Promise<boolean>;
123
- /** §5.2 `inspect_pdf_page`. Walks one page's content stream and returns its authoritative source
124
- * graph (islands, locators, digests). `path` must already be a broker-granted read target. */
125
- export declare const inspectPdfPage: InspectPdfPage;
126
- /** §7.2 `list_pdf_fonts`. Returns the bundled + system font catalog available for embedding. */
127
- export declare const listPdfFonts: ListPdfFonts;
128
- /** §9.4 `compose_pdf_preview`. Memory-only recomposition of staged source commands against fresh
129
- * disk bytes, for committed-unsaved-edit preview re-render — no token, no retained candidate, no
130
- * writes. Candidate bytes use JSON; affected pages derive from request commands. */
131
- export declare const composePdfPreview: ComposePdfPreview;
132
- /** §10.1 `prepare_pdf_save`. The frozen frontend `PreparePdfSave` type (`pdfEditModel.ts`) expects
133
- * one call returning `PreparedPdfSave` (metadata + `candidateBytes` together), but the actual Rust
134
- * implementation returns candidate bytes as a numeric JSON array because WKWebView cannot
135
- * reliably consume this staged candidate through Tauri's raw-response or large-base64 paths.
136
- *
137
- * Judgment call: this bridge function internally calls both backend commands in sequence and
138
- * combines their results into the single `PreparedPdfSave` shape B7's `pdfSave.ts` was written
139
- * against, so the frozen frontend type/signature is satisfied without B7 needing to know about the
140
- * two-call split. `expectedText` field names (`page`/`text`) come from the backend's
141
- * `ExpectedTextCheck { page, text }`; mapped here to `pdfEditModel.ts`'s `PdfExpectedTextCheck`
142
- * shape (`page`/`islandId`/`expectedText`) — no `islandId` exists in the backend response, so it is
143
- * populated as an empty string (the backend recheck matches by page + text substring only, not by
144
- * island id; see `pdf_save.rs`'s `structurally_verify_candidate`). */
145
- export declare const preparePdfSave: PreparePdfSave;
146
- /** §10.3 `commit_pdf_save`. Consumes the single-use save token and atomically writes the staged
147
- * candidate to `targetPath` (or back to the original source path for a same-path Save). The
148
- * backend's `PdfCommitResult` (`pdf_save.rs`) carries only `{ targetPath, documentSha256 }` — it
149
- * has no `revision`/`affectedPages` fields, unlike the richer shape `pdfEditModel.ts` sketches as
150
- * "inferred" (that file's own comment flags this exact field set as not given anywhere in the
151
- * contract text). Rather than fabricate an `affectedPages`/`revision` this command never returns,
152
- * this bridge function follows the caller-refresh pattern already used elsewhere in this file
153
- * (e.g. `readDocument`'s post-write re-read): the caller (`pdfSave.ts`) is expected to re-run
154
- * `inspectPdfPage` per page after a successful commit to obtain a fresh revision, rather than this
155
- * bridge inventing data. `committedPath`/`committedSha256` map 1:1 from the backend's
156
- * `targetPath`/`documentSha256`; `affectedPages` is returned empty and `revision` as an
157
- * empty-pages placeholder so the return type still satisfies `PdfCommitResult` structurally. */
158
- export declare const commitPdfSave: CommitPdfSave;
159
115
  export declare function setInspectableHtmlPreview(token: string | null): void;
160
116
  /** Clear the DevTools owner, but only if `token` still owns it (a newer frame may have replaced it). */
161
117
  export declare function releaseInspectableHtmlPreview(token: string): void;
@@ -163,7 +119,7 @@ export declare function releaseInspectableHtmlPreview(token: string): void;
163
119
  * content window that has no IPC, and the shell opens that window's inspector (decision D2). The
164
120
  * main webview is never inspectable. No-op without an active HTML preview or outside Tauri. */
165
121
  export declare function openDevtools(): Promise<void>;
166
- /** No-op: the macOS inspect-accelerator scope command was removed with the shell port (viewright#375). */
122
+ /** No-op: the macOS inspect-accelerator scope command was removed with the shell port (host shell port). */
167
123
  export declare function setDevtoolsShortcutScope(_enabled: boolean): Promise<void>;
168
124
  export declare function revealInFileExplorer(path: string): Promise<void>;
169
125
  /** What the clipboard held when "Open from clipboard" / paste ran. Files win, then a bitmap (written
@@ -1,6 +1,7 @@
1
1
  import { baseName, formatFromPath, normalizeViewMode, } from "../documents/types.js";
2
2
  import { isTauri } from "@rightkit/platform-ui";
3
3
  import { createShell } from "@rightkit/tauri-shell";
4
+ import { hostHeader, hostScheme } from "../host.js";
4
5
  /** True when running inside the Tauri webview (vs. plain `vite dev` in a browser). */
5
6
  const inTauri = isTauri;
6
7
  let shell = null;
@@ -82,7 +83,7 @@ export async function readDocument(path) {
82
83
  const { convertFileSrc } = await import("@tauri-apps/api/core");
83
84
  if (!raw.stream_token)
84
85
  throw new Error("binary stream token missing");
85
- assetUrl = `${convertFileSrc(raw.stream_token, "viewright-stream")}?t=${Date.now()}`;
86
+ assetUrl = `${convertFileSrc(raw.stream_token, hostScheme("stream"))}?t=${Date.now()}`;
86
87
  }
87
88
  let viewMeta;
88
89
  if (raw.view_meta) {
@@ -183,7 +184,7 @@ export async function grantRelativeFile(docPath, rel, rootPath, siteToken) {
183
184
  }
184
185
  }
185
186
  /** Infer and grant this HTML tab's site root (nearest enclosing project directory), returning the
186
- * opaque token that backs `viewright-site://` subresource URLs plus the granted directory for
187
+ * opaque token that backs `<host id>-site://` subresource URLs plus the granted directory for
187
188
  * display. Returns null outside Tauri, so browser/dev/test builds fall back to inlining. */
188
189
  export async function grantSiteRoot(docPath) {
189
190
  if (!inTauri())
@@ -280,7 +281,7 @@ export async function writeDocument(path, content, encoding, expectedSourceSha25
280
281
  // changing writeDocumentBytes's contract (out of scope here) — and a 32k-arg spread/apply call is
281
282
  // exactly the call-stack-pressure risk the loop below was already written to avoid. Not a clear
282
283
  // improvement, so kept unchanged per the audit's own guidance.
283
- function byteArrayToBase64(bytes) {
284
+ export function byteArrayToBase64(bytes) {
284
285
  let bin = "";
285
286
  const chunk = 0x8000;
286
287
  for (let i = 0; i < bytes.length; i += chunk) {
@@ -301,7 +302,7 @@ export async function writeDocumentBytes(path, data) {
301
302
  // the main thread. The target path rides in a hex header so any filesystem path is header-safe.
302
303
  const { invoke: tauriInvoke } = await import("@tauri-apps/api/core");
303
304
  await tauriInvoke("write_document_base64", new Uint8Array(data), {
304
- headers: { "x-viewright-path-hex": pathToHex(path) },
305
+ headers: { [hostHeader("path-hex")]: pathToHex(path) },
305
306
  });
306
307
  }
307
308
  function pathToHex(path) {
@@ -338,163 +339,6 @@ export async function editImageExternal(path) {
338
339
  return;
339
340
  await invoke("edit_image_external", { path });
340
341
  }
341
- /** Normalizes an `invoke()` raw-body result (an `ArrayBuffer`, or occasionally already a
342
- * `Uint8Array`/plain byte array depending on Tauri's IPC transport) into a `Uint8Array`. */
343
- function toUint8Array(body) {
344
- if (body instanceof Uint8Array)
345
- return body;
346
- if (body instanceof ArrayBuffer)
347
- return new Uint8Array(body);
348
- if (Array.isArray(body))
349
- return new Uint8Array(body);
350
- throw new Error("Expected a raw byte response from the PDF bridge.");
351
- }
352
- /** Every other bridge function in this file short-circuits outside a real Tauri webview
353
- * (`readDocument`, `fileFingerprint`, `getInitialOpenPaths`, …) rather than letting `invoke()`'s
354
- * dynamic `@tauri-apps/api/core` import reach into `window.__TAURI_INTERNALS__`, which is
355
- * `undefined` there and throws a raw, unclassified "Cannot read properties of undefined (reading
356
- * 'invoke')" instead of a `ClassifiedError` a caller's existing catch/`errorMessage` handling can
357
- * show meaningfully. These six PDF-editor commands need the real Rust backend for source
358
- * inspection/composition/save, so the correct graceful behavior is a clean, classified rejection
359
- * rather than either a raw crash or a fabricated result. */
360
- function requireTauriForPdfEdit(command) {
361
- if (!inTauri()) {
362
- throw { code: "unsupported_outside_tauri", message: `${command} requires the native app` };
363
- }
364
- }
365
- /** OCR one rasterized PDF page. The PNG is the raw request body, not JSON metadata. */
366
- export const ocrPage = async (png) => {
367
- // Browser QA has no Rust OCR backend, so the IPC-boundary fixture keeps the scanned-page UI
368
- // exercisable without moving a mock into the document components.
369
- requireTauriForPdfEdit("ocr_page");
370
- const { invoke: tauriInvoke } = await import("@tauri-apps/api/core");
371
- return tauriInvoke("ocr_page", png);
372
- };
373
- // Cached OCR-capability probe. OCR capability cannot change mid-session, so N concurrent
374
- // PdfViewer mounts share ONE `ocr_available` invoke instead of one IPC each. A failed probe is
375
- // NOT cached (reset below) — the next caller retries instead of pinning a transient IPC error.
376
- let ocrAvailableProbe = null;
377
- /** Probe whether native OCR can be offered. This deliberately returns false outside Tauri instead
378
- * of using requireTauriForPdfEdit: callers use it to decide whether to offer recognition at all.
379
- * Non-throwing contract: a backend/IPC failure resolves false. */
380
- export const ocrAvailable = () => {
381
- // Browser QA has no Rust OCR backend, so the IPC-boundary fixture keeps the scanned-page UI
382
- // exercisable without moving a mock into the document components.
383
- if (!inTauri())
384
- return Promise.resolve(false);
385
- ocrAvailableProbe ??= invoke("ocr_available").catch(() => {
386
- ocrAvailableProbe = null;
387
- return false;
388
- });
389
- return ocrAvailableProbe;
390
- };
391
- /** True only when the backend answered that this machine has no OCR. A timeout, an IPC failure or
392
- * running outside Tauri is not an answer: OCR stays offered and the run itself reports the
393
- * failure. Only a real answer is cached for the session. */
394
- let ocrBackendAnswer = null;
395
- export const ocrBackendMissing = () => {
396
- if (!inTauri())
397
- return Promise.resolve(false);
398
- ocrBackendAnswer ??= invoke("ocr_available").then((available) => available === false, () => {
399
- ocrBackendAnswer = null;
400
- return false;
401
- });
402
- return ocrBackendAnswer;
403
- };
404
- /** §5.2 `inspect_pdf_page`. Walks one page's content stream and returns its authoritative source
405
- * graph (islands, locators, digests). `path` must already be a broker-granted read target. */
406
- export const inspectPdfPage = async (path, page) => {
407
- // Browser QA has no Rust content-stream walker, so the IPC-boundary fixture keeps Edit-text mode
408
- // reachable/non-crashing (islands always empty — source-text editing stays native-only).
409
- requireTauriForPdfEdit("inspect_pdf_page");
410
- return invoke("inspect_pdf_page", { path, page });
411
- };
412
- /** §7.2 `list_pdf_fonts`. Returns the bundled + system font catalog available for embedding. */
413
- export const listPdfFonts = async () => {
414
- requireTauriForPdfEdit("list_pdf_fonts");
415
- return invoke("list_pdf_fonts");
416
- };
417
- /** §9.4 `compose_pdf_preview`. Memory-only recomposition of staged source commands against fresh
418
- * disk bytes, for committed-unsaved-edit preview re-render — no token, no retained candidate, no
419
- * writes. Candidate bytes use JSON; affected pages derive from request commands. */
420
- export const composePdfPreview = async (request) => {
421
- requireTauriForPdfEdit("compose_pdf_preview");
422
- const body = await invoke("compose_pdf_preview", {
423
- request: {
424
- sourcePath: request.sourcePath,
425
- expectedSourceSha256: request.expectedSourceSha256,
426
- sourceCommands: request.sourceCommands,
427
- },
428
- });
429
- const pages = new Set();
430
- for (const command of request.sourceCommands) {
431
- pages.add(command.kind === "replaceSourceText" ? command.locator.page : command.page);
432
- }
433
- return {
434
- candidateBytes: toUint8Array(body),
435
- affectedPages: Array.from(pages).sort((a, b) => a - b),
436
- };
437
- };
438
- /** §10.1 `prepare_pdf_save`. The frozen frontend `PreparePdfSave` type (`pdfEditModel.ts`) expects
439
- * one call returning `PreparedPdfSave` (metadata + `candidateBytes` together), but the actual Rust
440
- * implementation returns candidate bytes as a numeric JSON array because WKWebView cannot
441
- * reliably consume this staged candidate through Tauri's raw-response or large-base64 paths.
442
- *
443
- * Judgment call: this bridge function internally calls both backend commands in sequence and
444
- * combines their results into the single `PreparedPdfSave` shape B7's `pdfSave.ts` was written
445
- * against, so the frozen frontend type/signature is satisfied without B7 needing to know about the
446
- * two-call split. `expectedText` field names (`page`/`text`) come from the backend's
447
- * `ExpectedTextCheck { page, text }`; mapped here to `pdfEditModel.ts`'s `PdfExpectedTextCheck`
448
- * shape (`page`/`islandId`/`expectedText`) — no `islandId` exists in the backend response, so it is
449
- * populated as an empty string (the backend recheck matches by page + text substring only, not by
450
- * island id; see `pdf_save.rs`'s `structurally_verify_candidate`). */
451
- export const preparePdfSave = async (request) => {
452
- requireTauriForPdfEdit("prepare_pdf_save");
453
- const meta = await invoke("prepare_pdf_save", {
454
- request: {
455
- sourcePath: request.sourcePath,
456
- expectedSourceSha256: request.expectedSourceSha256,
457
- annotationPdfBase64: byteArrayToBase64(request.annotationPdfBytes),
458
- sourceCommands: request.sourceCommands,
459
- },
460
- });
461
- return {
462
- token: meta.token,
463
- candidateSha256: meta.candidateSha256,
464
- candidateBytes: Uint8Array.from(meta.candidateBytes),
465
- affectedPages: meta.affectedPages,
466
- expectedText: meta.expectedText.map((check) => ({
467
- page: check.page,
468
- islandId: "",
469
- expectedText: check.text,
470
- })),
471
- };
472
- };
473
- /** §10.3 `commit_pdf_save`. Consumes the single-use save token and atomically writes the staged
474
- * candidate to `targetPath` (or back to the original source path for a same-path Save). The
475
- * backend's `PdfCommitResult` (`pdf_save.rs`) carries only `{ targetPath, documentSha256 }` — it
476
- * has no `revision`/`affectedPages` fields, unlike the richer shape `pdfEditModel.ts` sketches as
477
- * "inferred" (that file's own comment flags this exact field set as not given anywhere in the
478
- * contract text). Rather than fabricate an `affectedPages`/`revision` this command never returns,
479
- * this bridge function follows the caller-refresh pattern already used elsewhere in this file
480
- * (e.g. `readDocument`'s post-write re-read): the caller (`pdfSave.ts`) is expected to re-run
481
- * `inspectPdfPage` per page after a successful commit to obtain a fresh revision, rather than this
482
- * bridge inventing data. `committedPath`/`committedSha256` map 1:1 from the backend's
483
- * `targetPath`/`documentSha256`; `affectedPages` is returned empty and `revision` as an
484
- * empty-pages placeholder so the return type still satisfies `PdfCommitResult` structurally. */
485
- export const commitPdfSave = async (token, targetPath) => {
486
- requireTauriForPdfEdit("commit_pdf_save");
487
- const result = await invoke("commit_pdf_save", {
488
- token,
489
- targetPath: targetPath ?? null,
490
- });
491
- return {
492
- committedPath: result.targetPath,
493
- committedSha256: result.documentSha256,
494
- affectedPages: [],
495
- revision: { documentSha256: result.documentSha256, pageCount: 0, pages: [] },
496
- };
497
- };
498
342
  /** Token of the interactive HTML preview that currently owns DevTools (the active tab's frame), or
499
343
  * null. Set by the HTML preview frame; DevTools opens exactly that registered document. */
500
344
  let inspectableHtmlToken = null;
@@ -515,7 +359,7 @@ export async function openDevtools() {
515
359
  return;
516
360
  await invoke("open_html_devtools", { token });
517
361
  }
518
- /** No-op: the macOS inspect-accelerator scope command was removed with the shell port (viewright#375). */
362
+ /** No-op: the macOS inspect-accelerator scope command was removed with the shell port (host shell port). */
519
363
  export async function setDevtoolsShortcutScope(_enabled) { }
520
364
  export async function revealInFileExplorer(path) {
521
365
  if (!inTauri())
package/dist/styles.css CHANGED
@@ -1,2 +1,2 @@
1
- /* Every stylesheet this package's components use. Hosts import "<package>/styles.css" once (Node cannot import CSS from JS). */
2
- @import "pdfjs-dist/web/pdf_viewer.css";
1
+ /* The editor base ships no stylesheet of its own. The PDF viewer styles (pdf.js `pdf_viewer.css`) moved
2
+ with the PDF editor to @rightkit/document-workspace in 0.2.0; this file stays so `<package>/styles.css` keeps resolving. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rightkit/document-core",
3
- "version": "0.1.2",
4
- "description": "Shared base for the document editors: platform bridge, settings, state, PDF helpers and the format registry.",
3
+ "version": "0.2.0",
4
+ "description": "Shared base for the document editors and the document workspace: document types and format registry, host bridge, drafts, diagnostics, settings store, find, print and toolbar primitives, and the one host-identity store.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -11,7 +11,6 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
13
  },
14
- "./styles.css": "./dist/styles.css",
15
14
  "./app/BlockDraftContext": {
16
15
  "types": "./dist/app/BlockDraftContext.d.ts",
17
16
  "import": "./dist/app/BlockDraftContext.js"
@@ -40,6 +39,10 @@
40
39
  "types": "./dist/app/nativePrintPreview.d.ts",
41
40
  "import": "./dist/app/nativePrintPreview.js"
42
41
  },
42
+ "./app/printPipelineShared": {
43
+ "types": "./dist/app/printPipelineShared.d.ts",
44
+ "import": "./dist/app/printPipelineShared.js"
45
+ },
43
46
  "./app/resourceCensus": {
44
47
  "types": "./dist/app/resourceCensus.d.ts",
45
48
  "import": "./dist/app/resourceCensus.js"
@@ -52,18 +55,6 @@
52
55
  "types": "./dist/app/shell/nativeMenu.d.ts",
53
56
  "import": "./dist/app/shell/nativeMenu.js"
54
57
  },
55
- "./app/shortcutChords": {
56
- "types": "./dist/app/shortcutChords.d.ts",
57
- "import": "./dist/app/shortcutChords.js"
58
- },
59
- "./app/useCloseFindOnSurfaceChange": {
60
- "types": "./dist/app/useCloseFindOnSurfaceChange.d.ts",
61
- "import": "./dist/app/useCloseFindOnSurfaceChange.js"
62
- },
63
- "./app/useEditText": {
64
- "types": "./dist/app/useEditText.d.ts",
65
- "import": "./dist/app/useEditText.js"
66
- },
67
58
  "./documents/BackToTopButton": {
68
59
  "types": "./dist/documents/BackToTopButton.d.ts",
69
60
  "import": "./dist/documents/BackToTopButton.js"
@@ -76,10 +67,6 @@
76
67
  "types": "./dist/documents/DocumentToolbarShell.d.ts",
77
68
  "import": "./dist/documents/DocumentToolbarShell.js"
78
69
  },
79
- "./documents/FullscreenIcon": {
80
- "types": "./dist/documents/FullscreenIcon.d.ts",
81
- "import": "./dist/documents/FullscreenIcon.js"
82
- },
83
70
  "./documents/PreviewChrome": {
84
71
  "types": "./dist/documents/PreviewChrome.d.ts",
85
72
  "import": "./dist/documents/PreviewChrome.js"
@@ -92,33 +79,9 @@
92
79
  "types": "./dist/documents/base64.d.ts",
93
80
  "import": "./dist/documents/base64.js"
94
81
  },
95
- "./documents/mdx/mdxRuntimeScript": {
96
- "types": "./dist/documents/mdx/mdxRuntimeScript.d.ts",
97
- "import": "./dist/documents/mdx/mdxRuntimeScript.js"
98
- },
99
- "./documents/pdf/NativePdfDocument": {
100
- "types": "./dist/documents/pdf/NativePdfDocument.d.ts",
101
- "import": "./dist/documents/pdf/NativePdfDocument.js"
102
- },
103
- "./documents/pdf/PdfViewer": {
104
- "types": "./dist/documents/pdf/PdfViewer.d.ts",
105
- "import": "./dist/documents/pdf/PdfViewer.js"
106
- },
107
- "./documents/pdf/macPdfNativeBridge": {
108
- "types": "./dist/documents/pdf/macPdfNativeBridge.d.ts",
109
- "import": "./dist/documents/pdf/macPdfNativeBridge.js"
110
- },
111
- "./documents/pdf/pdfEditModel": {
112
- "types": "./dist/documents/pdf/pdfEditModel.d.ts",
113
- "import": "./dist/documents/pdf/pdfEditModel.js"
114
- },
115
- "./documents/pdf/pdfEditor": {
116
- "types": "./dist/documents/pdf/pdfEditor.d.ts",
117
- "import": "./dist/documents/pdf/pdfEditor.js"
118
- },
119
- "./documents/pdf/pdfToMarkdown": {
120
- "types": "./dist/documents/pdf/pdfToMarkdown.d.ts",
121
- "import": "./dist/documents/pdf/pdfToMarkdown.js"
82
+ "./documents/documentFormats": {
83
+ "types": "./dist/documents/documentFormats.d.ts",
84
+ "import": "./dist/documents/documentFormats.js"
122
85
  },
123
86
  "./documents/perfEventCounters": {
124
87
  "types": "./dist/documents/perfEventCounters.d.ts",
@@ -132,10 +95,6 @@
132
95
  "types": "./dist/documents/previewViewport.d.ts",
133
96
  "import": "./dist/documents/previewViewport.js"
134
97
  },
135
- "./documents/scopedSelectAll": {
136
- "types": "./dist/documents/scopedSelectAll.d.ts",
137
- "import": "./dist/documents/scopedSelectAll.js"
138
- },
139
98
  "./documents/searchUtils": {
140
99
  "types": "./dist/documents/searchUtils.d.ts",
141
100
  "import": "./dist/documents/searchUtils.js"
@@ -148,30 +107,23 @@
148
107
  "types": "./dist/documents/toolbarPrimitives.d.ts",
149
108
  "import": "./dist/documents/toolbarPrimitives.js"
150
109
  },
151
- "./documents/txt/cmScroll": {
152
- "types": "./dist/documents/txt/cmScroll.d.ts",
153
- "import": "./dist/documents/txt/cmScroll.js"
154
- },
155
110
  "./documents/types": {
156
111
  "types": "./dist/documents/types.d.ts",
157
112
  "import": "./dist/documents/types.js"
158
113
  },
159
- "./documents/useMirroredEditText": {
160
- "types": "./dist/documents/useMirroredEditText.d.ts",
161
- "import": "./dist/documents/useMirroredEditText.js"
162
- },
163
114
  "./documents/usePreviewFind": {
164
115
  "types": "./dist/documents/usePreviewFind.d.ts",
165
116
  "import": "./dist/documents/usePreviewFind.js"
166
117
  },
167
- "./documents/useSplitResize": {
168
- "types": "./dist/documents/useSplitResize.d.ts",
169
- "import": "./dist/documents/useSplitResize.js"
170
- },
171
118
  "./documents/web/webUrl": {
172
119
  "types": "./dist/documents/web/webUrl.d.ts",
173
120
  "import": "./dist/documents/web/webUrl.js"
174
121
  },
122
+ "./host": {
123
+ "types": "./dist/host.d.ts",
124
+ "import": "./dist/host.js"
125
+ },
126
+ "./package.json": "./package.json",
175
127
  "./platform": {
176
128
  "types": "./dist/platform.d.ts",
177
129
  "import": "./dist/platform.js"
@@ -180,27 +132,6 @@
180
132
  "types": "./dist/settings/fonts.d.ts",
181
133
  "import": "./dist/settings/fonts.js"
182
134
  },
183
- "./settings/rk-settings.css": "./dist/settings/rk-settings.css",
184
- "./settings/sections/EditorSection": {
185
- "types": "./dist/settings/sections/EditorSection.d.ts",
186
- "import": "./dist/settings/sections/EditorSection.js"
187
- },
188
- "./settings/sections/FileAssociationsSection": {
189
- "types": "./dist/settings/sections/FileAssociationsSection.d.ts",
190
- "import": "./dist/settings/sections/FileAssociationsSection.js"
191
- },
192
- "./settings/sections/ThemeSection": {
193
- "types": "./dist/settings/sections/ThemeSection.d.ts",
194
- "import": "./dist/settings/sections/ThemeSection.js"
195
- },
196
- "./settings/sections/TypographySection": {
197
- "types": "./dist/settings/sections/TypographySection.d.ts",
198
- "import": "./dist/settings/sections/TypographySection.js"
199
- },
200
- "./settings/sections/onOff": {
201
- "types": "./dist/settings/sections/onOff.d.ts",
202
- "import": "./dist/settings/sections/onOff.js"
203
- },
204
135
  "./settings/settings": {
205
136
  "types": "./dist/settings/settings.d.ts",
206
137
  "import": "./dist/settings/settings.js"
@@ -233,7 +164,7 @@
233
164
  "types": "./dist/state/tauriBridge.d.ts",
234
165
  "import": "./dist/state/tauriBridge.js"
235
166
  },
236
- "./package.json": "./package.json"
167
+ "./styles.css": "./dist/styles.css"
237
168
  },
238
169
  "files": [
239
170
  "dist",
@@ -246,7 +177,6 @@
246
177
  "*.css"
247
178
  ],
248
179
  "dependencies": {
249
- "@codemirror/view": "^6.43.14",
250
180
  "@phosphor-icons/react": "^2.1.10",
251
181
  "@rightkit/license": "^0.3.1",
252
182
  "@rightkit/logs": "^0.1.6",
@@ -256,8 +186,7 @@
256
186
  "@rightkit/settings-ui": "^0.7.1",
257
187
  "@rightkit/tauri-shell": "^0.1.4",
258
188
  "@rightkit/theme": "^0.3.2",
259
- "@tauri-apps/api": "^2.12.2",
260
- "pdfjs-dist": "6.4.299"
189
+ "@tauri-apps/api": "^2.12.2"
261
190
  },
262
191
  "peerDependencies": {
263
192
  "react": ">=18 <21",
@@ -1,6 +0,0 @@
1
- /**
2
- * Chords for "Ctrl, Meta or both, no Alt" shortcuts, for handlers that used to test
3
- * `(event.metaKey || event.ctrlKey)` by hand. The shortcut registry matches modifiers exactly, so the
4
- * three Ctrl/Meta combinations are listed; `shift` selects which Shift states are accepted.
5
- */
6
- export declare function ctrlMetaChords(key: string, shift?: readonly boolean[]): string[];
@@ -1,14 +0,0 @@
1
- /**
2
- * Chords for "Ctrl, Meta or both, no Alt" shortcuts, for handlers that used to test
3
- * `(event.metaKey || event.ctrlKey)` by hand. The shortcut registry matches modifiers exactly, so the
4
- * three Ctrl/Meta combinations are listed; `shift` selects which Shift states are accepted.
5
- */
6
- export function ctrlMetaChords(key, shift = [false]) {
7
- const chords = [];
8
- for (const withShift of shift) {
9
- for (const mods of ["ctrl", "meta", "ctrl+meta"]) {
10
- chords.push(`${mods}${withShift ? "+shift" : ""}+${key}`);
11
- }
12
- }
13
- return chords;
14
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Close the shared find bar whenever a document switches between its rendered surface and its raw
3
- * source.
4
- *
5
- * Both surfaces register a search provider into the SAME path-scoped slot — a CodeMirror "source"
6
- * provider for the raw text, a rendered provider for the preview/editor. Switching between them
7
- * therefore swaps the provider underneath an open find bar, silently retargeting the user's query
8
- * at completely different text with no visible cue that it happened. Closing find on the switch
9
- * makes the user reopen it against whichever surface they actually meant.
10
- *
11
- * `surfaceKey` is anything that identifies the current surface (a boolean like `showSource` is
12
- * typical); find closes on any change to it.
13
- */
14
- export declare function useCloseFindOnSurfaceChange(surfaceKey: unknown, findOpen: boolean, onCloseFind?: () => void): void;
@@ -1,23 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- /**
3
- * Close the shared find bar whenever a document switches between its rendered surface and its raw
4
- * source.
5
- *
6
- * Both surfaces register a search provider into the SAME path-scoped slot — a CodeMirror "source"
7
- * provider for the raw text, a rendered provider for the preview/editor. Switching between them
8
- * therefore swaps the provider underneath an open find bar, silently retargeting the user's query
9
- * at completely different text with no visible cue that it happened. Closing find on the switch
10
- * makes the user reopen it against whichever surface they actually meant.
11
- *
12
- * `surfaceKey` is anything that identifies the current surface (a boolean like `showSource` is
13
- * typical); find closes on any change to it.
14
- */
15
- export function useCloseFindOnSurfaceChange(surfaceKey, findOpen, onCloseFind) {
16
- const previousSurfaceRef = useRef(surfaceKey);
17
- useEffect(() => {
18
- const previous = previousSurfaceRef.current;
19
- previousSurfaceRef.current = surfaceKey;
20
- if (previous !== surfaceKey && findOpen)
21
- onCloseFind?.();
22
- }, [surfaceKey, findOpen, onCloseFind]);
23
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Subscribe a component to ONE document's live unsaved-edit text from the edits store (useDocumentTabs).
3
- * Re-renders only this component when that path's edits change — App and the rest of the chrome stay put.
4
- * Consumers: the bottom bar (word-count/dirty) and each tab's live title (LiveTitle).
5
- */
6
- export declare function useEditText(subscribeEdits: (path: string, cb: () => void) => () => void, getEditSnapshot: (path: string) => string | undefined, path: string): string | undefined;
@@ -1,10 +0,0 @@
1
- import { useCallback, useSyncExternalStore } from "react";
2
- /**
3
- * Subscribe a component to ONE document's live unsaved-edit text from the edits store (useDocumentTabs).
4
- * Re-renders only this component when that path's edits change — App and the rest of the chrome stay put.
5
- * Consumers: the bottom bar (word-count/dirty) and each tab's live title (LiveTitle).
6
- */
7
- export function useEditText(subscribeEdits, getEditSnapshot, path) {
8
- const subscribe = useCallback((cb) => subscribeEdits(path, cb), [subscribeEdits, path]);
9
- return useSyncExternalStore(subscribe, () => getEditSnapshot(path));
10
- }
package/dist/appName.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function setHostAppName(name: string): void;
2
- export declare function hostAppName(): string;
package/dist/appName.js DELETED
@@ -1,8 +0,0 @@
1
- // Product name shown in user-facing copy. Hosts call setHostAppName() once at startup.
2
- let current = "App";
3
- export function setHostAppName(name) {
4
- current = name;
5
- }
6
- export function hostAppName() {
7
- return current;
8
- }
@@ -1,4 +0,0 @@
1
- /** Fullscreen enter/exit glyph — shared by the HTML, Markdown, and MDX source-drawer toggles. */
2
- export declare function FullscreenIcon({ restore }: {
3
- restore: boolean;
4
- }): import("react").JSX.Element;
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { ArrowsIn } from "@phosphor-icons/react/dist/icons/ArrowsIn";
3
- import { ArrowsOut } from "@phosphor-icons/react/dist/icons/ArrowsOut";
4
- /** Fullscreen enter/exit glyph — shared by the HTML, Markdown, and MDX source-drawer toggles. */
5
- export function FullscreenIcon({ restore }) {
6
- return restore ? (_jsx(ArrowsIn, { size: 14, weight: "regular", "aria-hidden": "true" })) : (_jsx(ArrowsOut, { size: 14, weight: "regular", "aria-hidden": "true" }));
7
- }
@@ -1,2 +0,0 @@
1
- export declare const mdxRuntimeScript: string;
2
- export default mdxRuntimeScript;