@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.
- package/CHANGELOG.md +29 -0
- package/README.md +31 -7
- package/dist/app/chrome.js +1 -1
- package/dist/app/documentPrinting.d.ts +0 -6
- package/dist/app/documentPrinting.js +0 -18
- package/dist/app/shell/nativeMenu.d.ts +3 -2
- package/dist/app/shell/nativeMenu.js +8 -5
- package/dist/documents/perfEventCounters.d.ts +0 -8
- package/dist/documents/perfEventCounters.js +2 -1
- package/dist/documents/preview/previewFrame.d.ts +2 -1
- package/dist/documents/preview/previewFrame.js +9 -7
- package/dist/documents/searchUtils.js +1 -1
- package/dist/host.d.ts +36 -0
- package/dist/host.js +54 -0
- package/dist/index.d.ts +1 -50
- package/dist/index.js +1 -50
- package/dist/settings/themes.js +1 -1
- package/dist/state/bridgeEvents.d.ts +1 -1
- package/dist/state/bridgeEvents.js +7 -4
- package/dist/state/recentUrls.js +4 -3
- package/dist/state/tauriBridge.d.ts +3 -61
- package/dist/state/tauriBridge.js +8 -297
- package/dist/styles.css +2 -2
- package/package.json +25 -98
- package/dist/app/shortcutChords.d.ts +0 -6
- package/dist/app/shortcutChords.js +0 -14
- package/dist/app/useCloseFindOnSurfaceChange.d.ts +0 -14
- package/dist/app/useCloseFindOnSurfaceChange.js +0 -23
- package/dist/app/useEditText.d.ts +0 -6
- package/dist/app/useEditText.js +0 -10
- package/dist/appName.d.ts +0 -2
- package/dist/appName.js +0 -8
- package/dist/documents/FullscreenIcon.d.ts +0 -4
- package/dist/documents/FullscreenIcon.js +0 -7
- package/dist/documents/mdx/mdxRuntimeScript.d.ts +0 -2
- package/dist/documents/mdx/mdxRuntimeScript.js +0 -3
- package/dist/documents/mdx/mdxRuntimeScript.txt +0 -584
- package/dist/documents/pdf/MacPdfReadPane.d.ts +0 -23
- package/dist/documents/pdf/MacPdfReadPane.js +0 -708
- package/dist/documents/pdf/NativePdfDocument.d.ts +0 -9
- package/dist/documents/pdf/NativePdfDocument.js +0 -41
- package/dist/documents/pdf/PdfInlineTextEditor.d.ts +0 -53
- package/dist/documents/pdf/PdfInlineTextEditor.js +0 -225
- package/dist/documents/pdf/PdfOcrLayer.d.ts +0 -4
- package/dist/documents/pdf/PdfOcrLayer.js +0 -30
- package/dist/documents/pdf/PdfOutline.d.ts +0 -6
- package/dist/documents/pdf/PdfOutline.js +0 -12
- package/dist/documents/pdf/PdfPasswordPrompt.d.ts +0 -5
- package/dist/documents/pdf/PdfPasswordPrompt.js +0 -24
- package/dist/documents/pdf/PdfThumbnails.d.ts +0 -8
- package/dist/documents/pdf/PdfThumbnails.js +0 -201
- package/dist/documents/pdf/PdfToolbar.d.ts +0 -47
- package/dist/documents/pdf/PdfToolbar.js +0 -76
- package/dist/documents/pdf/PdfViewer.d.ts +0 -36
- package/dist/documents/pdf/PdfViewer.js +0 -1522
- package/dist/documents/pdf/PdfViewerBody.d.ts +0 -22
- package/dist/documents/pdf/PdfViewerBody.js +0 -42
- package/dist/documents/pdf/macPdfNativeBridge.d.ts +0 -118
- package/dist/documents/pdf/macPdfNativeBridge.js +0 -134
- package/dist/documents/pdf/nearestVisiblePdfPage.d.ts +0 -2
- package/dist/documents/pdf/nearestVisiblePdfPage.js +0 -22
- package/dist/documents/pdf/pdfBench.d.ts +0 -88
- package/dist/documents/pdf/pdfBench.js +0 -535
- package/dist/documents/pdf/pdfBenchAutopilot.d.ts +0 -48
- package/dist/documents/pdf/pdfBenchAutopilot.js +0 -154
- package/dist/documents/pdf/pdfBenchTransport.d.ts +0 -21
- package/dist/documents/pdf/pdfBenchTransport.js +0 -233
- package/dist/documents/pdf/pdfEditModel.d.ts +0 -294
- package/dist/documents/pdf/pdfEditModel.js +0 -105
- package/dist/documents/pdf/pdfEditor.d.ts +0 -100
- package/dist/documents/pdf/pdfEditor.js +0 -68
- package/dist/documents/pdf/pdfOcr.d.ts +0 -36
- package/dist/documents/pdf/pdfOcr.js +0 -88
- package/dist/documents/pdf/pdfOcrEdit.d.ts +0 -32
- package/dist/documents/pdf/pdfOcrEdit.js +0 -138
- package/dist/documents/pdf/pdfPrinting.d.ts +0 -28
- package/dist/documents/pdf/pdfPrinting.js +0 -110
- package/dist/documents/pdf/pdfSave.d.ts +0 -87
- package/dist/documents/pdf/pdfSave.js +0 -250
- package/dist/documents/pdf/pdfShared.d.ts +0 -16
- package/dist/documents/pdf/pdfShared.js +0 -20
- package/dist/documents/pdf/pdfToMarkdown.d.ts +0 -11
- package/dist/documents/pdf/pdfToMarkdown.js +0 -67
- package/dist/documents/pdf/pdfjsLibGlobal.d.ts +0 -1
- package/dist/documents/pdf/pdfjsLibGlobal.js +0 -12
- package/dist/documents/pdf/toolbarIcons.d.ts +0 -18
- package/dist/documents/pdf/toolbarIcons.js +0 -31
- package/dist/documents/pdf/usePdfDocumentLoader.d.ts +0 -40
- package/dist/documents/pdf/usePdfDocumentLoader.js +0 -243
- package/dist/documents/pdf/usePdfEditSession.d.ts +0 -88
- package/dist/documents/pdf/usePdfEditSession.js +0 -341
- package/dist/documents/pdf/usePdfEditor.d.ts +0 -59
- package/dist/documents/pdf/usePdfEditor.js +0 -317
- package/dist/documents/pdf/usePdfFit.d.ts +0 -19
- package/dist/documents/pdf/usePdfFit.js +0 -55
- package/dist/documents/pdf/usePdfOcr.d.ts +0 -38
- package/dist/documents/pdf/usePdfOcr.js +0 -337
- package/dist/documents/pdf/usePdfPreviewRecompose.d.ts +0 -28
- package/dist/documents/pdf/usePdfPreviewRecompose.js +0 -256
- package/dist/documents/pdf/usePdfSavePlan.d.ts +0 -61
- package/dist/documents/pdf/usePdfSavePlan.js +0 -303
- package/dist/documents/pdf/usePdfSearch.d.ts +0 -31
- package/dist/documents/pdf/usePdfSearch.js +0 -367
- package/dist/documents/pdf/usePdfViewControls.d.ts +0 -72
- package/dist/documents/pdf/usePdfViewControls.js +0 -152
- package/dist/documents/scopedSelectAll.d.ts +0 -5
- package/dist/documents/scopedSelectAll.js +0 -77
- package/dist/documents/txt/cmScroll.d.ts +0 -11
- package/dist/documents/txt/cmScroll.js +0 -52
- package/dist/documents/useMirroredEditText.d.ts +0 -15
- package/dist/documents/useMirroredEditText.js +0 -29
- package/dist/documents/useSplitResize.d.ts +0 -7
- package/dist/documents/useSplitResize.js +0 -37
- package/dist/settings/rk-settings.css +0 -38
- package/dist/settings/sections/EditorSection.d.ts +0 -1
- package/dist/settings/sections/EditorSection.js +0 -18
- package/dist/settings/sections/FileAssociationsSection.d.ts +0 -1
- package/dist/settings/sections/FileAssociationsSection.js +0 -5
- package/dist/settings/sections/MacFileAssociationsBlock.d.ts +0 -33
- package/dist/settings/sections/MacFileAssociationsBlock.js +0 -151
- package/dist/settings/sections/ThemeSection.d.ts +0 -1
- package/dist/settings/sections/ThemeSection.js +0 -31
- package/dist/settings/sections/TypographySection.d.ts +0 -1
- package/dist/settings/sections/TypographySection.js +0 -19
- package/dist/settings/sections/onOff.d.ts +0 -11
- package/dist/settings/sections/onOff.js +0 -8
- package/dist/state/browserQa.d.ts +0 -21
- package/dist/state/browserQa.js +0 -303
- package/dist/state/browserQaDocx.d.ts +0 -3
- package/dist/state/browserQaDocx.js +0 -35
- package/dist/state/browserQaLicense.d.ts +0 -8
- package/dist/state/browserQaLicense.js +0 -7
- package/dist/state/browserQaPdf.d.ts +0 -60
- package/dist/state/browserQaPdf.js +0 -302
- package/dist/state/browserQaText.d.ts +0 -6
- package/dist/state/browserQaText.js +0 -48
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type FileFingerprint, type LoadedDocument } from "../documents/types.js";
|
|
2
|
-
import type { LicenseClient } from "@rightkit/license";
|
|
3
2
|
import { isTauri } from "@rightkit/platform-ui";
|
|
4
3
|
import { type Shell } from "@rightkit/tauri-shell";
|
|
5
4
|
/** True when running inside the Tauri webview (vs. plain `vite dev` in a browser). */
|
|
@@ -12,7 +11,6 @@ export declare function getShell(): Shell;
|
|
|
12
11
|
* reports a copy that did not happen (an absent browser clipboard used to read as success).
|
|
13
12
|
*/
|
|
14
13
|
export declare function writeClipboardText(text: string): Promise<void>;
|
|
15
|
-
export declare function isBrowserQaMode(): boolean;
|
|
16
14
|
declare function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
|
|
17
15
|
declare function listen<T>(event: string, callback: (event: {
|
|
18
16
|
payload: T;
|
|
@@ -26,12 +24,6 @@ export declare const nativeIpc: {
|
|
|
26
24
|
invoke: typeof invoke;
|
|
27
25
|
listen: typeof listen;
|
|
28
26
|
};
|
|
29
|
-
/**
|
|
30
|
-
* Browser-QA licence client (`@rightkit/license/testing`, in-memory, no network). Returns null
|
|
31
|
-
* outside browser QA, so the caller uses the native client. The `testing` export resolves only
|
|
32
|
-
* under the `development` condition and the call site folds to `false` in a release build.
|
|
33
|
-
*/
|
|
34
|
-
export declare function browserQaLicenseClient(): Promise<LicenseClient | null>;
|
|
35
27
|
/** Classified shape every bridge caller can rely on. `code` matches the Rust `HostError`
|
|
36
28
|
* variant in snake_case (e.g. "broker_denied", "file_not_found"), or "unknown" when the rejection
|
|
37
29
|
* didn't carry the envelope shape at all (a raw JS Error, a plain string, or something else). */
|
|
@@ -79,7 +71,7 @@ export declare function readRelativeScript(docPath: string, rel: string, rootPat
|
|
|
79
71
|
* rejection (escapes the granted root, not an openable type). The grant is brokered in Rust. */
|
|
80
72
|
export declare function grantRelativeFile(docPath: string, rel: string, rootPath?: string, siteToken?: string): Promise<string | null>;
|
|
81
73
|
/** Infer and grant this HTML tab's site root (nearest enclosing project directory), returning the
|
|
82
|
-
* opaque token that backs
|
|
74
|
+
* opaque token that backs `<host id>-site://` subresource URLs plus the granted directory for
|
|
83
75
|
* display. Returns null outside Tauri, so browser/dev/test builds fall back to inlining. */
|
|
84
76
|
export declare function grantSiteRoot(docPath: string): Promise<{
|
|
85
77
|
token: string;
|
|
@@ -111,6 +103,7 @@ export declare function revokePath(path: string): Promise<void>;
|
|
|
111
103
|
/** Write text, preserving the file's `encoding` (default UTF-8). Returns actual encoding plus the
|
|
112
104
|
* committed source SHA-256; in-place callers send the prior SHA for stale-source protection. */
|
|
113
105
|
export declare function writeDocument(path: string, content: string, encoding?: string, expectedSourceSha256?: string): Promise<WriteDocumentResult>;
|
|
106
|
+
export declare function byteArrayToBase64(bytes: Uint8Array): string;
|
|
114
107
|
export declare function writeDocumentBytes(path: string, data: ArrayBuffer): Promise<void>;
|
|
115
108
|
/** Copy an already-authorized document to a user-selected write target without decoding or
|
|
116
109
|
* reserializing its bytes. The desktop command owns both broker checks and the filesystem copy so
|
|
@@ -119,57 +112,6 @@ export declare function copyDocument(sourcePath: string, targetPath: string): Pr
|
|
|
119
112
|
/** Open a web/mail link in the system browser (never navigate the app webview away). */
|
|
120
113
|
export declare function openExternal(url: string): Promise<void>;
|
|
121
114
|
export declare function editImageExternal(path: string): Promise<void>;
|
|
122
|
-
import type { ComposePdfPreview, CommitPdfSave, InspectPdfPage, ListPdfFonts, PreparePdfSave } from "../documents/pdf/pdfEditModel.js";
|
|
123
|
-
import type { OcrLine } from "../documents/pdf/pdfOcr.js";
|
|
124
|
-
/** OCR one rasterized PDF page. The PNG is the raw request body, not JSON metadata. */
|
|
125
|
-
export declare const ocrPage: (png: ArrayBuffer | Uint8Array) => Promise<OcrLine[]>;
|
|
126
|
-
/** Probe whether native OCR can be offered. This deliberately returns false outside Tauri instead
|
|
127
|
-
* of using requireTauriForPdfEdit: callers use it to decide whether to offer recognition at all.
|
|
128
|
-
* Non-throwing contract: a backend/IPC failure resolves false. */
|
|
129
|
-
export declare const ocrAvailable: () => Promise<boolean>;
|
|
130
|
-
export declare const ocrBackendMissing: () => Promise<boolean>;
|
|
131
|
-
/** §5.2 `inspect_pdf_page`. Walks one page's content stream and returns its authoritative source
|
|
132
|
-
* graph (islands, locators, digests). `path` must already be a broker-granted read target. */
|
|
133
|
-
export declare const inspectPdfPage: InspectPdfPage;
|
|
134
|
-
/** §7.2 `list_pdf_fonts`. Returns the bundled + system font catalog available for embedding. */
|
|
135
|
-
export declare const listPdfFonts: ListPdfFonts;
|
|
136
|
-
/** §9.4 `compose_pdf_preview`. Memory-only recomposition of staged source commands against fresh
|
|
137
|
-
* disk bytes, for committed-unsaved-edit preview re-render — no token, no retained candidate, no
|
|
138
|
-
* writes. Candidate bytes use JSON; affected pages derive from request commands. */
|
|
139
|
-
export declare const composePdfPreview: ComposePdfPreview;
|
|
140
|
-
/** §10.1 `prepare_pdf_save`. The frozen frontend `PreparePdfSave` type (`pdfEditModel.ts`) expects
|
|
141
|
-
* one call returning `PreparedPdfSave` (metadata + `candidateBytes` together), but the actual Rust
|
|
142
|
-
* implementation returns candidate bytes as a numeric JSON array because WKWebView cannot
|
|
143
|
-
* reliably consume this staged candidate through Tauri's raw-response or large-base64 paths.
|
|
144
|
-
*
|
|
145
|
-
* Judgment call: this bridge function internally calls both backend commands in sequence and
|
|
146
|
-
* combines their results into the single `PreparedPdfSave` shape B7's `pdfSave.ts` was written
|
|
147
|
-
* against, so the frozen frontend type/signature is satisfied without B7 needing to know about the
|
|
148
|
-
* two-call split. `expectedText` field names (`page`/`text`) come from the backend's
|
|
149
|
-
* `ExpectedTextCheck { page, text }`; mapped here to `pdfEditModel.ts`'s `PdfExpectedTextCheck`
|
|
150
|
-
* shape (`page`/`islandId`/`expectedText`) — no `islandId` exists in the backend response, so it is
|
|
151
|
-
* populated as an empty string (the backend recheck matches by page + text substring only, not by
|
|
152
|
-
* island id; see `pdf_save.rs`'s `structurally_verify_candidate`). */
|
|
153
|
-
export declare const preparePdfSave: PreparePdfSave;
|
|
154
|
-
/** §10.3 `commit_pdf_save`. Consumes the single-use save token and atomically writes the staged
|
|
155
|
-
* candidate to `targetPath` (or back to the original source path for a same-path Save). The
|
|
156
|
-
* backend's `PdfCommitResult` (`pdf_save.rs`) carries only `{ targetPath, documentSha256 }` — it
|
|
157
|
-
* has no `revision`/`affectedPages` fields, unlike the richer shape `pdfEditModel.ts` sketches as
|
|
158
|
-
* "inferred" (that file's own comment flags this exact field set as not given anywhere in the
|
|
159
|
-
* contract text). Rather than fabricate an `affectedPages`/`revision` this command never returns,
|
|
160
|
-
* this bridge function follows the caller-refresh pattern already used elsewhere in this file
|
|
161
|
-
* (e.g. `readDocument`'s post-write re-read): the caller (`pdfSave.ts`) is expected to re-run
|
|
162
|
-
* `inspectPdfPage` per page after a successful commit to obtain a fresh revision, rather than this
|
|
163
|
-
* bridge inventing data. `committedPath`/`committedSha256` map 1:1 from the backend's
|
|
164
|
-
* `targetPath`/`documentSha256`; `affectedPages` is returned empty and `revision` as an
|
|
165
|
-
* empty-pages placeholder so the return type still satisfies `PdfCommitResult` structurally. */
|
|
166
|
-
export declare const commitPdfSave: CommitPdfSave;
|
|
167
|
-
/** Browser-QA-only: current bytes of the in-memory QA PDF "disk" at `path`, or `null` outside QA
|
|
168
|
-
* mode / for an untouched path. PdfViewer.tsx's post-commit reload uses this instead of
|
|
169
|
-
* re-fetching its `url` prop — a real Tauri stream token is a revocable token that re-resolves to
|
|
170
|
-
* the same (now-committed) file on every fetch, but browser QA's `url` is a static `data:` URL
|
|
171
|
-
* captured once at document-open time, which can never reflect a later commit on its own. */
|
|
172
|
-
export declare function qaReloadPdfBytes(path: string): Promise<Uint8Array | null>;
|
|
173
115
|
export declare function setInspectableHtmlPreview(token: string | null): void;
|
|
174
116
|
/** Clear the DevTools owner, but only if `token` still owns it (a newer frame may have replaced it). */
|
|
175
117
|
export declare function releaseInspectableHtmlPreview(token: string): void;
|
|
@@ -177,7 +119,7 @@ export declare function releaseInspectableHtmlPreview(token: string): void;
|
|
|
177
119
|
* content window that has no IPC, and the shell opens that window's inspector (decision D2). The
|
|
178
120
|
* main webview is never inspectable. No-op without an active HTML preview or outside Tauri. */
|
|
179
121
|
export declare function openDevtools(): Promise<void>;
|
|
180
|
-
/** No-op: the macOS inspect-accelerator scope command was removed with the shell port (
|
|
122
|
+
/** No-op: the macOS inspect-accelerator scope command was removed with the shell port (host shell port). */
|
|
181
123
|
export declare function setDevtoolsShortcutScope(_enabled: boolean): Promise<void>;
|
|
182
124
|
export declare function revealInFileExplorer(path: string): Promise<void>;
|
|
183
125
|
/** What the clipboard held when "Open from clipboard" / paste ran. Files win, then a bitmap (written
|
|
@@ -1,14 +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
|
-
|
|
5
|
-
// build-time constant), so production builds fold the guard to `false`, drop these dynamic imports,
|
|
6
|
-
// and never emit the fixture chunks. Keep static imports of these modules out of this file.
|
|
7
|
-
const loadQaFixtures = () => import("./browserQa.js");
|
|
8
|
-
const loadQaText = () => import("./browserQaText.js");
|
|
9
|
-
const loadQaDocx = () => import("./browserQaDocx.js");
|
|
10
|
-
const loadQaPdf = () => import("./browserQaPdf.js");
|
|
11
|
-
const loadQaLicense = () => import("./browserQaLicense.js");
|
|
4
|
+
import { hostHeader, hostScheme } from "../host.js";
|
|
12
5
|
/** True when running inside the Tauri webview (vs. plain `vite dev` in a browser). */
|
|
13
6
|
const inTauri = isTauri;
|
|
14
7
|
let shell = null;
|
|
@@ -17,13 +10,6 @@ export function getShell() {
|
|
|
17
10
|
shell ??= createShell();
|
|
18
11
|
return shell;
|
|
19
12
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Build-time switch for the browser-QA fixtures: `true` in `vite dev` and in the
|
|
22
|
-
* `VITE_RIGHTKIT_BROWSER_QA=1` build, a literal `false` in production builds. Every QA branch in
|
|
23
|
-
* this module is guarded with it, so the minifier drops those branches and nothing references the
|
|
24
|
-
* `browserQa*` fixture modules in a production bundle.
|
|
25
|
-
*/
|
|
26
|
-
const BROWSER_QA_BUILD = import.meta.env?.DEV || import.meta.env?.VITE_RIGHTKIT_BROWSER_QA === "1";
|
|
27
13
|
/**
|
|
28
14
|
* Write text to the system clipboard: through the shell's native clipboard in the app, through the
|
|
29
15
|
* browser clipboard in browser QA. It rejects when no clipboard is available, so a caller never
|
|
@@ -39,15 +25,6 @@ export async function writeClipboardText(text) {
|
|
|
39
25
|
}
|
|
40
26
|
await navigator.clipboard.writeText(text);
|
|
41
27
|
}
|
|
42
|
-
export function isBrowserQaMode() {
|
|
43
|
-
const qaBuild = import.meta.env?.VITE_RIGHTKIT_BROWSER_QA === "1";
|
|
44
|
-
if (!import.meta.env?.DEV && !qaBuild)
|
|
45
|
-
return false;
|
|
46
|
-
if (typeof window === "undefined" || inTauri())
|
|
47
|
-
return false;
|
|
48
|
-
const params = new URLSearchParams(window.location.search);
|
|
49
|
-
return params.has("qa") || qaBuild;
|
|
50
|
-
}
|
|
51
28
|
async function invoke(cmd, args) {
|
|
52
29
|
const { invoke } = await import("@tauri-apps/api/core");
|
|
53
30
|
return invoke(cmd, args);
|
|
@@ -62,16 +39,6 @@ async function listen(event, callback) {
|
|
|
62
39
|
* update Bearer; the webview only sends commands and receives validated display views.
|
|
63
40
|
*/
|
|
64
41
|
export const nativeIpc = { invoke, listen };
|
|
65
|
-
/**
|
|
66
|
-
* Browser-QA licence client (`@rightkit/license/testing`, in-memory, no network). Returns null
|
|
67
|
-
* outside browser QA, so the caller uses the native client. The `testing` export resolves only
|
|
68
|
-
* under the `development` condition and the call site folds to `false` in a release build.
|
|
69
|
-
*/
|
|
70
|
-
export async function browserQaLicenseClient() {
|
|
71
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
72
|
-
return (await loadQaLicense()).qaLicenseClient();
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
42
|
/** Classify an IPC rejection from `invoke()` into `{code, message}`. Tauri serializes a command's
|
|
76
43
|
* `Err(HostError)` using the envelope's own `#[serde(tag = "code", content = "message")]`
|
|
77
44
|
* representation, so a migrated command's rejection value IS already `{code, message}` — this
|
|
@@ -97,9 +64,6 @@ export function parseHostError(e) {
|
|
|
97
64
|
return { code: "unknown", message: String(e) };
|
|
98
65
|
}
|
|
99
66
|
export async function openFileDialog() {
|
|
100
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode()) {
|
|
101
|
-
return (await loadQaFixtures()).qaDialogPath();
|
|
102
|
-
}
|
|
103
67
|
if (!inTauri()) {
|
|
104
68
|
console.warn("openFileDialog: not in Tauri — open a real document via `pnpm tauri dev`.");
|
|
105
69
|
return null;
|
|
@@ -108,27 +72,6 @@ export async function openFileDialog() {
|
|
|
108
72
|
}
|
|
109
73
|
export async function readDocument(path) {
|
|
110
74
|
const format = formatFromPath(path);
|
|
111
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode()) {
|
|
112
|
-
const qaDocx = await loadQaDocx();
|
|
113
|
-
const qaText = await loadQaText();
|
|
114
|
-
const savedDocx = qaDocx.readQaDocxDocument({
|
|
115
|
-
path,
|
|
116
|
-
displayName: baseName(path),
|
|
117
|
-
format,
|
|
118
|
-
content: "",
|
|
119
|
-
});
|
|
120
|
-
if (savedDocx)
|
|
121
|
-
return savedDocx;
|
|
122
|
-
const doc = await (await loadQaFixtures()).qaDocumentForPath(path);
|
|
123
|
-
if (doc) {
|
|
124
|
-
if (format === "pdf") {
|
|
125
|
-
const assetUrl = await (await loadQaPdf()).qaCurrentPdfAssetUrl(path);
|
|
126
|
-
return { ...doc, assetUrl: assetUrl ?? doc.assetUrl };
|
|
127
|
-
}
|
|
128
|
-
return qaText.readQaTextDocument(doc);
|
|
129
|
-
}
|
|
130
|
-
return qaText.readQaTextDocument({ path, displayName: baseName(path), format, content: "" });
|
|
131
|
-
}
|
|
132
75
|
if (!inTauri()) {
|
|
133
76
|
return { path, displayName: baseName(path), format, content: "" };
|
|
134
77
|
}
|
|
@@ -140,7 +83,7 @@ export async function readDocument(path) {
|
|
|
140
83
|
const { convertFileSrc } = await import("@tauri-apps/api/core");
|
|
141
84
|
if (!raw.stream_token)
|
|
142
85
|
throw new Error("binary stream token missing");
|
|
143
|
-
assetUrl = `${convertFileSrc(raw.stream_token, "
|
|
86
|
+
assetUrl = `${convertFileSrc(raw.stream_token, hostScheme("stream"))}?t=${Date.now()}`;
|
|
144
87
|
}
|
|
145
88
|
let viewMeta;
|
|
146
89
|
if (raw.view_meta) {
|
|
@@ -191,10 +134,6 @@ export async function getPersistenceStatus() {
|
|
|
191
134
|
return { degraded: status.degraded === true, quarantinedTo: status.quarantined_to ?? null };
|
|
192
135
|
}
|
|
193
136
|
export async function getInitialOpenPaths() {
|
|
194
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode()) {
|
|
195
|
-
const path = (await loadQaFixtures()).qaInitialOpenPath();
|
|
196
|
-
return path ? [path] : [];
|
|
197
|
-
}
|
|
198
137
|
if (!inTauri())
|
|
199
138
|
return [];
|
|
200
139
|
// The shell's open-paths gate: it grants and drains what argv / a second launch / macOS
|
|
@@ -245,7 +184,7 @@ export async function grantRelativeFile(docPath, rel, rootPath, siteToken) {
|
|
|
245
184
|
}
|
|
246
185
|
}
|
|
247
186
|
/** Infer and grant this HTML tab's site root (nearest enclosing project directory), returning the
|
|
248
|
-
* opaque token that backs
|
|
187
|
+
* opaque token that backs `<host id>-site://` subresource URLs plus the granted directory for
|
|
249
188
|
* display. Returns null outside Tauri, so browser/dev/test builds fall back to inlining. */
|
|
250
189
|
export async function grantSiteRoot(docPath) {
|
|
251
190
|
if (!inTauri())
|
|
@@ -325,8 +264,6 @@ export async function revokePath(path) {
|
|
|
325
264
|
/** Write text, preserving the file's `encoding` (default UTF-8). Returns actual encoding plus the
|
|
326
265
|
* committed source SHA-256; in-place callers send the prior SHA for stale-source protection. */
|
|
327
266
|
export async function writeDocument(path, content, encoding, expectedSourceSha256) {
|
|
328
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
329
|
-
return (await loadQaText()).writeQaTextDocument(path, content, encoding, expectedSourceSha256);
|
|
330
267
|
if (!inTauri())
|
|
331
268
|
throw new Error("Saving requires the desktop app.");
|
|
332
269
|
const result = await invoke("write_document", {
|
|
@@ -344,10 +281,7 @@ export async function writeDocument(path, content, encoding, expectedSourceSha25
|
|
|
344
281
|
// changing writeDocumentBytes's contract (out of scope here) — and a 32k-arg spread/apply call is
|
|
345
282
|
// exactly the call-stack-pressure risk the loop below was already written to avoid. Not a clear
|
|
346
283
|
// improvement, so kept unchanged per the audit's own guidance.
|
|
347
|
-
function
|
|
348
|
-
return byteArrayToBase64(new Uint8Array(ab));
|
|
349
|
-
}
|
|
350
|
-
function byteArrayToBase64(bytes) {
|
|
284
|
+
export function byteArrayToBase64(bytes) {
|
|
351
285
|
let bin = "";
|
|
352
286
|
const chunk = 0x8000;
|
|
353
287
|
for (let i = 0; i < bytes.length; i += chunk) {
|
|
@@ -362,18 +296,13 @@ function byteArrayToBase64(bytes) {
|
|
|
362
296
|
return btoa(bin);
|
|
363
297
|
}
|
|
364
298
|
export async function writeDocumentBytes(path, data) {
|
|
365
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode()) {
|
|
366
|
-
if (formatFromPath(path) === "docx")
|
|
367
|
-
await (await loadQaDocx()).writeQaDocxDocument(path, data, arrayBufferToBase64(data));
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
299
|
if (!inTauri())
|
|
371
300
|
throw new Error("Saving requires the desktop app.");
|
|
372
301
|
// Raw request body (like ocr_page): the DOCX bytes cross IPC as-is, with no JS base64 encode on
|
|
373
302
|
// the main thread. The target path rides in a hex header so any filesystem path is header-safe.
|
|
374
303
|
const { invoke: tauriInvoke } = await import("@tauri-apps/api/core");
|
|
375
304
|
await tauriInvoke("write_document_base64", new Uint8Array(data), {
|
|
376
|
-
headers: { "
|
|
305
|
+
headers: { [hostHeader("path-hex")]: pathToHex(path) },
|
|
377
306
|
});
|
|
378
307
|
}
|
|
379
308
|
function pathToHex(path) {
|
|
@@ -386,8 +315,6 @@ function pathToHex(path) {
|
|
|
386
315
|
* reserializing its bytes. The desktop command owns both broker checks and the filesystem copy so
|
|
387
316
|
* PDF Save As preserves signatures, encryption, widgets, and any bytes pdf.js cannot round-trip. */
|
|
388
317
|
export async function copyDocument(sourcePath, targetPath) {
|
|
389
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
390
|
-
return;
|
|
391
318
|
if (!inTauri())
|
|
392
319
|
throw new Error("Saving requires the desktop app.");
|
|
393
320
|
await invoke("copy_document", { sourcePath, targetPath });
|
|
@@ -412,191 +339,6 @@ export async function editImageExternal(path) {
|
|
|
412
339
|
return;
|
|
413
340
|
await invoke("edit_image_external", { path });
|
|
414
341
|
}
|
|
415
|
-
import { hostAppName } from "../appName.js";
|
|
416
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
417
|
-
void loadQaPdf().then((qaPdf) => qaPdf.registerViewrightQaGlobal());
|
|
418
|
-
/** Normalizes an `invoke()` raw-body result (an `ArrayBuffer`, or occasionally already a
|
|
419
|
-
* `Uint8Array`/plain byte array depending on Tauri's IPC transport) into a `Uint8Array`. */
|
|
420
|
-
function toUint8Array(body) {
|
|
421
|
-
if (body instanceof Uint8Array)
|
|
422
|
-
return body;
|
|
423
|
-
if (body instanceof ArrayBuffer)
|
|
424
|
-
return new Uint8Array(body);
|
|
425
|
-
if (Array.isArray(body))
|
|
426
|
-
return new Uint8Array(body);
|
|
427
|
-
throw new Error("Expected a raw byte response from the PDF bridge.");
|
|
428
|
-
}
|
|
429
|
-
/** Every other bridge function in this file short-circuits outside a real Tauri webview
|
|
430
|
-
* (`readDocument`, `fileFingerprint`, `getInitialOpenPaths`, …) rather than letting `invoke()`'s
|
|
431
|
-
* dynamic `@tauri-apps/api/core` import reach into `window.__TAURI_INTERNALS__`, which is
|
|
432
|
-
* `undefined` there and throws a raw, unclassified "Cannot read properties of undefined (reading
|
|
433
|
-
* 'invoke')" instead of a `ClassifiedError` a caller's existing catch/`errorMessage` handling can
|
|
434
|
-
* show meaningfully. These six PDF-editor commands have no browser-QA fixture to fall back to
|
|
435
|
-
* (unlike `readDocument`'s `qaDocumentForPath`) — a real Rust backend is unavoidable for source
|
|
436
|
-
* inspection/composition/save — so the correct graceful behavior is a clean, classified rejection
|
|
437
|
-
* rather than either a raw crash or a fabricated result. */
|
|
438
|
-
function requireTauriForPdfEdit(command) {
|
|
439
|
-
if (!inTauri()) {
|
|
440
|
-
throw { code: "unsupported_outside_tauri", message: `${command} requires the native app` };
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
/** OCR one rasterized PDF page. The PNG is the raw request body, not JSON metadata. */
|
|
444
|
-
export const ocrPage = async (png) => {
|
|
445
|
-
// Browser QA has no Rust OCR backend, so the IPC-boundary fixture keeps the scanned-page UI
|
|
446
|
-
// exercisable without moving a mock into the document components.
|
|
447
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
448
|
-
return (await loadQaFixtures()).qaOcrLines();
|
|
449
|
-
requireTauriForPdfEdit("ocr_page");
|
|
450
|
-
const { invoke: tauriInvoke } = await import("@tauri-apps/api/core");
|
|
451
|
-
return tauriInvoke("ocr_page", png);
|
|
452
|
-
};
|
|
453
|
-
// Cached OCR-capability probe. OCR capability cannot change mid-session, so N concurrent
|
|
454
|
-
// PdfViewer mounts share ONE `ocr_available` invoke instead of one IPC each. A failed probe is
|
|
455
|
-
// NOT cached (reset below) — the next caller retries instead of pinning a transient IPC error.
|
|
456
|
-
let ocrAvailableProbe = null;
|
|
457
|
-
/** Probe whether native OCR can be offered. This deliberately returns false outside Tauri instead
|
|
458
|
-
* of using requireTauriForPdfEdit: callers use it to decide whether to offer recognition at all.
|
|
459
|
-
* Non-throwing contract: a backend/IPC failure resolves false. */
|
|
460
|
-
export const ocrAvailable = () => {
|
|
461
|
-
// Browser QA has no Rust OCR backend, so the IPC-boundary fixture keeps the scanned-page UI
|
|
462
|
-
// exercisable without moving a mock into the document components.
|
|
463
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
464
|
-
return Promise.resolve(true);
|
|
465
|
-
if (!inTauri())
|
|
466
|
-
return Promise.resolve(false);
|
|
467
|
-
ocrAvailableProbe ??= invoke("ocr_available").catch(() => {
|
|
468
|
-
ocrAvailableProbe = null;
|
|
469
|
-
return false;
|
|
470
|
-
});
|
|
471
|
-
return ocrAvailableProbe;
|
|
472
|
-
};
|
|
473
|
-
/** True only when the backend answered that this machine has no OCR. A timeout, an IPC failure or
|
|
474
|
-
* running outside Tauri is not an answer: OCR stays offered and the run itself reports the
|
|
475
|
-
* failure. Only a real answer is cached for the session. */
|
|
476
|
-
let ocrBackendAnswer = null;
|
|
477
|
-
export const ocrBackendMissing = () => {
|
|
478
|
-
if (!inTauri())
|
|
479
|
-
return Promise.resolve(false);
|
|
480
|
-
ocrBackendAnswer ??= invoke("ocr_available").then((available) => available === false, () => {
|
|
481
|
-
ocrBackendAnswer = null;
|
|
482
|
-
return false;
|
|
483
|
-
});
|
|
484
|
-
return ocrBackendAnswer;
|
|
485
|
-
};
|
|
486
|
-
/** §5.2 `inspect_pdf_page`. Walks one page's content stream and returns its authoritative source
|
|
487
|
-
* graph (islands, locators, digests). `path` must already be a broker-granted read target. */
|
|
488
|
-
export const inspectPdfPage = async (path, page) => {
|
|
489
|
-
// Browser QA has no Rust content-stream walker, so the IPC-boundary fixture keeps Edit-text mode
|
|
490
|
-
// reachable/non-crashing (islands always empty — source-text editing stays native-only).
|
|
491
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
492
|
-
return (await loadQaPdf()).qaInspectPdfPage(path, page);
|
|
493
|
-
requireTauriForPdfEdit("inspect_pdf_page");
|
|
494
|
-
return invoke("inspect_pdf_page", { path, page });
|
|
495
|
-
};
|
|
496
|
-
/** §7.2 `list_pdf_fonts`. Returns the bundled + system font catalog available for embedding. */
|
|
497
|
-
export const listPdfFonts = async () => {
|
|
498
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
499
|
-
return (await loadQaPdf()).qaListPdfFonts();
|
|
500
|
-
requireTauriForPdfEdit("list_pdf_fonts");
|
|
501
|
-
return invoke("list_pdf_fonts");
|
|
502
|
-
};
|
|
503
|
-
/** §9.4 `compose_pdf_preview`. Memory-only recomposition of staged source commands against fresh
|
|
504
|
-
* disk bytes, for committed-unsaved-edit preview re-render — no token, no retained candidate, no
|
|
505
|
-
* writes. Candidate bytes use JSON; affected pages derive from request commands. */
|
|
506
|
-
export const composePdfPreview = async (request) => {
|
|
507
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
508
|
-
return (await loadQaPdf()).qaComposePdfPreview(request);
|
|
509
|
-
requireTauriForPdfEdit("compose_pdf_preview");
|
|
510
|
-
const body = await invoke("compose_pdf_preview", {
|
|
511
|
-
request: {
|
|
512
|
-
sourcePath: request.sourcePath,
|
|
513
|
-
expectedSourceSha256: request.expectedSourceSha256,
|
|
514
|
-
sourceCommands: request.sourceCommands,
|
|
515
|
-
},
|
|
516
|
-
});
|
|
517
|
-
const pages = new Set();
|
|
518
|
-
for (const command of request.sourceCommands) {
|
|
519
|
-
pages.add(command.kind === "replaceSourceText" ? command.locator.page : command.page);
|
|
520
|
-
}
|
|
521
|
-
return {
|
|
522
|
-
candidateBytes: toUint8Array(body),
|
|
523
|
-
affectedPages: Array.from(pages).sort((a, b) => a - b),
|
|
524
|
-
};
|
|
525
|
-
};
|
|
526
|
-
/** §10.1 `prepare_pdf_save`. The frozen frontend `PreparePdfSave` type (`pdfEditModel.ts`) expects
|
|
527
|
-
* one call returning `PreparedPdfSave` (metadata + `candidateBytes` together), but the actual Rust
|
|
528
|
-
* implementation returns candidate bytes as a numeric JSON array because WKWebView cannot
|
|
529
|
-
* reliably consume this staged candidate through Tauri's raw-response or large-base64 paths.
|
|
530
|
-
*
|
|
531
|
-
* Judgment call: this bridge function internally calls both backend commands in sequence and
|
|
532
|
-
* combines their results into the single `PreparedPdfSave` shape B7's `pdfSave.ts` was written
|
|
533
|
-
* against, so the frozen frontend type/signature is satisfied without B7 needing to know about the
|
|
534
|
-
* two-call split. `expectedText` field names (`page`/`text`) come from the backend's
|
|
535
|
-
* `ExpectedTextCheck { page, text }`; mapped here to `pdfEditModel.ts`'s `PdfExpectedTextCheck`
|
|
536
|
-
* shape (`page`/`islandId`/`expectedText`) — no `islandId` exists in the backend response, so it is
|
|
537
|
-
* populated as an empty string (the backend recheck matches by page + text substring only, not by
|
|
538
|
-
* island id; see `pdf_save.rs`'s `structurally_verify_candidate`). */
|
|
539
|
-
export const preparePdfSave = async (request) => {
|
|
540
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
541
|
-
return (await loadQaPdf()).qaPreparePdfSave(request);
|
|
542
|
-
requireTauriForPdfEdit("prepare_pdf_save");
|
|
543
|
-
const meta = await invoke("prepare_pdf_save", {
|
|
544
|
-
request: {
|
|
545
|
-
sourcePath: request.sourcePath,
|
|
546
|
-
expectedSourceSha256: request.expectedSourceSha256,
|
|
547
|
-
annotationPdfBase64: byteArrayToBase64(request.annotationPdfBytes),
|
|
548
|
-
sourceCommands: request.sourceCommands,
|
|
549
|
-
},
|
|
550
|
-
});
|
|
551
|
-
return {
|
|
552
|
-
token: meta.token,
|
|
553
|
-
candidateSha256: meta.candidateSha256,
|
|
554
|
-
candidateBytes: Uint8Array.from(meta.candidateBytes),
|
|
555
|
-
affectedPages: meta.affectedPages,
|
|
556
|
-
expectedText: meta.expectedText.map((check) => ({
|
|
557
|
-
page: check.page,
|
|
558
|
-
islandId: "",
|
|
559
|
-
expectedText: check.text,
|
|
560
|
-
})),
|
|
561
|
-
};
|
|
562
|
-
};
|
|
563
|
-
/** §10.3 `commit_pdf_save`. Consumes the single-use save token and atomically writes the staged
|
|
564
|
-
* candidate to `targetPath` (or back to the original source path for a same-path Save). The
|
|
565
|
-
* backend's `PdfCommitResult` (`pdf_save.rs`) carries only `{ targetPath, documentSha256 }` — it
|
|
566
|
-
* has no `revision`/`affectedPages` fields, unlike the richer shape `pdfEditModel.ts` sketches as
|
|
567
|
-
* "inferred" (that file's own comment flags this exact field set as not given anywhere in the
|
|
568
|
-
* contract text). Rather than fabricate an `affectedPages`/`revision` this command never returns,
|
|
569
|
-
* this bridge function follows the caller-refresh pattern already used elsewhere in this file
|
|
570
|
-
* (e.g. `readDocument`'s post-write re-read): the caller (`pdfSave.ts`) is expected to re-run
|
|
571
|
-
* `inspectPdfPage` per page after a successful commit to obtain a fresh revision, rather than this
|
|
572
|
-
* bridge inventing data. `committedPath`/`committedSha256` map 1:1 from the backend's
|
|
573
|
-
* `targetPath`/`documentSha256`; `affectedPages` is returned empty and `revision` as an
|
|
574
|
-
* empty-pages placeholder so the return type still satisfies `PdfCommitResult` structurally. */
|
|
575
|
-
export const commitPdfSave = async (token, targetPath) => {
|
|
576
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
577
|
-
return (await loadQaPdf()).qaCommitPdfSave(token, targetPath);
|
|
578
|
-
requireTauriForPdfEdit("commit_pdf_save");
|
|
579
|
-
const result = await invoke("commit_pdf_save", {
|
|
580
|
-
token,
|
|
581
|
-
targetPath: targetPath ?? null,
|
|
582
|
-
});
|
|
583
|
-
return {
|
|
584
|
-
committedPath: result.targetPath,
|
|
585
|
-
committedSha256: result.documentSha256,
|
|
586
|
-
affectedPages: [],
|
|
587
|
-
revision: { documentSha256: result.documentSha256, pageCount: 0, pages: [] },
|
|
588
|
-
};
|
|
589
|
-
};
|
|
590
|
-
/** Browser-QA-only: current bytes of the in-memory QA PDF "disk" at `path`, or `null` outside QA
|
|
591
|
-
* mode / for an untouched path. PdfViewer.tsx's post-commit reload uses this instead of
|
|
592
|
-
* re-fetching its `url` prop — a real Tauri stream token is a revocable token that re-resolves to
|
|
593
|
-
* the same (now-committed) file on every fetch, but browser QA's `url` is a static `data:` URL
|
|
594
|
-
* captured once at document-open time, which can never reflect a later commit on its own. */
|
|
595
|
-
export async function qaReloadPdfBytes(path) {
|
|
596
|
-
if (!BROWSER_QA_BUILD || !isBrowserQaMode())
|
|
597
|
-
return null;
|
|
598
|
-
return (await loadQaPdf()).qaCurrentPdfBytes(path);
|
|
599
|
-
}
|
|
600
342
|
/** Token of the interactive HTML preview that currently owns DevTools (the active tab's frame), or
|
|
601
343
|
* null. Set by the HTML preview frame; DevTools opens exactly that registered document. */
|
|
602
344
|
let inspectableHtmlToken = null;
|
|
@@ -613,14 +355,14 @@ export function releaseInspectableHtmlPreview(token) {
|
|
|
613
355
|
* main webview is never inspectable. No-op without an active HTML preview or outside Tauri. */
|
|
614
356
|
export async function openDevtools() {
|
|
615
357
|
const token = inspectableHtmlToken;
|
|
616
|
-
if (!token ||
|
|
358
|
+
if (!token || !inTauri())
|
|
617
359
|
return;
|
|
618
360
|
await invoke("open_html_devtools", { token });
|
|
619
361
|
}
|
|
620
|
-
/** No-op: the macOS inspect-accelerator scope command was removed with the shell port (
|
|
362
|
+
/** No-op: the macOS inspect-accelerator scope command was removed with the shell port (host shell port). */
|
|
621
363
|
export async function setDevtoolsShortcutScope(_enabled) { }
|
|
622
364
|
export async function revealInFileExplorer(path) {
|
|
623
|
-
if (
|
|
365
|
+
if (!inTauri())
|
|
624
366
|
return;
|
|
625
367
|
await invoke("reveal_in_file_explorer", { path });
|
|
626
368
|
}
|
|
@@ -651,24 +393,10 @@ export async function printCurrentWebview() {
|
|
|
651
393
|
}
|
|
652
394
|
}
|
|
653
395
|
export async function listSystemFonts() {
|
|
654
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
655
|
-
return ["Inter", "Source Serif 4", "JetBrains Mono", "Geist", "Newsreader"];
|
|
656
396
|
if (!inTauri())
|
|
657
397
|
return [];
|
|
658
398
|
return invoke("list_system_fonts");
|
|
659
399
|
}
|
|
660
|
-
const QA_FILE_ASSOCIATION_FORMATS = ["md", "mdx", "txt", "pdf", "html", "docx", "image"];
|
|
661
|
-
let qaPreferredAssociationFormats = new Set(["md", "mdx"]);
|
|
662
|
-
function qaFileAssociationStatus() {
|
|
663
|
-
return {
|
|
664
|
-
formats: QA_FILE_ASSOCIATION_FORMATS.map((formatId) => ({
|
|
665
|
-
formatId,
|
|
666
|
-
extensions: [],
|
|
667
|
-
handlers: [],
|
|
668
|
-
allSet: qaPreferredAssociationFormats.has(formatId),
|
|
669
|
-
})),
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
400
|
function toFormatStatus(group) {
|
|
673
401
|
return {
|
|
674
402
|
formatId: group.id,
|
|
@@ -682,17 +410,10 @@ function toFormatStatus(group) {
|
|
|
682
410
|
};
|
|
683
411
|
}
|
|
684
412
|
export async function fileAssociationStatus() {
|
|
685
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
686
|
-
return qaFileAssociationStatus();
|
|
687
413
|
const status = await getShell().associations.status();
|
|
688
414
|
return { formats: status.groups.map(toFormatStatus) };
|
|
689
415
|
}
|
|
690
416
|
export async function setFileAssociationDefaults(formatIds) {
|
|
691
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode()) {
|
|
692
|
-
qaPreferredAssociationFormats = new Set(formatIds);
|
|
693
|
-
const status = qaFileAssociationStatus();
|
|
694
|
-
return { formats: status.formats, allSet: formatIds.length > 0 };
|
|
695
|
-
}
|
|
696
417
|
// macOS: one NSWorkspace request per content type (system consent sheet), one shared 60 s
|
|
697
418
|
// deadline (the shell default; the host clamps a given value to 1 to 120 s).
|
|
698
419
|
const result = await getShell().associations.set(formatIds);
|
|
@@ -701,8 +422,6 @@ export async function setFileAssociationDefaults(formatIds) {
|
|
|
701
422
|
/** Windows owns protected default-app choices. This opens Windows Default apps; the shell never
|
|
702
423
|
* writes UserChoice registry hashes or claims a default changed. */
|
|
703
424
|
export async function openFileAssociationSettings(_formatIds) {
|
|
704
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
705
|
-
return;
|
|
706
425
|
await getShell().associations.openDefaultApps();
|
|
707
426
|
}
|
|
708
427
|
export async function saveSession(tabs) {
|
|
@@ -818,15 +537,11 @@ export function installExternalLinkGuard() {
|
|
|
818
537
|
});
|
|
819
538
|
}
|
|
820
539
|
export async function saveFileDialog(defaultName, format) {
|
|
821
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
822
|
-
return `D:\\${hostAppName()} QA\\${defaultName ?? `untitled.${format ?? "txt"}`}`;
|
|
823
540
|
if (!inTauri())
|
|
824
541
|
return null;
|
|
825
542
|
return invoke("save_file_dialog", { defaultName, format });
|
|
826
543
|
}
|
|
827
544
|
export async function grantKnownFileToken(token) {
|
|
828
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
829
|
-
return token;
|
|
830
545
|
if (!inTauri())
|
|
831
546
|
return null;
|
|
832
547
|
return invoke("grant_known_file_token", { token });
|
|
@@ -840,15 +555,11 @@ export async function grantKnownFileToken(token) {
|
|
|
840
555
|
// - regrantSavedTarget: re-grant a path the host app itself just wrote (save-as, duplicate, DOCX
|
|
841
556
|
// save-as) — refused unless the exact path was written in the last few writes.
|
|
842
557
|
export async function openLinkedDocument(target, from) {
|
|
843
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
844
|
-
return target;
|
|
845
558
|
if (!inTauri())
|
|
846
559
|
return null;
|
|
847
560
|
return invoke("open_linked_document", { target, from: from ?? null });
|
|
848
561
|
}
|
|
849
562
|
export async function regrantSavedTarget(path) {
|
|
850
|
-
if (BROWSER_QA_BUILD && isBrowserQaMode())
|
|
851
|
-
return path;
|
|
852
563
|
if (!inTauri())
|
|
853
564
|
return null;
|
|
854
565
|
return invoke("regrant_saved_target", { path });
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*
|
|
2
|
-
@
|
|
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. */
|