@silurus/ooxml 0.76.2 → 0.77.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/README.md +144 -32
- package/dist/{canvas-viewer-mechanics-CwVSOYke.js → canvas-viewer-mechanics-DTkBvITv.js} +318 -152
- package/dist/{document-pull-client-B-3_7_YS.js → document-pull-client-iWr8-S7P.js} +2106 -2028
- package/dist/{docx-C6B98B4-.js → docx-B1gYS6eU.js} +612 -191
- package/dist/docx.mjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/node.mjs +5 -5
- package/dist/{pptx-CKAk5e-J.js → pptx-CQjtK_o7.js} +646 -258
- package/dist/pptx.mjs +4 -4
- package/dist/pptx_parser_bg.wasm +0 -0
- package/dist/{render-CLcpSi0m.js → render-Ca80nlG5.js} +1 -1
- package/dist/{render-worker-host-Bkf1jUcW.js → render-worker-host-BozYMmxO.js} +1 -1
- package/dist/render-worker-host-C96AiK8e.js +27 -0
- package/dist/{render-worker-host-CKOmXdyr.js → render-worker-host-EHG5j8FK.js} +1 -1
- package/dist/{session-B4Y54cbT.js → session-KvKxQAeL.js} +1 -1
- package/dist/{slide-pull-client-WCuYCjio.js → slide-pull-client-BXb67StB.js} +15 -11
- package/dist/types/docx.d.ts +129 -28
- package/dist/types/index.d.ts +400 -86
- package/dist/types/node.d.ts +35 -20
- package/dist/types/pptx.d.ts +136 -10
- package/dist/types/xlsx.d.ts +163 -54
- package/dist/{xlsx-EykJ9tPV.js → xlsx-RLCmd1Bm.js} +1943 -1108
- package/dist/xlsx.mjs +4 -4
- package/package.json +1 -1
- package/dist/render-worker-host-Dpv-nKHY.js +0 -27
package/README.md
CHANGED
|
@@ -46,6 +46,11 @@ npm install @silurus/ooxml
|
|
|
46
46
|
pnpm add @silurus/ooxml
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
> Upgrading from v0.76? Review the
|
|
50
|
+
> [v0.77 migration guide](https://ooxml.silurus.dev/announcements/v077-migration-guide/)
|
|
51
|
+
> for the XLSX selection, selection-context, MCP-tool, option/type, and Viewer
|
|
52
|
+
> error-handling changes.
|
|
53
|
+
|
|
49
54
|
> **Bundler note**: the Rust parsers ship as real `.wasm` asset files next to the
|
|
50
55
|
> JavaScript, referenced with the standard `new URL('…', import.meta.url)` form
|
|
51
56
|
> and fetched (streaming-compiled) at load time. Verified to work with zero
|
|
@@ -71,7 +76,31 @@ pnpm add @silurus/ooxml
|
|
|
71
76
|
> new DocxViewer(canvas, { wasmUrl: 'https://cdn.example.com/docx_parser_bg.wasm' });
|
|
72
77
|
> ```
|
|
73
78
|
|
|
74
|
-
> **Bundle size note**: the package is ESM-only (`.mjs`). npm's *Unpacked
|
|
79
|
+
> **Bundle size note**: the package is ESM-only (`.mjs`). npm's *Unpacked
|
|
80
|
+
> Size* sums every entry bundle **and** the standalone MathJax + STIX Two Math
|
|
81
|
+
> asset, so the reported figure is much larger than any single app build. For
|
|
82
|
+
> v0.77.0, the complete npm package is approximately 11.3 MB unpacked (3.8 MB
|
|
83
|
+
> as the downloaded tarball), while a format-specific application graph is
|
|
84
|
+
> approximately:
|
|
85
|
+
>
|
|
86
|
+
> | Imported entry | Reachable assets | gzip | Includes |
|
|
87
|
+
> |---|---:|---:|---|
|
|
88
|
+
> | `@silurus/ooxml/docx` | 4.0 MB | 1.2 MB | DOCX renderer, parser WASM, and lazy worker |
|
|
89
|
+
> | `@silurus/ooxml/xlsx` | 2.6 MB | 0.82 MB | XLSX renderer, parser WASM, and lazy worker |
|
|
90
|
+
> | `@silurus/ooxml/pptx` | 2.5 MB | 0.78 MB | PPTX renderer, parser WASM, and lazy worker |
|
|
91
|
+
> | `@silurus/ooxml/math` | 3.1 MB | 1.1 MB | Optional MathJax + STIX Two Math engine |
|
|
92
|
+
>
|
|
93
|
+
> These are production-artifact estimates, not initial-load figures: each row
|
|
94
|
+
> sums all assets reachable from that entry, including parser WASM and worker
|
|
95
|
+
> chunks loaded on demand. Exact output varies by bundler and compression. Import
|
|
96
|
+
> only the format you need (for example, `@silurus/ooxml/pptx`) so the other
|
|
97
|
+
> formats can be tree-shaken. The math engine is a **separate entry** whose
|
|
98
|
+
> main-thread chunk is a ~1 KB loader referencing the ~3 MB engine as a
|
|
99
|
+
> **sibling file**, not an inline data URL. The engine is fetched lazily, only
|
|
100
|
+
> when a document contains equations, and only if you imported
|
|
101
|
+
> `@silurus/ooxml/math` and passed it to a viewer (see
|
|
102
|
+
> [Rendering equations](#rendering-equations)). Never import the `math` entry
|
|
103
|
+
> and the loader chunk never enters your graph at all.
|
|
75
104
|
|
|
76
105
|
---
|
|
77
106
|
|
|
@@ -92,6 +121,23 @@ docx.nextPage();
|
|
|
92
121
|
const container = document.getElementById('xlsx-container') as HTMLElement;
|
|
93
122
|
const xlsx = new XlsxViewer(container);
|
|
94
123
|
await xlsx.load('/workbook.xlsx');
|
|
124
|
+
xlsx.setSelection('B2:D5'); // A1 strings describe geometry; the normalized upper-left is ActiveCell
|
|
125
|
+
|
|
126
|
+
// Excel keeps Selection and ActiveCell separate. Use structured state when the
|
|
127
|
+
// active cell or Shift-extension anchor is not the area's upper-left cell.
|
|
128
|
+
xlsx.setSelection({
|
|
129
|
+
areas: [{ kind: 'cells', top: 2, left: 2, bottom: 5, right: 4 }],
|
|
130
|
+
activeAreaIndex: 0,
|
|
131
|
+
activeCell: { row: 3, col: 3 },
|
|
132
|
+
extensionAnchor: { row: 2, col: 2 },
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Read-only, serializable context for an AI/MCP request. Populated cells are
|
|
136
|
+
// bounded and detached; formulas and Viewer-formatted display text are retained.
|
|
137
|
+
const context = xlsx.getSelectionContext({
|
|
138
|
+
maxCells: 1_000,
|
|
139
|
+
maxTextCharacters: 1_048_576,
|
|
140
|
+
});
|
|
95
141
|
|
|
96
142
|
// XLSX active-sheet surface only — caller provides the <canvas>
|
|
97
143
|
const sheetCanvas = document.getElementById('xlsx-canvas') as HTMLCanvasElement;
|
|
@@ -266,6 +312,74 @@ slides outside the mounted window. Set `findHighlightColors: { match, active }`
|
|
|
266
312
|
on any viewer to override the two overlay backgrounds with CSS colors; use an
|
|
267
313
|
alpha color when the canvas text should remain visible through the highlight.
|
|
268
314
|
|
|
315
|
+
**Selection context for AI/MCP.** Every Viewer exposes one read-only query,
|
|
316
|
+
`getSelectionContext()`, for handing the user's current focus to an external
|
|
317
|
+
assistant. The result is a detached, JSON-serializable snapshot discriminated by
|
|
318
|
+
`format` and `kind`; it never exposes a mutable document model or sends data over
|
|
319
|
+
the network. Text, run locators, and populated XLSX cells have hard resource
|
|
320
|
+
limits. Check `truncated` / `truncationReasons` before building a prompt.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
const docx = new DocxViewer(docxCanvas, {
|
|
324
|
+
enableTextSelection: true,
|
|
325
|
+
enableElementSelection: true,
|
|
326
|
+
onSelectionContextChange(context) {
|
|
327
|
+
// kind === 'text' or 'element': selected text or a clicked drawing
|
|
328
|
+
updateAskAiButton(context);
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const pptx = new PptxViewer(pptxCanvas, {
|
|
333
|
+
enableTextSelection: true,
|
|
334
|
+
enableElementSelection: true,
|
|
335
|
+
onSelectionContextChange(context) {
|
|
336
|
+
// Text selection wins while it exists; otherwise a slide-element click
|
|
337
|
+
// yields kind === 'element' with compact bounds, provenance and content.
|
|
338
|
+
updateAskAiButton(context);
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const spreadsheet = new XlsxViewer(container, {
|
|
343
|
+
enableElementSelection: true,
|
|
344
|
+
onSelectionContextChange(context) {
|
|
345
|
+
updateAskAiButton(context);
|
|
346
|
+
},
|
|
347
|
+
onContextMenu: async ({ originalEvent, getContext }) => {
|
|
348
|
+
// Browser-menu control must happen synchronously, before the first await.
|
|
349
|
+
originalEvent.preventDefault();
|
|
350
|
+
const { clientX, clientY } = originalEvent;
|
|
351
|
+
const context = await getContext();
|
|
352
|
+
openContextMenu({ clientX, clientY, context });
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
const spreadsheetContext = spreadsheet.getSelectionContext({ maxCells: 1_000 });
|
|
356
|
+
// kind === 'range': selection state, values and formulas.
|
|
357
|
+
// kind === 'element': a clicked chart, picture or shape.
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
All three formats expose the same `onSelectionContextChange(context)` handoff;
|
|
361
|
+
callers may instead query on demand. `enableElementSelection` is an independent,
|
|
362
|
+
explicit opt-in because it enables object selection and draws a non-editable outline
|
|
363
|
+
around the focused object; adding the callback alone never enables object
|
|
364
|
+
hit-testing. XLSX separately retains
|
|
365
|
+
`onSelectionStateChange` for canonical UI state such as ActiveCell and multiple
|
|
366
|
+
areas. Its context callback is frame-coalesced so drag selection does not build
|
|
367
|
+
one snapshot per pointer event.
|
|
368
|
+
`onContextMenu` is also common to every Viewer. It receives the real browser
|
|
369
|
+
event synchronously so the host can call `preventDefault()`, plus a clearly
|
|
370
|
+
asynchronous `getContext()` lookup for the right-click target. The lookup starts
|
|
371
|
+
on the first call and is memoized. Omitting the callback installs no listener and leaves
|
|
372
|
+
the native browser menu unchanged.
|
|
373
|
+
`DocxDocument.getElementContextAt()` and
|
|
374
|
+
`PptxPresentation.getElementContextAt()` provide the identical compact element
|
|
375
|
+
query for custom/headless page or slide surfaces in both modes. PPTX
|
|
376
|
+
element provenance is limited to `master | layout | slide`; editor tree indexes,
|
|
377
|
+
archive paths, save/round-trip handles, and mutation APIs are deliberately absent.
|
|
378
|
+
When switching on `kind`, retain a default branch so a future read-only focus kind
|
|
379
|
+
can be added without changing the transport envelope.
|
|
380
|
+
See the [selection-context guide](docs/selection-context.md) for the complete
|
|
381
|
+
contract, resource bounds, PPTX hit-testing semantics, and extension policy.
|
|
382
|
+
|
|
269
383
|
**Hyperlinks.** For DOCX/PPTX the link hit regions live on the text-selection
|
|
270
384
|
overlay, so hyperlink interaction requires `enableTextSelection: true`; when that
|
|
271
385
|
overlay is enabled, links are interactive by default. XLSX hit-tests cells
|
|
@@ -344,20 +458,9 @@ const md = await doc.toMarkdown();
|
|
|
344
458
|
bullets, notes / comments collated) and `XlsxWorkbook.toMarkdown()` (each sheet →
|
|
345
459
|
a `## SheetName` pipe table) are the twins.
|
|
346
460
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
```typescript
|
|
351
|
-
import { docxToMarkdown, initDocxFromBytes } from '@silurus/ooxml-markdown';
|
|
352
|
-
|
|
353
|
-
initDocxFromBytes(wasmBytes); // the docx parser's `_bg.wasm`
|
|
354
|
-
const md = docxToMarkdown(fileBytes); // ArrayBuffer | Uint8Array | Buffer
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
```bash
|
|
358
|
-
npx ooxml-md document.docx # → stdout
|
|
359
|
-
npx ooxml-md deck.pptx -o deck.md # → file
|
|
360
|
-
```
|
|
461
|
+
The repository also contains a low-level adapter and CLI for workspace tooling.
|
|
462
|
+
They are internal implementation utilities, not separately published packages;
|
|
463
|
+
installed applications should use the format model's `toMarkdown()` method.
|
|
361
464
|
|
|
362
465
|
---
|
|
363
466
|
|
|
@@ -492,9 +595,10 @@ file without uploading it.
|
|
|
492
595
|
| | `w:snapToGrid` opt-out of the document grid (§17.3.1.32) | ✅ |
|
|
493
596
|
| | Track changes (`w:ins` / `w:del` — author-coloured underline / strikethrough) | ✅ |
|
|
494
597
|
| | Comments — author / date / text via the document model (`doc.comments`, §17.13.4; not drawn on the page) | ✅ |
|
|
495
|
-
| | Markdown export (`DocxDocument.toMarkdown()` — headings, lists, tables, footnotes / comments
|
|
598
|
+
| | Markdown export (`DocxDocument.toMarkdown()` — headings, lists, tables, footnotes / comments) | ✅ |
|
|
496
599
|
| | Mail merge fields | ❌ Not planned |
|
|
497
600
|
| **Interaction** | Text selection (transparent overlay, native copy) | ✅ |
|
|
601
|
+
| | Bounded read-only text/element context (`getSelectionContext()`, page/source locators, element selection, AI/MCP callback) | ✅ |
|
|
498
602
|
| | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — full-text search, all hits highlighted, each match tagged with its page) | ✅ |
|
|
499
603
|
| | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
|
|
500
604
|
| | Clickable hyperlinks (overlay hit-test, `onHyperlinkClick`; internal bookmark / anchor navigation) | ✅ |
|
|
@@ -547,12 +651,12 @@ file without uploading it.
|
|
|
547
651
|
| | Pivot tables (saved worksheet output renders unchanged; read-only metadata is exposed. Refresh, recalculation, filtering, restructuring, and interactivity are unsupported) | ⚠️ Partial |
|
|
548
652
|
| | Cell comments / notes (classic `xl/commentsN.xml` + Office-365 threaded comments — red triangle indicator + author / text via the worksheet model, shown in an Excel-style hover popup) | ✅ |
|
|
549
653
|
| | Data validation (rules via the worksheet model; `list`-type dropdown arrow on the selected cell whose click opens a panel showing the allowed values — read-only) | ✅ |
|
|
550
|
-
| | Markdown export (`XlsxWorkbook.toMarkdown()` — each sheet as a `## SheetName` pipe table
|
|
551
|
-
| **Interaction** | Cell selection (single / range / row / column / all) | ✅ |
|
|
654
|
+
| | Markdown export (`XlsxWorkbook.toMarkdown()` — each sheet as a `## SheetName` pipe table) | ✅ |
|
|
655
|
+
| **Interaction** | Cell selection (single / range / row / column / all / multiple areas; `setSelection('B2:D5')` or canonical structured state) | ✅ |
|
|
552
656
|
| | Excel-style row / column header highlight on selection | ✅ |
|
|
553
657
|
| | Shift+click to extend, Ctrl+C to copy as TSV | ✅ |
|
|
554
658
|
| | Text selection inside cells (transparent overlay) | ✅ |
|
|
555
|
-
| | `
|
|
659
|
+
| | `onSelectionStateChange`, bounded range/element `getSelectionContext()` / `copySelection()`, chart/picture/shape selection, `getCellAt(x, y)` | ✅ |
|
|
556
660
|
| | Zoom slider (Excel-style, right of the tab bar, 10–400% with 100% centered; `showZoomSlider` option) | ✅ |
|
|
557
661
|
| | Ctrl/⌘ + mouse-wheel and trackpad-pinch zoom (in addition to the slider) | ✅ |
|
|
558
662
|
| | Runtime fit / zoom API (`fitWidth` / `fitPage` / `getScale` / `setScale`, in addition to the slider) | ✅ |
|
|
@@ -574,7 +678,7 @@ file without uploading it.
|
|
|
574
678
|
| | Slide background (solid, gradient, image) | ✅ |
|
|
575
679
|
| | Slide numbers | ✅ |
|
|
576
680
|
| | Speaker notes (plain text via `getNotes()`) | ✅ |
|
|
577
|
-
| | Markdown export (`PptxPresentation.toMarkdown()` — title slides → headings, body → nested bullets, notes / comments collated
|
|
681
|
+
| | Markdown export (`PptxPresentation.toMarkdown()` — title slides → headings, body → nested bullets, notes / comments collated) | ✅ |
|
|
578
682
|
| | Animations / transitions | ❌ Not planned |
|
|
579
683
|
| **Element types** | Shapes (`sp`) | ✅ |
|
|
580
684
|
| | Pictures (`pic`) | ✅ |
|
|
@@ -656,6 +760,7 @@ file without uploading it.
|
|
|
656
760
|
| | Font scheme (`+mj-lt`, `+mn-lt`) | ✅ |
|
|
657
761
|
| | lumMod / lumOff / alpha transforms | ✅ |
|
|
658
762
|
| **Interaction** | Text selection (transparent overlay, native copy) | ✅ |
|
|
763
|
+
| | Bounded text/element selection context (`getSelectionContext()`, element selection, master/layout/slide provenance, main + worker) | ✅ |
|
|
659
764
|
| | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — matches tagged with slide) | ✅ |
|
|
660
765
|
| | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
|
|
661
766
|
| | Clickable hyperlinks (`onHyperlinkClick`; internal slide-jump navigation) | ✅ |
|
|
@@ -670,10 +775,10 @@ file without uploading it.
|
|
|
670
775
|
|
|
671
776
|
## Companion packages
|
|
672
777
|
|
|
673
|
-
- **[`packages/markdown/`](packages/markdown/)** —
|
|
778
|
+
- **[`packages/markdown/`](packages/markdown/)** — internal workspace adapter and `ooxml-md` development CLI for the same GitHub-flavoured Markdown projection exposed by each format model's `toMarkdown()` method.
|
|
674
779
|
- **[`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
780
|
See the [0.75 to 0.76 migration guide](docs/migration-0.76.md) for every removed synchronous helper and its replacement.
|
|
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`
|
|
781
|
+
- **[`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` for GitHub Copilot Chat in Agent mode, including active Viewer selection. Claude Code and Codex can configure the same binary separately for path-based file tools, but do not receive the active selection bridge. 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.
|
|
677
782
|
- **[`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.
|
|
678
783
|
|
|
679
784
|
---
|
|
@@ -712,16 +817,18 @@ cd packages/pptx/parser && wasm-pack build --target web && cp pkg/pptx_parser_bg
|
|
|
712
817
|
|
|
713
818
|
## Error handling
|
|
714
819
|
|
|
715
|
-
Headless APIs (`DocxDocument`, `XlsxWorkbook`, and `PptxPresentation`)
|
|
716
|
-
|
|
717
|
-
|
|
820
|
+
Headless APIs (`DocxDocument`, `XlsxWorkbook`, and `PptxPresentation`) and
|
|
821
|
+
Viewer APIs report failures from awaitable operations by rejecting the returned
|
|
822
|
+
Promise. This includes `viewer.load()` parsing and its initial render, whether
|
|
823
|
+
or not the Viewer has an `onError(error)` callback. A failure is never delivered
|
|
824
|
+
through both channels.
|
|
718
825
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
826
|
+
Use `onError` for later Viewer-managed work that has no directly awaitable
|
|
827
|
+
result, such as virtualized scroll-view rendering or embedded-media playback.
|
|
828
|
+
Those failures are logged with `console.error` when the callback is omitted.
|
|
829
|
+
`PptxPresentation.presentSlide()` follows the same boundary: initialization
|
|
830
|
+
rejects its Promise, while `PresentSlideOptions.onError` observes only media
|
|
831
|
+
decode or playback failures after the presentation handle has been returned.
|
|
725
832
|
|
|
726
833
|
Stable failures can be narrowed without parsing message strings:
|
|
727
834
|
|
|
@@ -754,6 +861,7 @@ import {
|
|
|
754
861
|
} from '@silurus/ooxml/docx';
|
|
755
862
|
|
|
756
863
|
const viewer = new DocxViewer(canvas, {
|
|
864
|
+
// Background failures after an awaited operation has completed.
|
|
757
865
|
onError(error) {
|
|
758
866
|
if (error instanceof OoxmlResourceLimitError) {
|
|
759
867
|
const { limit, observed } = error.details.violation;
|
|
@@ -768,7 +876,11 @@ const viewer = new DocxViewer(canvas, {
|
|
|
768
876
|
},
|
|
769
877
|
});
|
|
770
878
|
|
|
771
|
-
|
|
879
|
+
try {
|
|
880
|
+
await viewer.load(file);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
reportUnexpectedError(error);
|
|
883
|
+
}
|
|
772
884
|
```
|
|
773
885
|
|
|
774
886
|
## Security & Privacy
|