@silurus/ooxml 0.74.6 → 0.75.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 (47) hide show
  1. package/README.md +105 -6
  2. package/dist/bounded-raw-part-cache-BTfZD_Sz.js +1248 -0
  3. package/dist/{docx-DftZMp7R.js → document-pull-client-H80_E10V.js} +11165 -11517
  4. package/dist/docx-BX0mJqS1.js +1274 -0
  5. package/dist/docx.mjs +6 -3
  6. package/dist/docx_parser_bg.wasm +0 -0
  7. package/dist/duotone-bitmap-by-path-Dv5Ikbzl.js +28 -0
  8. package/dist/find-cursor-Dc5iM6s7.js +815 -0
  9. package/dist/highlight-rect-cCvVU-MW.js +48 -0
  10. package/dist/hyperlink-D85FexTa.js +27 -0
  11. package/dist/index.mjs +4 -4
  12. package/dist/{highlight-rect-IjFkGg4X.js → line-distribute-DkLgIa7B.js} +37 -84
  13. package/dist/{find-cursor-DtgyGs5V.js → line-metrics-qwIyTk7Q.js} +1169 -3641
  14. package/dist/math.mjs +1 -1
  15. package/dist/node.mjs +998 -0
  16. package/dist/pptx-BEYjiTnZ.js +822 -0
  17. package/dist/pptx-CXgyi7wu.js +1705 -0
  18. package/dist/pptx.mjs +7 -3
  19. package/dist/pptx_parser_bg.wasm +0 -0
  20. package/dist/preload-BEouWnlI.js +132 -0
  21. package/dist/render-C0wMf5eT.js +71 -0
  22. package/dist/render-worker-host-CLdOlxFu.js +27 -0
  23. package/dist/render-worker-host-DZ4u0RFs.js +27 -0
  24. package/dist/render-worker-host-s3J-mWBP.js +27 -0
  25. package/dist/renderer-CwzTv9hH.js +5225 -0
  26. package/dist/resource-measurement-6aReN3K0.js +93 -0
  27. package/dist/slide-pull-client-D_T0AIoX.js +175 -0
  28. package/dist/svg-image-by-path-C1M3N2pT.js +1623 -0
  29. package/dist/transfer-3QEJrsJa.js +6 -0
  30. package/dist/types/docx.d.ts +290 -105
  31. package/dist/types/index.d.ts +399 -142
  32. package/dist/types/math.d.ts +1 -1
  33. package/dist/types/node.d.ts +4855 -0
  34. package/dist/types/pptx.d.ts +431 -245
  35. package/dist/types/xlsx.d.ts +320 -120
  36. package/dist/visible-index-CKvgpUrf.js +17 -0
  37. package/dist/worksheet-pull-worker-DCei8u-4.js +347 -0
  38. package/dist/{xlsx-BqMHvfsE.js → xlsx-DJyPlzjB.js} +1499 -1284
  39. package/dist/xlsx.mjs +7 -3
  40. package/dist/xlsx_parser_bg.wasm +0 -0
  41. package/package.json +12 -2
  42. package/dist/pptx-qbadwIv4.js +0 -6761
  43. package/dist/render-worker-host-Bcm9j4-H.js +0 -27
  44. package/dist/render-worker-host-BqSTDaYt.js +0 -27
  45. package/dist/render-worker-host-C523QxVw.js +0 -27
  46. package/dist/visible-index-C3_3gBg-.js +0 -50
  47. /package/dist/{mathjax-BPjQ2C_j.js → mathjax-Dqo857oC.js} +0 -0
package/README.md CHANGED
@@ -285,8 +285,8 @@ in a way a `ResizeObserver` cannot see — e.g. a late web-font load),
285
285
  `onVisiblePageChange` / `onVisibleSlideChange` (fires when the top-most visible
286
286
  page/slide changes), and `onError` (async per-page render failures are routed
287
287
  here instead of crashing the scroll loop). The parse/render knobs from the
288
- headless engines (`mode`, `useGoogleFonts`, `maxZipEntryBytes`, `math`, `dpr`)
289
- are accepted too.
288
+ headless engines (`mode`, `useGoogleFonts`, `resourceLimits`, the deprecated
289
+ `maxZipEntryBytes` alias, `math`, `dpr`) are accepted too.
290
290
 
291
291
  ### Markdown export
292
292
 
@@ -878,7 +878,7 @@ export const PptxViewerComponent = component$<{ src: string }>(({ src }) => {
878
878
  ## Companion packages
879
879
 
880
880
  - **[`packages/markdown/`](packages/markdown/)** — `@silurus/ooxml-markdown` and the `ooxml-md` CLI convert `.pptx` / `.docx` / `.xlsx` to GitHub-flavoured markdown via the workspace WASM parsers. Same projection used by the MCP server (~21× smaller than the raw XML on the demo deck, ~8% bigger than a flat-text extractor). Includes a node20-based GitHub Action for bulk repo-wide conversion.
881
- - **[`packages/node/`](packages/node/)** — Node-side parsers (`@silurus/ooxml-node`) exposing `parsePptx` / `parseDocx` / `parseXlsx` / `parseXlsxAllSheets` against the workspace WASM artifacts, with no DOM or Web Worker dependency. Useful for CI checks, headless rendering pipelines, and CLI tools. Includes an `ooxml-thumbnail` CLI (pptx-only first pass; requires `skia-canvas`).
881
+ - **[`packages/node/`](packages/node/)** — the implementation behind the public Node-only `@silurus/ooxml/node` subpath. It exposes materializing `parsePptx` / `parseDocx` / `parseXlsx` / `parseXlsxAllSheets` helpers plus uniformly owned, bounded `openPptxPresentation`, `openDocxDocument`, and `openXlsxWorkbook` sessions, with no DOM or Web Worker dependency. Each `open*` call returns an explicit `close()`-able session; PPTX streams `slides()` and can render each yielded slide through the same bounded archive, DOCX completes format-required sequential pagination before streaming `pages()`, and XLSX parses its workbook index once before sequential `worksheetRows(sheetIndex)` streams reuse the retained archive. Useful for CI checks and headless rendering pipelines; canvas rendering accepts a user-supplied backend such as `skia-canvas` without making it a runtime dependency.
882
882
  - **[`packages/vscode-extension/`](packages/vscode-extension/)** — VS Code extension (`ooxml-viewer`) that registers `CustomEditorProvider`s for `.docx`, `.xlsx`, and `.pptx`, and (opt-in) auto-installs and registers the `ooxml-mcp-server` so AI coding agents in the same window (Copilot Agent mode, Claude, …) can read those files via dedicated tools. The preview is offline by default; an opt-in `ooxmlViewer.useGoogleFonts` setting (off, and force-disabled in untrusted workspaces) surfaces the library's metric-compatible font substitution, widening the webview CSP to the Google Fonts CDN only while enabled.
883
883
  - **[`packages/mcp-server/`](packages/mcp-server/)** — Rust MCP server (`ooxml-mcp-server`) exposing the parsers as tools for AI agents (Claude, Copilot, Codex, etc.). Provides structured queries (`docx_get_structure`, `xlsx_get_cell_range`, `pptx_get_slide_structure`, …) so agents can inspect OOXML files without shelling out to `unzip`. Prebuilt binaries are attached to each [GitHub Release](https://github.com/yukiyokotani/office-open-xml-viewer/releases) for macOS / Linux / Windows; the VS Code extension downloads them on demand.
884
884
 
@@ -916,14 +916,113 @@ cd packages/xlsx/parser && wasm-pack build --target web && cp pkg/xlsx_parser_bg
916
916
  cd packages/pptx/parser && wasm-pack build --target web && cp pkg/pptx_parser_bg.wasm pkg/pptx_parser.js ../src/wasm/
917
917
  ```
918
918
 
919
+ ## Error handling
920
+
921
+ Headless APIs (`DocxDocument`, `XlsxWorkbook`, and `PptxPresentation`) report
922
+ load and render failures by rejecting the returned Promise. Viewer APIs also
923
+ support an `onError(error)` callback, with an important delivery rule:
924
+
925
+ - Without `onError`, a load/parse failure rejects `viewer.load()`.
926
+ - With `onError`, that failure is delivered to the callback and
927
+ `viewer.load()` resolves. Do not treat resolution alone as proof that the
928
+ document rendered.
929
+ - Later Viewer-managed render or media failures are delivered to `onError`, or
930
+ logged with `console.error` when the callback is omitted.
931
+
932
+ Stable failures can be narrowed without parsing message strings:
933
+
934
+ - `OoxmlError` — container failures. Its `code` is `encrypted`,
935
+ `invalid-password`, `unsupported-encryption`, `legacy-binary-format`, or
936
+ `not-ooxml`.
937
+ - `OoxmlResourceLimitError` (`code === 'ooxml-resource-limit'`) — a measured
938
+ package or format resource crossed a configurable limit or hard ceiling.
939
+ `details.violation` contains the resource, metric, limit, observed value, and
940
+ usage snapshot.
941
+ - `OoxmlDecodedImageLimitError`
942
+ (`code === 'ooxml-decoded-image-limit'`) — a raster crossed an image pixel or
943
+ active decoded-byte ceiling. Its `metric`, `limit`, and `observed` properties
944
+ are stable.
945
+ - An otherwise ordinary `Error` may carry `code === 'parser-crashed'` for a
946
+ recognized WASM trap. This does not mean “OOM”: panic, allocation failure,
947
+ stack overflow, and other traps can be indistinguishable at the current WASM
948
+ boundary.
949
+
950
+ All other configuration, fetch, parser, renderer, worker, and media failures
951
+ remain `Error`, `TypeError`, or `RangeError` values without a stable code. Their
952
+ messages are diagnostic text, not a programmatic API.
953
+
954
+ ```ts
955
+ import {
956
+ DocxViewer,
957
+ OoxmlDecodedImageLimitError,
958
+ OoxmlError,
959
+ OoxmlResourceLimitError,
960
+ } from '@silurus/ooxml/docx';
961
+
962
+ const viewer = new DocxViewer(canvas, {
963
+ onError(error) {
964
+ if (error instanceof OoxmlResourceLimitError) {
965
+ const { limit, observed } = error.details.violation;
966
+ showTooLargeMessage({ limit, observed });
967
+ } else if (error instanceof OoxmlDecodedImageLimitError) {
968
+ showImageTooLargeMessage(error);
969
+ } else if (error instanceof OoxmlError) {
970
+ handleContainerError(error.code);
971
+ } else {
972
+ reportUnexpectedError(error);
973
+ }
974
+ },
975
+ });
976
+
977
+ await viewer.load(file);
978
+ ```
979
+
919
980
  ## Security & Privacy
920
981
 
921
982
  - **Canvas-only rendering.** Documents are decoded and drawn to an `HTMLCanvasElement`. No script, link, form, or other active content from the source file is executed or injected into the DOM.
922
- - **ZIP decompression cap.** Each entry in the source archive is limited to 512 MiB of uncompressed output by default to block zip-bomb DoS. Override per viewer with `maxZipEntryBytes` (bytes) raise it for legitimate decks with large embedded media, lower it to tighten the budget for untrusted input:
983
+ - **Bounded OOXML package expansion.** DOCX, XLSX, and PPTX use the same resource policy. By default, one archive entry may inflate to at most 128 MiB and the distinct entries visited during one package session may inflate to at most 256 MiB. Override either budget with a plain `resourceLimits` object on a viewer or `load(...)` call:
984
+ ```ts
985
+ new XlsxViewer(container, {
986
+ resourceLimits: {
987
+ maxArchiveEntryBytes: 64 * 1024 * 1024,
988
+ maxTotalInflatedBytes: 192 * 1024 * 1024,
989
+ },
990
+ });
991
+ ```
992
+ `maxArchiveEntryBytes` applies to every XML, text, image, media, and other package part that the parser reads. `maxTotalInflatedBytes` counts the largest amount actually read from each distinct part during the lifetime of the loaded package; reading the same part again does not consume that budget twice. Set an individual field to `null` to disable that configurable budget. Internal hard safety ceilings still apply, so disabling a budget does not make arbitrary archives acceptable. Values other than `null` must be positive safe-integer byte counts.
993
+
994
+ A violation rejects with `OoxmlResourceLimitError` (`code === 'ooxml-resource-limit'`). Its structured `details.violation` reports the resource, metric, limit, observed value, usage snapshot, and part name when a particular part caused the failure. The deprecated `maxZipEntryBytes` option remains as a compatibility alias for `resourceLimits.maxArchiveEntryBytes`, but is scheduled for removal in a future breaking release; new code should use `resourceLimits`.
995
+
996
+ Applications can collect the same data as a machine-readable `OoxmlResourceMetrics` report without enabling console output. This is useful for choosing limits from representative files in the application's own domain:
997
+ ```ts
998
+ new DocxViewer(canvas, {
999
+ onResourceMetrics(metrics) {
1000
+ // Send only under your application's own consent/privacy policy.
1001
+ analytics.record('ooxml-resource-usage', metrics);
1002
+ },
1003
+ });
1004
+ ```
1005
+ After resource options validate, the callback also runs for failed document loads, for which no document/viewer engine is returned. It is not awaited; callback exceptions and rejected promises are ignored and never change the load result. On a successful load, every DOCX/XLSX/PPTX engine and Viewer also exposes `await getResourceMetrics()`; unlike the one-shot callback, this probes the archive owner and returns a fresh snapshot after lazy sheet, slide, image, font, or media access. A failed or unresponsive probe rejects within a bounded timeout rather than presenting stale counters as current. Collection for that getter is always active—`debug` controls only console presentation. The library itself does not transmit or persist the report.
1006
+
1007
+ For interactive inspection, pass `debug: true`. The same report is formatted as one compact, Ratatui-inspired console card with the compressed source size, largest observed inflated entry, distinct inflated total, entry count, configured limits, and timing checkpoints:
923
1008
  ```ts
924
- new PptxViewer(canvas, { maxZipEntryBytes: 64 * 1024 * 1024 }); // 64 MiB
1009
+ new DocxViewer(canvas, {
1010
+ debug: true,
1011
+ resourceLimits: {
1012
+ maxArchiveEntryBytes: 128 * 1024 * 1024,
1013
+ maxTotalInflatedBytes: 256 * 1024 * 1024,
1014
+ },
1015
+ });
925
1016
  ```
926
- Supported uniformly by `DocxViewer`, `PptxViewer`, and `XlsxViewer`. Zero / negative values fall back to the default.
1017
+ Browser DevTools receive typography-only `%c` styling (a fixed-width font stack, fixed size and line height, disabled ligatures, zero letter spacing, and preserved whitespace) so Unicode borders and gauges stay aligned. The library does not set foreground or background colors. Node and Worker consoles receive the same card as one plain argument without CSS or ANSI escapes.
1018
+
1019
+ The report is content-free by construction: it does not include source URLs, filenames, package paths, document text, passwords, or raw error messages. It still contains document-derived sizes, counts, and timings, so applications remain responsible for consent, retention, and telemetry policy. The initial browser callback covers the underlying document/workbook/presentation factory and does not wait for a Viewer's first canvas paint; use `getResourceMetrics()` for the latest observed package counters. Bounded Node sessions accept both `onResourceMetrics` and `debug`. DOCX/PPTX report successful terminal metrics when their one-pass stream completes or the session is explicitly closed; XLSX reports success when the reusable workbook session is explicitly closed. Open-time and session-operation failures report immediately.
1020
+
1021
+ Image decoding has separate, non-configurable browser safety ceilings shared by all three formats: at most 32 megapixels (128 MiB RGBA) for one raster, 128 MiB of decoded raster ownership per document cache or live render pass, and two simultaneous decodes per document. Crossing a measurable image ceiling rejects with `OoxmlDecodedImageLimitError` (`code === 'ooxml-decoded-image-limit'`) instead of silently omitting the image. These are hard implementation guards rather than public tuning knobs because browser/GPU overhead is not portable enough for an application-supplied byte value to mean the same thing across devices.
1022
+
1023
+ The package counters and raster-image guards are deterministic admission limits, not exact JavaScript/WASM process-memory accounting. XML trees, document models, canvas backing stores, browser decoder overhead, renderer state, and browser-managed SVG/vector parse or decoded storage can still require several times the measured input. SVG has no portable decoded-byte measure or explicit browser release primitive; the library count-bounds its cache and revokes owned object URLs, but cannot charge it as RGBA bytes. The defaults therefore reduce risk but cannot promise that an OOM is impossible on every device. Running parse and render work in `mode: 'worker'` can contain many failures away from the main UI thread, but a Worker is not a separate operating-system process or a strict memory sandbox.
1024
+
1025
+ A measured limit crossing is reported as `OoxmlResourceLimitError`. A residual WASM failure that reaches a recognized trap-shaped boundary is reported conservatively as `parser-crashed`, not `parser-oom`: with the current aborting Rust/WASM boundary, panic, allocation failure, explicit `unreachable`, and stack overflow can lose their distinct causes and converge on the same generic runtime error. Inferring OOM from an exception class or message would misclassify some parser defects as large-file failures. Reliable OOM classification would require preserving a structured cause before the trap across every relevant allocation path; it cannot be recovered from the generic trap afterward. The WebAssembly JavaScript embedding also permits implementation-defined stack/OOM failures, including an indistinguishable plain `Error` or process termination, so converting and poisoning every engine-level failure cannot be guaranteed.
927
1026
  - **No network by default.** The library does not send telemetry or analytics, and does not contact third-party services unless you ask it to. In particular, theme webfonts, Office font metric substitutes (Carlito/Caladea), and the script fallback fonts are **not** loaded from Google Fonts unless you pass `useGoogleFonts: true` to the relevant `Viewer` / `load(...)` options — supported uniformly by `DocxViewer`, `PptxViewer`, and `XlsxViewer`. When enabled, fonts for non-Latin scripts are supplied on demand from Noto families so text does not fall back to tofu: Arabic (Noto Naskh/Sans Arabic), CJK (Noto Sans/Serif KR · SC · TC · JP, picked per document language so shared Han glyphs take the right shapes), Cyrillic (Noto Sans/Serif), Hebrew (Noto Sans/Serif Hebrew, RTL), Thai (Noto Sans Thai) and Devanagari (Noto Sans Devanagari). No font binaries ship in the bundle. Enabling this option causes the end-user's browser to send an HTTP request (IP and User-Agent) to `fonts.googleapis.com`, which may have GDPR implications for your application — consider self-hosting the required fonts via `@font-face` instead.
928
1027
  - **XML parsing.** Uses `roxmltree`, which does not resolve external entities (XXE-safe by default).
929
1028
  - **Encrypted OOXML ([MS-OFFCRYPTO] Agile Encryption).** Password-protected `.docx` / `.xlsx` / `.pptx` files are OLE2/CFB containers, not ZIPs. Pass `password` to `load(...)` and the file is decrypted **client-side** via WebCrypto — no bytes and no password leave the browser: