@silurus/ooxml 0.75.5 → 0.76.1

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 (52) hide show
  1. package/README.md +66 -28
  2. package/dist/bounded-raw-part-cache-C6ro6Ezf.js +254 -0
  3. package/dist/{find-cursor-Dc5iM6s7.js → canvas-viewer-mechanics-CwVSOYke.js} +192 -64
  4. package/dist/{document-pull-client-BcNYhoAG.js → document-pull-client-AAnwzlig.js} +3625 -3601
  5. package/dist/docx-CCksIXd5.js +1301 -0
  6. package/dist/docx.mjs +4 -6
  7. package/dist/docx_parser_bg.wasm +0 -0
  8. package/dist/index.mjs +3 -3
  9. package/dist/{line-distribute-B8sqT8kC.js → line-distribute-C1r2zvji.js} +141 -141
  10. package/dist/{line-metrics-D9gqQWHl.js → line-metrics-BdCACYlq.js} +4026 -1170
  11. package/dist/math.mjs +1 -1
  12. package/dist/node.mjs +779 -465
  13. package/dist/pptx-CKAk5e-J.js +1735 -0
  14. package/dist/pptx.mjs +5 -7
  15. package/dist/pptx_parser_bg.wasm +0 -0
  16. package/dist/{render-CalC7GX4.js → render-CLcpSi0m.js} +11 -18
  17. package/dist/render-worker-host-B8HAb_sK.js +27 -0
  18. package/dist/render-worker-host-Bkf1jUcW.js +27 -0
  19. package/dist/render-worker-host-CKOmXdyr.js +27 -0
  20. package/dist/resource-measurement-E_S_iau4.js +119 -0
  21. package/dist/session-B4Y54cbT.js +730 -0
  22. package/dist/{renderer-B9R6F_QY.js → slide-pull-client-WCuYCjio.js} +973 -820
  23. package/dist/types/docx.d.ts +1181 -3994
  24. package/dist/types/index.d.ts +2733 -8171
  25. package/dist/types/math.d.ts +8 -33
  26. package/dist/types/node.d.ts +1852 -4433
  27. package/dist/types/pptx.d.ts +1030 -3678
  28. package/dist/types/xlsx.d.ts +1291 -3262
  29. package/dist/worksheet-pull-client-YzjJMOns.js +455 -0
  30. package/dist/xlsx-BBmmZNQn.js +6362 -0
  31. package/dist/xlsx.mjs +5 -7
  32. package/dist/xlsx_parser_bg.wasm +0 -0
  33. package/package.json +14 -7
  34. package/dist/bounded-raw-part-cache-BTfZD_Sz.js +0 -1248
  35. package/dist/docx-DjF8FgoP.js +0 -1274
  36. package/dist/duotone-bitmap-by-path-CWsSJkJu.js +0 -28
  37. package/dist/hyperlink-D85FexTa.js +0 -27
  38. package/dist/pptx-C17xP8AV.js +0 -1705
  39. package/dist/pptx-Dl8tOSmP.js +0 -822
  40. package/dist/preload-BEouWnlI.js +0 -132
  41. package/dist/render-worker-host-BG3a7brz.js +0 -27
  42. package/dist/render-worker-host-CsB-dPJv.js +0 -27
  43. package/dist/render-worker-host-Cyv5Hkbh.js +0 -27
  44. package/dist/resource-measurement-6aReN3K0.js +0 -93
  45. package/dist/slide-pull-client-D_T0AIoX.js +0 -175
  46. package/dist/svg-image-by-path-C1M3N2pT.js +0 -1623
  47. package/dist/worksheet-pull-worker-DCei8u-4.js +0 -347
  48. package/dist/xlsx-BaH9irS0.js +0 -5515
  49. /package/dist/{highlight-rect-cCvVU-MW.js → highlight-rect-CAkCWJ37.js} +0 -0
  50. /package/dist/{mathjax-Dqo857oC.js → mathjax-CMjda8Ip.js} +0 -0
  51. /package/dist/{transfer-3QEJrsJa.js → transfer-DCu4c2BL.js} +0 -0
  52. /package/dist/{visible-index-CKvgpUrf.js → visible-index-CgyJLAS_.js} +0 -0
package/README.md CHANGED
@@ -79,12 +79,12 @@ pnpm add @silurus/ooxml
79
79
 
80
80
  ```typescript
81
81
  import { DocxViewer } from '@silurus/ooxml/docx';
82
- import { XlsxViewer } from '@silurus/ooxml/xlsx';
82
+ import { XlsxSheetViewer, XlsxViewer, XlsxWorkbook } from '@silurus/ooxml/xlsx';
83
83
  import { PptxViewer } from '@silurus/ooxml/pptx';
84
84
 
85
85
  // DOCX — caller provides the <canvas>
86
- const canvas = document.getElementById('docx-canvas') as HTMLCanvasElement;
87
- const docx = new DocxViewer(canvas);
86
+ const docxCanvas = document.getElementById('docx-canvas') as HTMLCanvasElement;
87
+ const docx = new DocxViewer(docxCanvas);
88
88
  await docx.load('/document.docx');
89
89
  docx.nextPage();
90
90
 
@@ -93,9 +93,32 @@ const container = document.getElementById('xlsx-container') as HTMLElement;
93
93
  const xlsx = new XlsxViewer(container);
94
94
  await xlsx.load('/workbook.xlsx');
95
95
 
96
+ // XLSX active-sheet surface only — caller provides the <canvas>
97
+ const sheetCanvas = document.getElementById('xlsx-canvas') as HTMLCanvasElement;
98
+ const sheet = new XlsxSheetViewer(sheetCanvas);
99
+ await sheet.load('/workbook.xlsx');
100
+ await sheet.goToSheet(1);
101
+
102
+ // Share one parsed workbook across independently scrollable sheet canvases,
103
+ // including canvases created in same-origin popup windows.
104
+ const workbook = await XlsxWorkbook.load('/workbook.xlsx');
105
+ const firstCanvas = document.getElementById('xlsx-first-canvas') as HTMLCanvasElement;
106
+ const secondCanvas = document.getElementById('xlsx-second-canvas') as HTMLCanvasElement;
107
+ const firstSheet = XlsxSheetViewer.fromWorkbook(firstCanvas, workbook);
108
+ const secondSheet = XlsxSheetViewer.fromWorkbook(secondCanvas, workbook);
109
+ await Promise.all([
110
+ firstSheet.goToSheet(0),
111
+ secondSheet.goToSheet(1),
112
+ ]);
113
+
114
+ // Each viewer borrows the workbook; the caller closes it after the viewers.
115
+ firstSheet.destroy();
116
+ secondSheet.destroy();
117
+ workbook.destroy();
118
+
96
119
  // PPTX — caller provides the <canvas>
97
- const canvas = document.getElementById('pptx-canvas') as HTMLCanvasElement;
98
- const pptx = new PptxViewer(canvas);
120
+ const pptxCanvas = document.getElementById('pptx-canvas') as HTMLCanvasElement;
121
+ const pptx = new PptxViewer(pptxCanvas);
99
122
  await pptx.load('/deck.pptx');
100
123
  pptx.nextSlide();
101
124
  ```
@@ -203,7 +226,7 @@ The container must have a bounded height (e.g. `height: 100vh` or a flex child)
203
226
  so the viewer can size its scroll host to it. Base zoom fits the first page/slide
204
227
  width to the container width and re-fits on resize; a `0`-width container defers
205
228
  layout until it has width. Call `destroy()` to tear down (a self-loaded engine is
206
- destroyed with it; an injected one is not — see below).
229
+ destroyed with it; a borrowed one is not — see below).
207
230
 
208
231
  Pass `refitOnResize: false` when the viewport must not determine the document's
209
232
  physical display size. An explicit pre-load `setScale(1)` then keeps the same
@@ -255,26 +278,38 @@ Pass `enableHyperlinks: false` to disable hyperlink interactivity entirely — n
255
278
  hit-testing, no pointer cursor over links, no default navigation, and
256
279
  `onHyperlinkClick` is never called; links still render as authored but are inert.
257
280
  This applies to every viewer that supports hyperlinks (`DocxViewer`,
258
- `DocxScrollViewer`, `PptxViewer`, `PptxScrollViewer`, `XlsxViewer`).
259
-
260
- **Master–detail / shared engine.** Inject an already-loaded headless engine so a
261
- paged viewer and a scroll viewer (or several panes) share **one** parse. When you
262
- inject, `load()` is unsupported (the engine is already loaded), the engine's own
263
- `mode` wins, and `destroy()` leaves the injected engine intact the caller owns
264
- its lifecycle:
281
+ `DocxScrollViewer`, `PptxViewer`, `PptxScrollViewer`, `XlsxViewer`,
282
+ `XlsxSheetViewer`).
283
+
284
+ **Choose one loading mode.** For the normal one-view case, construct a Viewer and
285
+ call `viewer.load(source)`: the Viewer owns the parsed engine, may replace it on a
286
+ later load, and destroys it during teardown. For master–detail, multi-pane, or
287
+ multi-window UIs, create the Viewer from an already-loaded headless engine so
288
+ every view shares **one** parse. The two modes are mutually exclusive: on a
289
+ Viewer returned by a `from*()` factory, `load()` is unsupported, the engine's
290
+ own `mode` wins, and `destroy()` leaves the borrowed engine intact — the caller
291
+ owns its lifecycle.
292
+
293
+ | Use case | Acquisition | Engine owner |
294
+ | --- | --- | --- |
295
+ | One Viewer | `new Viewer(target)` then `viewer.load(source)` | Viewer |
296
+ | Shared parse | `Engine.load(source)` then `Viewer.fromDocument / fromPresentation / fromWorkbook(...)` | Caller |
265
297
 
266
298
  ```typescript
267
- import { DocxDocument, DocxScrollViewer } from '@silurus/ooxml/docx';
268
-
269
- const doc = await DocxDocument.load('/document.docx'); // parse once
270
- const scroll = new DocxScrollViewer(container, { document: doc });
271
- // ...also drive a thumbnail grid, a paged view, etc. from the same `doc`.
272
- scroll.destroy(); // the injected `doc` is NOT destroyed — you own it
273
- doc.destroy(); // release it yourself when every pane is gone
299
+ import { DocxDocument, DocxScrollViewer, DocxViewer } from '@silurus/ooxml/docx';
300
+
301
+ const document = await DocxDocument.load('/document.docx'); // parse once
302
+ const scroll = DocxScrollViewer.fromDocument(container, document);
303
+ const page = DocxViewer.fromDocument(canvas, document);
304
+ await page.goToPage(0);
305
+ // ...also drive a thumbnail grid or more panes from the same document.
306
+ page.destroy();
307
+ scroll.destroy(); // the borrowed document is NOT destroyed — you own it
308
+ document.destroy(); // release it yourself when every pane is gone
274
309
  ```
275
310
 
276
- `PptxScrollViewer` takes the same shape with `{ presentation: pres }`
277
- (`await PptxPresentation.load(...)`).
311
+ `PptxViewer` and `PptxScrollViewer` use `fromPresentation(...)`; `XlsxViewer`
312
+ and `XlsxSheetViewer` use `fromWorkbook(...)`.
278
313
 
279
314
  For presentations, `enableMediaPlayback: true` makes embedded audio and video
280
315
  interactive inside the real viewport plus `mediaOverscan` slides. Other mounted
@@ -463,7 +498,7 @@ file without uploading it.
463
498
  | | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — full-text search, all hits highlighted, each match tagged with its page) | ✅ |
464
499
  | | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
465
500
  | | Clickable hyperlinks (overlay hit-test, `onHyperlinkClick`; internal bookmark / anchor navigation) | ✅ |
466
- | | Continuous scroll viewer (`DocxScrollViewer` — virtualized page list, desk background / shadow, Ctrl/⌘+wheel zoom, engine injection) | ✅ |
501
+ | | Continuous scroll viewer (`DocxScrollViewer` — virtualized page list, desk background / shadow, Ctrl/⌘+wheel zoom, borrowed-engine factory) | ✅ |
467
502
  | **Loading** | Password-protected files ([MS-OFFCRYPTO] Agile Encryption — `load(bytes, { password })`, decrypted client-side via WebCrypto; legacy Standard / Extensible encryption → typed `unsupported-encryption`) | ✅ |
468
503
 
469
504
  ---
@@ -624,7 +659,7 @@ file without uploading it.
624
659
  | | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — matches tagged with slide) | ✅ |
625
660
  | | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
626
661
  | | Clickable hyperlinks (`onHyperlinkClick`; internal slide-jump navigation) | ✅ |
627
- | | Continuous scroll viewer (`PptxScrollViewer` — virtualized slide list, desk background / shadow, Ctrl/⌘+wheel zoom, engine injection) | ✅ |
662
+ | | Continuous scroll viewer (`PptxScrollViewer` — virtualized slide list, desk background / shadow, Ctrl/⌘+wheel zoom, borrowed-engine factory) | ✅ |
628
663
  | **Loading** | Password-protected files ([MS-OFFCRYPTO] Agile Encryption — `load(bytes, { password })`, decrypted client-side via WebCrypto; legacy Standard / Extensible encryption → typed `unsupported-encryption`) | ✅ |
629
664
 
630
665
  ---
@@ -636,7 +671,8 @@ file without uploading it.
636
671
  ## Companion packages
637
672
 
638
673
  - **[`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.
639
- - **[`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.
674
+ - **[`packages/node/`](packages/node/)** — the implementation behind the public Node-only `@silurus/ooxml/node` subpath. Its canonical APIs are the explicitly owned, bounded `openPptxPresentation`, `openDocxDocument`, and `openXlsxWorkbook` sessions. Async `materializePptxPresentation`, `materializeDocxDocument`, `materializeXlsxWorkbookIndex`, `materializeXlsxWorksheet`, and `materializeXlsxWorkbook` are provided when a complete caller-owned graph is actually needed. Each `open*` call returns an explicit, idempotent `close()`-able session; PPTX streams `slides()`, 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.
675
+ See the [0.75 to 0.76 migration guide](docs/migration-0.76.md) for every removed synchronous helper and its replacement.
640
676
  - **[`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.
641
677
  - **[`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.
642
678
 
@@ -738,16 +774,17 @@ await viewer.load(file);
738
774
  ## Security & Privacy
739
775
 
740
776
  - **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.
741
- - **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:
777
+ - **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, the distinct entries visited during one package session may inflate to at most 256 MiB, and an archive may contain at most 4,096 entries. Override these budgets with a plain `resourceLimits` object on a viewer or `load(...)` call:
742
778
  ```ts
743
779
  new XlsxViewer(container, {
744
780
  resourceLimits: {
745
781
  maxArchiveEntryBytes: 64 * 1024 * 1024,
746
782
  maxTotalInflatedBytes: 192 * 1024 * 1024,
783
+ maxArchiveEntries: 2048,
747
784
  },
748
785
  });
749
786
  ```
750
- `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.
787
+ `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. `maxArchiveEntries` bounds central-directory entries before the ZIP library allocates its owned index. 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 integers; byte fields are expressed in bytes and the entry field is a count.
751
788
 
752
789
  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`.
753
790
 
@@ -769,6 +806,7 @@ await viewer.load(file);
769
806
  resourceLimits: {
770
807
  maxArchiveEntryBytes: 128 * 1024 * 1024,
771
808
  maxTotalInflatedBytes: 256 * 1024 * 1024,
809
+ maxArchiveEntries: 4096,
772
810
  },
773
811
  });
774
812
  ```
@@ -781,7 +819,7 @@ await viewer.load(file);
781
819
  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.
782
820
 
783
821
  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.
784
- - **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.
822
+ - **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`, `XlsxViewer`, and `XlsxSheetViewer`. 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.
785
823
  - **XML parsing.** Uses `roxmltree`, which does not resolve external entities (XXE-safe by default).
786
824
  - **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:
787
825
  ```ts
@@ -0,0 +1,254 @@
1
+ //#region packages/core/src/fonts/font-registry.ts
2
+ var e = /* @__PURE__ */ new Map();
3
+ function t(t, n, r) {
4
+ let i = e.get(t), a = i?.get(n);
5
+ if (a) return a.refs++, {
6
+ face: a.face,
7
+ isNew: !1
8
+ };
9
+ let o = r(), s = i ?? /* @__PURE__ */ new Map();
10
+ return s.set(n, {
11
+ face: o,
12
+ set: n,
13
+ refs: 1
14
+ }), e.set(t, s), {
15
+ face: o,
16
+ isNew: !0
17
+ };
18
+ }
19
+ function n(t) {
20
+ let n = /* @__PURE__ */ new Set();
21
+ for (let r of t) if (!n.has(r)) {
22
+ n.add(r);
23
+ for (let [t, n] of e) {
24
+ let i = !1;
25
+ for (let [a, o] of n) if (o.face === r) {
26
+ if (i = !0, o.refs--, o.refs <= 0) {
27
+ try {
28
+ o.set.delete(r);
29
+ } catch {}
30
+ n.delete(a), n.size === 0 && e.delete(t);
31
+ }
32
+ break;
33
+ }
34
+ if (i) break;
35
+ }
36
+ }
37
+ }
38
+ //#endregion
39
+ //#region packages/core/src/fonts/preload.ts
40
+ var r = 15e3;
41
+ function i(e) {
42
+ return Promise.race([e, new Promise((e) => setTimeout(e, r))]);
43
+ }
44
+ var a = /* @__PURE__ */ new Map();
45
+ function o(e) {
46
+ let t = [], n = /@font-face\s*\{([^}]*)\}/g, r;
47
+ for (; r = n.exec(e);) {
48
+ let e = r[1], n = (t) => e.match(RegExp(`(?:^|;|\\n)\\s*${t}\\s*:\\s*([^;]+)`, "i"))?.[1].trim(), i = n("font-family"), a = n("src");
49
+ if (!i || !a) continue;
50
+ let o = {}, s = n("font-style");
51
+ s && (o.style = s);
52
+ let c = n("font-weight");
53
+ c && (o.weight = c);
54
+ let l = n("font-stretch");
55
+ l && (o.stretch = l);
56
+ let u = n("unicode-range");
57
+ u && (o.unicodeRange = u), t.push({
58
+ family: i.replace(/^['"]|['"]$/g, ""),
59
+ src: a,
60
+ descriptors: o
61
+ });
62
+ }
63
+ return t;
64
+ }
65
+ function s() {
66
+ return typeof document < "u" && document && document.fonts ? document.fonts : typeof self < "u" && self && "fonts" in self ? self.fonts : null;
67
+ }
68
+ function c(e, t) {
69
+ let n = t.descriptors;
70
+ return [
71
+ "gfonts",
72
+ e,
73
+ t.family.toLowerCase(),
74
+ n.style ?? "",
75
+ n.weight ?? "",
76
+ n.stretch ?? "",
77
+ n.unicodeRange ?? "",
78
+ t.src
79
+ ].join("|");
80
+ }
81
+ async function l(e, n, r = s()) {
82
+ let l = r;
83
+ if (!l || typeof FontFace > "u" || typeof fetch > "u") return [];
84
+ let u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set(), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set();
85
+ for (let t of e) {
86
+ if (!t) continue;
87
+ let e = t.toLowerCase();
88
+ if (u.has(e)) continue;
89
+ u.add(e);
90
+ let r = n[e];
91
+ if (!r) continue;
92
+ f.add(r.url);
93
+ let i = (r.loadFamily ?? t).toLowerCase();
94
+ d.add(i);
95
+ let a = p.get(r.url);
96
+ a || (a = /* @__PURE__ */ new Set(), p.set(r.url, a)), a.add(i);
97
+ }
98
+ if (d.size === 0) return [];
99
+ let h = await i(Promise.all([...f].map(async (e) => {
100
+ let t = a.get(e);
101
+ if (t) return {
102
+ url: e,
103
+ rules: await t
104
+ };
105
+ let n = (async () => {
106
+ try {
107
+ let t = await fetch(e);
108
+ if (!t.ok) throw Error(`HTTP ${t.status}`);
109
+ return o(await t.text());
110
+ } catch {
111
+ a.delete(e);
112
+ for (let t of p.get(e) ?? []) m.add(t);
113
+ return [];
114
+ }
115
+ })();
116
+ return a.set(e, n), {
117
+ url: e,
118
+ rules: await n
119
+ };
120
+ }))), g = [], _ = [];
121
+ for (let e of Array.isArray(h) ? h : []) for (let n of e.rules) {
122
+ let { face: r, isNew: i } = t(c(e.url, n), l, () => {
123
+ let e = new FontFace(n.family, n.src, n.descriptors);
124
+ return l.add(e), e;
125
+ });
126
+ g.push(r), i && _.push(r);
127
+ }
128
+ return _.length > 0 && await i(Promise.allSettled(_.map((e) => e.load())).then((e) => (e.forEach((e, t) => {
129
+ e.status === "rejected" && m.add(_[t].family.replace(/['"]/g, "").toLowerCase());
130
+ }), l.ready))), m.size > 0 && console.warn(`[ooxml] failed to preload web font(s): ${[...m].join(", ")}; falling back to system fonts (text may shift or differ).`), g;
131
+ }
132
+ function u(e) {
133
+ n(e);
134
+ }
135
+ //#endregion
136
+ //#region packages/core/src/internal/bounded-async-lru-cache.ts
137
+ function d(e, t) {
138
+ if (!Number.isSafeInteger(e) || e <= 0) throw TypeError(`${t} must be a positive safe integer`);
139
+ }
140
+ function f(e) {
141
+ if (!Number.isSafeInteger(e) || e < 0) throw TypeError("cache entry weight must be a non-negative safe integer");
142
+ }
143
+ var p = class {
144
+ #e;
145
+ #t;
146
+ #n;
147
+ #r;
148
+ #i = /* @__PURE__ */ new Map();
149
+ #a = /* @__PURE__ */ new Map();
150
+ #o = 0;
151
+ constructor(e) {
152
+ d(e.maxEntries, "maxEntries"), d(e.maxWeight, "maxWeight"), this.#e = e.maxEntries, this.#t = e.maxWeight, this.#n = e.measure, this.#r = e.onRemove;
153
+ }
154
+ get usage() {
155
+ return {
156
+ entries: this.#i.size,
157
+ weight: this.#o,
158
+ pending: this.#a.size
159
+ };
160
+ }
161
+ has(e) {
162
+ return this.#i.has(e);
163
+ }
164
+ get(e) {
165
+ let t = this.#i.get(e);
166
+ if (t !== void 0) return this.#i.delete(e), this.#i.set(e, t), t.value;
167
+ }
168
+ getOrLoad(e, t) {
169
+ let n = this.get(e);
170
+ if (n !== void 0 || this.#i.has(e)) return Promise.resolve(n);
171
+ let r = this.#a.get(e);
172
+ if (r !== void 0) return r.promise;
173
+ let i = {}, a = Promise.resolve().then(t).then((t) => this.#c(e, i, t), (t) => {
174
+ throw this.#s(e, i), t;
175
+ });
176
+ return this.#a.set(e, {
177
+ token: i,
178
+ promise: a
179
+ }), a;
180
+ }
181
+ delete(e) {
182
+ let t = this.#a.delete(e), n = this.#i.get(e);
183
+ return n === void 0 ? t : (this.#i.delete(e), this.#o -= n.weight, this.#l(n.value, e, "deleted"), !0);
184
+ }
185
+ clear() {
186
+ this.#a.clear();
187
+ let e = [...this.#i];
188
+ this.#i.clear(), this.#o = 0;
189
+ for (let [t, n] of e) this.#l(n.value, t, "cleared");
190
+ }
191
+ #s(e, t) {
192
+ this.#a.get(e)?.token === t && this.#a.delete(e);
193
+ }
194
+ #c(e, t, n) {
195
+ if (this.#a.get(e)?.token !== t) return n;
196
+ let r;
197
+ try {
198
+ r = this.#n(n), f(r);
199
+ } catch (n) {
200
+ throw this.#s(e, t), n;
201
+ }
202
+ if (this.#a.get(e)?.token !== t || (this.#a.delete(e), r > this.#t)) return n;
203
+ let i = [];
204
+ for (; this.#i.size >= this.#e || r > this.#t - this.#o;) {
205
+ let e = this.#i.entries().next().value;
206
+ if (e === void 0) break;
207
+ let [t, n] = e;
208
+ this.#i.delete(t), this.#o -= n.weight, i.push([t, n]);
209
+ }
210
+ this.#i.set(e, {
211
+ value: n,
212
+ weight: r
213
+ }), this.#o += r;
214
+ for (let [e, t] of i) this.#l(t.value, e, "evicted");
215
+ return n;
216
+ }
217
+ #l(e, t, n) {
218
+ try {
219
+ this.#r?.(e, t, n);
220
+ } catch {}
221
+ }
222
+ }, m = class {
223
+ #e;
224
+ constructor(e) {
225
+ this.#e = new p({
226
+ maxEntries: e.maxEntries,
227
+ maxWeight: e.maxBytes,
228
+ measure: (e) => e.size
229
+ });
230
+ }
231
+ get usage() {
232
+ let e = this.#e.usage;
233
+ return {
234
+ entries: e.entries,
235
+ bytes: e.weight,
236
+ pending: e.pending
237
+ };
238
+ }
239
+ async get(e, t, n) {
240
+ if (typeof e != "string" || e.length === 0) throw TypeError("raw package part path must be a non-empty string");
241
+ if (typeof t != "string") throw TypeError("raw package part MIME type must be a string");
242
+ let r = await this.#e.getOrLoad(e, async () => {
243
+ let e = await n();
244
+ if (!(e instanceof Blob)) throw TypeError("raw package part loader must return a Blob");
245
+ return e;
246
+ });
247
+ return t === "" || r.type === t ? r : r.slice(0, r.size, t);
248
+ }
249
+ clear() {
250
+ this.#e.clear();
251
+ }
252
+ };
253
+ //#endregion
254
+ export { u as a, t as c, l as i, p as n, i as o, s as r, n as s, m as t };