mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-28 08:25:57 +08:00
* fix(sanitize): keep inline math through the scene-content sanitizer The prose policy flattened the editor's inline formulas on every persistence read and write: it dropped data-inline-math, the MathML annotation, the layout SVG and KaTeX positioning, so saved formulas rendered broken and their LaTeX source was lost. Move the lift / sanitize / re-render approach from the standalone HTML export into lib/sanitize/inline-math.ts and apply it in sanitizeProseHtml, so the persistence boundary and the export share one implementation. It parses with parse5, so it needs no DOM and runs on the server and in the browser alike. Each formula is replaced by an empty source span before sanitizing, and every surviving source span is replaced afterwards by a fresh KaTeX render (trust: false); authored markup never bypasses the policy. Prose without a formula skips the parse and is sanitized byte-for-byte as before. Renders are cached by source, and pathological markup falls back to the plain policy instead of failing the read or write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(sanitize): bound inline math rendering and detect encoded KaTeX classes KaTeX markup is 100-150x the size of its source and is regenerated synchronously on every persistence read and write, so one large formula could block the event loop for seconds and pin hundreds of MB in the render cache. - Render a formula only if its source is at most 2000 characters, and within a per-call budget of 16000 source characters and 1000 formulas. Anything else stays a source span showing its LaTeX as text, so nothing is lost and the editor still recovers it. Limits are counted in document order, never time, so repeated passes stay stable. - Bound the render cache by markup size (1 MB) and never cache renders over 32 KB. - Pre-check on `data-inline-math` or `annotation` instead of `katex`: element and attribute names cannot be written as character references, but a class value can, so an encoded `katex` class no longer skips the lift and loses its source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(sanitize): store inline math as source and typeset it in the client Rendering formulas on the server made every persistence read and write run KaTeX on authored input, which user macros and long sources can turn into seconds of CPU per document. Store each inline formula as its LaTeX source instead and let the clients that display slides typeset it. - The prose sanitizer reduces each inline formula (span[data-inline-math], else span.katex with a TeX annotation, entity-encoded class included) to <span data-inline-math="SRC">SRC</span> and allows only that attribute. The source doubles as text for consumers that do not render math. A source over 2000 characters is kept as plain text. The pre-pass uses htmlparser2, the parser sanitize-html uses, so it is linear and sees the same element boundaries; prose without a formula marker is sanitized exactly as before. The server never runs KaTeX, and the parse5 lift, render cache and budgets are gone. - @openmaic/renderer typesets span[data-inline-math] in text, shape and table prose after injection (renderInlineMath / useInlineMath), with trust disabled, macro definitions blocked and bounded expansion. It also re-renders older content that still carries KaTeX markup. The app's slide renderer components use the same hook. Bump the renderer to 0.1.12. - The standalone HTML export ships source-only formulas, which the player's renderer typesets, and ships the math fonts when a slide has an inline formula. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(slide-renderer): keep cell markup intact when formatting table text formatText turned every space in a table cell into , including the spaces inside tags, which broke any cell markup with attributes. An inline formula in a cell was shown as its raw source instead of being typeset. Only format the text between tags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(renderer): allow 1000 macro expansions when typesetting inline math A cap of 50 expansions rejects realistic long formulas: built-in commands such as \neq, \iff, \, and \dots each count, and a formula with a few dozen of them needs over 100. Macro definitions are blocked, so expansion stays linear in the source and 1000 is only a backstop. This matches the shared safe KaTeX options. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(sanitize): replace self-closing inline formulas in SVG and MathML once Inside SVG or MathML the parser honours `/>` and reports the close as implied while still on the opening token, so the replacement ended before the formula started and the original span stayed next to the stored one; the next pass then stored it again. End a formula no earlier than its opening tag. Adds SVG and MathML cases and fuzzes the pass for idempotency and formula shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(renderer): keep inline math typeset across re-renders React can rewrite `dangerouslySetInnerHTML` markup on a re-render even when the HTML string is unchanged, which put the stored source spans back after a move or resize while the effect, keyed on the HTML, did not run again. Typeset after every commit instead: formulas already typeset are skipped, and typeset formulas are cached by source and cloned, so a re-render costs a query and, at most, cheap clones. Typesetting never updates React state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(renderer): budget inline math typesetting per prose root One slide packed with large formulas could block the page for hundreds of milliseconds on every mount. Typeset at most 4000 characters of uncached source or 100 uncached formulas per pass over a prose root before paint, and the rest in idle time, a chunk of the same size per idle period. The next commit, an unmount or new content cancels pending idle work. Past 50 000 characters or 1000 formulas per root, formulas are shown as their LaTeX text. Slide snapshots typeset everything before capture. Covers identical-content re-renders and A, B, A, A content sequences in both renderers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(renderer): keep inline math progress across commits and complete snapshots per root - Give injected prose a stable dangerouslySetInnerHTML value per markup string (text, shape label and each table cell, in both renderers), so React leaves unchanged markup alone. Typeset formulas and pending idle progress then survive re-renders; formulas too large to cache are no longer typeset again on every commit. The every-commit pass stays as a safety net. - Mark each prose root and complete snapshots root by root, so each text box keeps its own hard cap as on the live slide instead of sharing one slide-wide count. - Apply the hard cap from document order on every pass, whatever earlier passes typeset, and let a formula shown as text by an earlier cap be typeset once it falls within its root's cap. - Note that the render cache bound counts serialized characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(renderer): bump to 0.1.13 after rebase Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(renderer): typeset inline math through the shared safeKatexOptions Replace the local stand-in options (inert macro-definition commands, trust: false, maxExpand 1000) with safeKatexOptions from @openmaic/dsl, keeping the inline-specific settings (displayMode: false, output: html, throwOnError: false, strict: ignore). The shared helper's expansion budget is the same 1000, and it also keeps the built-in \tag/\notag state and makes \long inert. The math engine guard now lists the renderer's inline-math module as a render-calls site and drops the standalone HTML rich-text module, which no longer renders KaTeX itself. Tests: ordinary formulas typeset byte-for-byte as with the previous options, and formula-defined macros stay inert within one formula and across formulas in the same prose root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(sanitize): keep over-long inline formulas as formulas; bound typesetting only The 2000-character bound dropped the data-inline-math marker at save time, so an over-long formula became plain text for good. The bound now applies only where formulas are typeset: the slide renderer already shows an over-long source as text, and the editor's inline_math node now does the same instead of typesetting it, using the renderer's MAX_INLINE_MATH_SOURCE. @openmaic/editor 0.0.11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(sanitize): a 100 KB formula is kept as a formula in the node-environment suite Follows the sanitizer change: the length bound applies to typesetting only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>