@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,535 +0,0 @@
1
- import { isTauri } from "@rightkit/platform-ui";
2
- import { invoke } from "@tauri-apps/api/core";
3
- import { getResourceCensus } from "../../app/resourceCensus.js";
4
- import { isMac, isWindows } from "../../platform.js";
5
- import { logEvent } from "../../state/diagnostics.js";
6
- import { autopilotOnComplete, autopilotStatus, maybeAutoStartFromEnv, startAutopilot, stopAutopilot, } from "./pdfBenchAutopilot.js";
7
- // The harness is dev-only. Every export starts with a literal `import.meta.env?.DEV` check (not a
8
- // helper call) so production builds fold each one to its no-op and the minifier drops the harness,
9
- // its storage keys and the autopilot. Env values are read by explicit key for the same reason: a
10
- // computed `import.meta.env[key]` makes Vite inline the whole env object.
11
- const ENABLED_KEY = "vr.pdf.bench.enabled";
12
- const MODE_KEY = "vr.pdf.bench.mode";
13
- const HISTORY_KEY = "vr.pdf.bench.history.v1";
14
- const MAX_HISTORY = 40;
15
- const SETTLE_POLL_MS = 250;
16
- const SETTLE_QUIET_MS = 1_000;
17
- const SETTLE_MAX_MS = 6_000;
18
- const WATCHDOG_MS = 30_000;
19
- const FIXTURE_LABEL_KEY = "vr.pdf.bench.fixture.label";
20
- const SOURCE_FILENAME_KEY = "vr.pdf.bench.fixture.filename";
21
- const FIXTURE_BYTES_KEY = "vr.pdf.bench.fixture.bytes";
22
- const FIXTURE_SHA256_KEY = "vr.pdf.bench.fixture.sha256";
23
- let active = null;
24
- let settleGeneration = 0;
25
- let beginGeneration = 0;
26
- let latePageNavigator = null;
27
- function benchEnabled() {
28
- if (typeof window === "undefined" || !import.meta.env?.DEV)
29
- return false;
30
- try {
31
- return localStorage.getItem(ENABLED_KEY) === "1";
32
- }
33
- catch {
34
- return false;
35
- }
36
- }
37
- export function isPdfBenchEnabled() {
38
- return import.meta.env?.DEV && benchEnabled();
39
- }
40
- function normalizeMode(value) {
41
- return value === "url-native" || value === "custom-range" ? value : "buffer";
42
- }
43
- function isWindowsPdfRuntime() {
44
- return isWindows();
45
- }
46
- export function getPdfBenchLoadMode() {
47
- // Mac WKWebView corpus: custom range matched/surpassed full-fetch latency while avoiding the
48
- // initial whole-file read on large PDFs. Windows/WebView2 keeps the prior full-buffer default
49
- // until a recorded Windows corpus confirms custom range there. Benchmark mode may still
50
- // override this per localStorage for either platform.
51
- // Browser QA and web previews can use data/blob/http URLs that do not promise byte-range
52
- // semantics. Custom range is a native macOS transport choice, so keep non-Tauri runtimes on
53
- // the portable full-buffer path unless benchmark mode explicitly overrides it.
54
- if (!import.meta.env?.DEV || !benchEnabled()) {
55
- return !isTauri() || isWindowsPdfRuntime() ? "buffer" : "custom-range";
56
- }
57
- try {
58
- return normalizeMode(localStorage.getItem(MODE_KEY));
59
- }
60
- catch {
61
- return isWindowsPdfRuntime() ? "buffer" : "custom-range";
62
- }
63
- }
64
- export function registerPdfBenchLatePageNavigator(navigator) {
65
- if (!import.meta.env?.DEV)
66
- return;
67
- latePageNavigator = navigator;
68
- }
69
- function latePageTarget() {
70
- const raw = import.meta.env?.VITE_PDF_BENCH_LATE_PAGE;
71
- if (!raw || !/^\d+$/.test(raw))
72
- return null;
73
- const value = Number(raw);
74
- return Number.isSafeInteger(value) && value > 0 ? value : null;
75
- }
76
- async function safeInvoke(command, args) {
77
- if (!isTauri())
78
- return null;
79
- try {
80
- return await invoke(command, args);
81
- }
82
- catch (error) {
83
- console.warn(`[pdf-bench] ${command} failed`, error);
84
- return null;
85
- }
86
- }
87
- async function streamStats() {
88
- return safeInvoke("pdf_bench_stream_stats");
89
- }
90
- async function processMemory() {
91
- const value = await safeInvoke("pdf_bench_process_memory");
92
- return value
93
- ? {
94
- app_process_rss_bytes: value.app_process_rss_bytes,
95
- app_process_tree_rss_bytes: value.app_process_tree_rss_bytes,
96
- process_count: value.app_process_count,
97
- }
98
- : null;
99
- }
100
- async function activateMacBenchWindow() {
101
- if (!isTauri() || !isMac())
102
- return;
103
- const deadline = performance.now() + 2_000;
104
- do {
105
- await safeInvoke("pdf_bench_activate_foreground");
106
- await new Promise((resolve) => window.setTimeout(resolve, 100));
107
- if (document.visibilityState === "visible" && document.hasFocus())
108
- return;
109
- } while (performance.now() < deadline);
110
- }
111
- function envOrStored(key, env) {
112
- if (env)
113
- return env;
114
- try {
115
- return localStorage.getItem(key) || null;
116
- }
117
- catch {
118
- return null;
119
- }
120
- }
121
- function fixtureIdentity() {
122
- const bytesRaw = envOrStored(FIXTURE_BYTES_KEY, import.meta.env?.VITE_PDF_BENCH_FIXTURE_BYTES);
123
- const bytes = bytesRaw && /^\d+$/.test(bytesRaw) ? Number(bytesRaw) : null;
124
- const sha = envOrStored(FIXTURE_SHA256_KEY, import.meta.env?.VITE_PDF_BENCH_FIXTURE_SHA256);
125
- return {
126
- label: envOrStored(FIXTURE_LABEL_KEY, import.meta.env?.VITE_PDF_BENCH_FIXTURE_LABEL),
127
- sourceFilename: envOrStored(SOURCE_FILENAME_KEY, import.meta.env?.VITE_PDF_BENCH_SOURCE_FILENAME),
128
- bytes: bytes !== null && Number.isSafeInteger(bytes) && bytes > 0 ? bytes : null,
129
- sha256: sha && /^[0-9a-f]{64}$/i.test(sha) ? sha.toLowerCase() : null,
130
- };
131
- }
132
- function runtimeStats(session) {
133
- const memory = performance.memory;
134
- return {
135
- js_heap_used_bytes: memory?.usedJSHeapSize ?? null,
136
- js_heap_total_bytes: memory?.totalJSHeapSize ?? null,
137
- js_heap_limit_bytes: memory?.jsHeapSizeLimit ?? null,
138
- longtask_count: session.longTaskCount,
139
- longtask_duration_ms: session.longTaskDurationMs,
140
- };
141
- }
142
- function elapsed(session) {
143
- return Math.max(0, performance.now() - session.startedAt);
144
- }
145
- function serializable(session) {
146
- const plan = autopilotStatus();
147
- return {
148
- schema_version: 1,
149
- mode: session.mode,
150
- run_id: session.run_id,
151
- launch_kind: session.launch_kind,
152
- run_index: plan && !plan.done ? plan.index + 1 : null,
153
- run_total: plan ? plan.modes.length * plan.repeats : null,
154
- started_at: session.startedIso,
155
- platform: session.platform,
156
- user_agent: session.userAgent,
157
- pdfjs_version: session.pdfjsVersion,
158
- document_ready_ms: session.documentReadyMs,
159
- first_canvas_ms: session.firstCanvasMs,
160
- first_canvas_page: session.firstCanvasPage,
161
- baseline_memory: session.baselineMemory,
162
- baseline_runtime: session.baselineRuntime,
163
- first_canvas_snapshot: session.firstCanvasSnapshot,
164
- late_page_target: session.latePageTarget,
165
- late_page_request_ms: session.latePageRequestedAt,
166
- late_page_ms: session.latePageMs,
167
- late_page_snapshot: session.latePageSnapshot,
168
- settled_snapshot: session.settledSnapshot,
169
- fixture_label: session.fixtureLabel,
170
- source_filename: session.sourceFilename,
171
- fixture_bytes: session.fixtureBytes,
172
- fixture_sha256: session.fixtureSha256,
173
- fixture_identity_status: session.fixtureIdentityStatus,
174
- error: session.error,
175
- };
176
- }
177
- function loadHistory() {
178
- try {
179
- const raw = localStorage.getItem(HISTORY_KEY);
180
- if (!raw)
181
- return [];
182
- const parsed = JSON.parse(raw);
183
- return Array.isArray(parsed) ? parsed : [];
184
- }
185
- catch {
186
- return [];
187
- }
188
- }
189
- function saveHistory(result) {
190
- try {
191
- const history = loadHistory();
192
- history.push(result);
193
- while (history.length > MAX_HISTORY)
194
- history.shift();
195
- localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
196
- }
197
- catch {
198
- // Dev-only benchmark history; never an application correctness dependency.
199
- }
200
- }
201
- async function capture(session) {
202
- const [stream, memory] = await Promise.all([streamStats(), processMemory()]);
203
- if (session.fixtureBytes !== null && stream?.resource_bytes) {
204
- session.fixtureIdentityStatus =
205
- stream.resource_bytes === session.fixtureBytes ? "matched" : "mismatch";
206
- if (session.fixtureIdentityStatus === "mismatch" && !session.error) {
207
- session.error = `fixture byte mismatch: expected ${session.fixtureBytes}, native reported ${stream.resource_bytes}`;
208
- }
209
- }
210
- return {
211
- at_ms: elapsed(session),
212
- stream,
213
- process_memory: memory,
214
- runtime: runtimeStats(session),
215
- resources: getResourceCensus(),
216
- };
217
- }
218
- async function finalize(session) {
219
- if (session.finalized)
220
- return;
221
- session.finalized = true;
222
- if (session.watchdogHandle !== null)
223
- window.clearTimeout(session.watchdogHandle);
224
- session.longTaskObserver?.disconnect();
225
- const result = serializable(session);
226
- logEvent("pdf-bench-finalize");
227
- saveHistory(result);
228
- let artifactPath = null;
229
- if (isTauri()) {
230
- try {
231
- artifactPath = await invoke("pdf_bench_write_result", {
232
- runId: result.run_id,
233
- result,
234
- });
235
- }
236
- catch (error) {
237
- console.error("[pdf-bench] durable artifact write failed", error);
238
- return;
239
- }
240
- }
241
- if (artifactPath)
242
- console.info(`[pdf-bench] durable artifact ${artifactPath}`);
243
- await safeInvoke("pdf_bench_stop");
244
- console.info("[pdf-bench] completed", result);
245
- // Unattended matrix: record to the diagnostics log and advance to the next mode. No-op unless a
246
- // plan is active, so hand-driven console runs behave exactly as before.
247
- autopilotOnComplete();
248
- }
249
- async function settle(session, generation) {
250
- const settleStarted = performance.now();
251
- let lastSignature = "";
252
- let stableSince = performance.now();
253
- while (active === session &&
254
- generation === settleGeneration &&
255
- performance.now() - settleStarted < SETTLE_MAX_MS) {
256
- await new Promise((resolve) => window.setTimeout(resolve, SETTLE_POLL_MS));
257
- const stats = await streamStats();
258
- const signature = stats
259
- ? `${stats.head_requests}:${stats.full_get_requests}:${stats.range_get_requests}:${stats.total_bytes_read}`
260
- : "no-native-stats";
261
- if (signature !== lastSignature) {
262
- lastSignature = signature;
263
- stableSince = performance.now();
264
- continue;
265
- }
266
- if (performance.now() - stableSince >= SETTLE_QUIET_MS)
267
- break;
268
- }
269
- if (active !== session || generation !== settleGeneration)
270
- return;
271
- session.settledSnapshot = await capture(session);
272
- await finalize(session);
273
- }
274
- export async function beginPdfBench(url, pdfjsVersion, mode = getPdfBenchLoadMode()) {
275
- if (!import.meta.env?.DEV)
276
- return;
277
- const enabled = benchEnabled();
278
- if (!enabled)
279
- return;
280
- logEvent("pdf-bench-invoked");
281
- logEvent("pdf-bench-begin");
282
- const generation = ++beginGeneration;
283
- settleGeneration++;
284
- await activateMacBenchWindow();
285
- await safeInvoke("pdf_bench_reset");
286
- const baselineMemory = await processMemory();
287
- if (generation !== beginGeneration)
288
- return;
289
- logEvent("pdf-bench-baseline-ready");
290
- const identity = fixtureIdentity();
291
- const baselineRuntime = {
292
- js_heap_used_bytes: null,
293
- js_heap_total_bytes: null,
294
- js_heap_limit_bytes: null,
295
- longtask_count: 0,
296
- longtask_duration_ms: 0,
297
- };
298
- const session = {
299
- url,
300
- mode,
301
- run_id: String(import.meta.env?.VITE_PDF_BENCH_RUN_ID ?? `run-${Date.now()}`),
302
- launch_kind: import.meta.env?.VITE_PDF_BENCH_LAUNCH_KIND ?? null,
303
- startedAt: performance.now(),
304
- startedIso: new Date().toISOString(),
305
- platform: navigator.platform,
306
- userAgent: navigator.userAgent,
307
- pdfjsVersion,
308
- baselineMemory,
309
- baselineRuntime,
310
- fixtureLabel: identity.label,
311
- sourceFilename: identity.sourceFilename,
312
- fixtureBytes: identity.bytes,
313
- fixtureSha256: identity.sha256,
314
- fixtureIdentityStatus: identity.bytes === null ? "missing" : "pending",
315
- longTaskObserver: null,
316
- longTaskCount: 0,
317
- longTaskDurationMs: 0,
318
- watchdogHandle: null,
319
- documentReadyMs: null,
320
- firstCanvasMs: null,
321
- firstCanvasPage: null,
322
- firstCanvasSnapshot: null,
323
- latePageTarget: latePageTarget(),
324
- latePagePending: false,
325
- latePageMs: null,
326
- latePageSnapshot: null,
327
- latePageRequestedAt: null,
328
- settledSnapshot: null,
329
- error: null,
330
- finalized: false,
331
- };
332
- let observer = null;
333
- try {
334
- if (typeof PerformanceObserver !== "undefined") {
335
- observer = new PerformanceObserver((list) => {
336
- for (const entry of list.getEntries()) {
337
- session.longTaskCount += 1;
338
- session.longTaskDurationMs += entry.duration;
339
- }
340
- });
341
- }
342
- observer?.observe({ type: "longtask", buffered: true });
343
- }
344
- catch {
345
- // Long-task timing is optional in WebView.
346
- observer = null;
347
- }
348
- session.longTaskObserver = observer;
349
- session.baselineRuntime = runtimeStats(session);
350
- active = session;
351
- logEvent("pdf-bench-session-active");
352
- session.watchdogHandle = window.setTimeout(() => {
353
- if (active !== session || session.finalized)
354
- return;
355
- logEvent("pdf-bench-watchdog-fired");
356
- session.error =
357
- session.documentReadyMs === null
358
- ? "watchdog: document-ready timeout"
359
- : session.latePagePending
360
- ? "watchdog: late-page timeout"
361
- : "watchdog: first-canvas timeout";
362
- void capture(session).then(async (snapshot) => {
363
- if (active !== session)
364
- return;
365
- session.settledSnapshot = snapshot;
366
- await finalize(session);
367
- });
368
- }, WATCHDOG_MS);
369
- console.info(`[pdf-bench] started mode=${mode}`);
370
- }
371
- export function markPdfBenchDocumentReady(url) {
372
- if (!import.meta.env?.DEV)
373
- return;
374
- const session = active;
375
- if (!session || session.url !== url || session.documentReadyMs !== null)
376
- return;
377
- session.documentReadyMs = elapsed(session);
378
- logEvent("pdf-bench-document-ready");
379
- }
380
- export function markPdfBenchFirstCanvasPaint(url, page) {
381
- if (!import.meta.env?.DEV)
382
- return;
383
- const session = active;
384
- if (!url || !session || session.url !== url)
385
- return;
386
- if (session.firstCanvasMs !== null) {
387
- markLatePagePaint(session, page);
388
- return;
389
- }
390
- // Record latency before memory/stat snapshots add any benchmark work.
391
- session.firstCanvasMs = elapsed(session);
392
- session.firstCanvasPage = page;
393
- logEvent("pdf-bench-first-canvas");
394
- void capture(session).then((snapshot) => {
395
- if (active === session)
396
- session.firstCanvasSnapshot = snapshot;
397
- if (active !== session)
398
- return;
399
- const target = session.latePageTarget;
400
- if (target === null || latePageNavigator === null) {
401
- const generation = ++settleGeneration;
402
- void settle(session, generation);
403
- return;
404
- }
405
- if (target === page) {
406
- session.latePageRequestedAt = session.firstCanvasMs;
407
- session.latePageMs = 0;
408
- session.latePageSnapshot = snapshot;
409
- const generation = ++settleGeneration;
410
- void settle(session, generation);
411
- return;
412
- }
413
- session.latePagePending = true;
414
- session.latePageRequestedAt = elapsed(session);
415
- const actual = latePageNavigator(target);
416
- if (actual === null || !Number.isSafeInteger(actual) || actual <= 0) {
417
- session.latePagePending = false;
418
- const generation = ++settleGeneration;
419
- void settle(session, generation);
420
- return;
421
- }
422
- session.latePageTarget = actual;
423
- if (actual === page) {
424
- session.latePagePending = false;
425
- session.latePageMs = 0;
426
- session.latePageSnapshot = snapshot;
427
- const generation = ++settleGeneration;
428
- void settle(session, generation);
429
- }
430
- });
431
- }
432
- function markLatePagePaint(session, page) {
433
- if (!session.latePagePending || session.latePageTarget === null || session.latePageMs !== null)
434
- return;
435
- if (page !== session.latePageTarget)
436
- return;
437
- const arrivedAt = elapsed(session);
438
- session.latePageMs = Math.max(0, arrivedAt - (session.latePageRequestedAt ?? arrivedAt));
439
- void capture(session).then((snapshot) => {
440
- if (active !== session)
441
- return;
442
- session.latePageSnapshot = snapshot;
443
- session.latePagePending = false;
444
- const generation = ++settleGeneration;
445
- void settle(session, generation);
446
- });
447
- }
448
- export function markPdfBenchError(url, error) {
449
- if (!import.meta.env?.DEV)
450
- return;
451
- const session = active;
452
- if (!session || session.url !== url || session.error)
453
- return;
454
- session.error = String(error?.message ?? error);
455
- void capture(session).then(async (snapshot) => {
456
- if (active !== session)
457
- return;
458
- session.settledSnapshot = snapshot;
459
- await finalize(session);
460
- });
461
- }
462
- async function currentReport() {
463
- const session = active;
464
- if (!session)
465
- return null;
466
- if (!session.settledSnapshot)
467
- session.settledSnapshot = await capture(session);
468
- return serializable(session);
469
- }
470
- function downloadJson(filename, value) {
471
- const blob = new Blob([JSON.stringify(value, null, 2)], { type: "application/json" });
472
- const url = URL.createObjectURL(blob);
473
- const anchor = document.createElement("a");
474
- anchor.href = url;
475
- anchor.download = filename;
476
- anchor.click();
477
- window.setTimeout(() => URL.revokeObjectURL(url), 0);
478
- }
479
- function installConsoleApi() {
480
- if (typeof window === "undefined" || !import.meta.env?.DEV)
481
- return;
482
- const api = {
483
- status: () => ({
484
- enabled: benchEnabled(),
485
- mode: getPdfBenchLoadMode(),
486
- active: active ? serializable(active) : null,
487
- history_count: loadHistory().length,
488
- }),
489
- enable: (mode = "buffer", reload = true) => {
490
- localStorage.setItem(ENABLED_KEY, "1");
491
- localStorage.setItem(MODE_KEY, normalizeMode(mode));
492
- if (reload)
493
- location.reload();
494
- },
495
- disable: (reload = false) => {
496
- localStorage.removeItem(ENABLED_KEY);
497
- void safeInvoke("pdf_bench_stop");
498
- if (reload)
499
- location.reload();
500
- },
501
- setMode: (mode, reload = true) => {
502
- localStorage.setItem(ENABLED_KEY, "1");
503
- localStorage.setItem(MODE_KEY, normalizeMode(mode));
504
- if (reload)
505
- location.reload();
506
- },
507
- report: currentReport,
508
- history: loadHistory,
509
- clearHistory: () => localStorage.removeItem(HISTORY_KEY),
510
- download: async () => {
511
- const report = await currentReport();
512
- const payload = {
513
- schema_version: 1,
514
- exported_at: new Date().toISOString(),
515
- history: loadHistory(),
516
- active: report,
517
- };
518
- downloadJson(`viewright-pdf-bench-${Date.now()}.json`, payload);
519
- return payload;
520
- },
521
- // Unattended matrix (modes x repeats), results written to the diagnostics log.
522
- autopilot: (label, repeats) => startAutopilot(label ?? "manual", undefined, repeats),
523
- autopilotStatus,
524
- stopAutopilot,
525
- };
526
- Object.defineProperty(window, "vrPdfBench", {
527
- configurable: true,
528
- enumerable: false,
529
- value: api,
530
- });
531
- // Env-driven start so the matrix needs no console at all:
532
- // VITE_PDF_BENCH_AUTOPILOT=1 pnpm dev:tauri <file.pdf>
533
- maybeAutoStartFromEnv();
534
- }
535
- installConsoleApi();
@@ -1,48 +0,0 @@
1
- /**
2
- * VR-P0-1 benchmark autopilot (dev-only, temporary instrumentation).
3
- *
4
- * The PDF loading benchmark has to run in the real WKWebView/WebView2 webview, whose DevTools
5
- * console is GUI-only — so driving it by hand does not scale to "3 repeats x 3 modes x N fixtures,
6
- * on two operating systems". This module runs the whole matrix unattended:
7
- *
8
- * 1. a plan (modes x repeats) is stored in localStorage;
9
- * 2. each app load runs whichever mode the plan currently points at;
10
- * 3. on completion the full result is appended to native PDF benchmark JSONL;
11
- * a content-free diagnostics breadcrumb remains for quick status checks;
12
- * 4. the plan advances and the app reloads, until the matrix is done.
13
- *
14
- * Repeats are INTERLEAVED (round-robin across modes) rather than grouped, so a thermal or
15
- * page-cache drift over the run cannot systematically favour whichever mode ran first.
16
- *
17
- * Delete this file together with the rest of the benchmark harness once the study is decided.
18
- */
19
- import type { PdfBenchLoadMode } from "./pdfBench.js";
20
- interface AutopilotPlan {
21
- /** Native artifact identity. Distinguishes separate launcher processes using the same fixture. */
22
- readonly runId: string;
23
- readonly modes: PdfBenchLoadMode[];
24
- readonly repeats: number;
25
- /** Flattened run index: run n uses modes[n % modes.length]. */
26
- index: number;
27
- readonly label: string;
28
- done: boolean;
29
- }
30
- /** The mode the plan wants for the current load, or null when no plan is active. */
31
- export declare function autopilotCurrentMode(): PdfBenchLoadMode | null;
32
- /**
33
- * Called from benchmark `finalize()`. Records a content-free diagnostics breadcrumb, advances plan,
34
- * & either reloads for next mode or reports matrix complete. Full result is native JSONL.
35
- */
36
- export declare function autopilotOnComplete(): void;
37
- /** Begin a matrix. Arms the first mode and reloads so the run starts from a clean document load. */
38
- export declare function startAutopilot(label?: string, modes?: PdfBenchLoadMode[], repeats?: number, reload?: boolean, runId?: string): void;
39
- export declare function stopAutopilot(): void;
40
- export declare function autopilotStatus(): AutopilotPlan | null;
41
- /**
42
- * Auto-start from the environment so the matrix needs no console at all:
43
- * VITE_PDF_BENCH_AUTOPILOT=1 pnpm dev:tauri <file.pdf>
44
- *
45
- * Only fires when no plan exists yet, so the per-run reloads do not restart the matrix.
46
- */
47
- export declare function maybeAutoStartFromEnv(): void;
48
- export {};