Skip to content

[Preview NG] Add functions to sanitize objects for sending to Preview#3492

Merged
jeremywiebe merged 3 commits intomainfrom
jer/preview-ng-4-sanitize-api-options
Apr 16, 2026
Merged

[Preview NG] Add functions to sanitize objects for sending to Preview#3492
jeremywiebe merged 3 commits intomainfrom
jer/preview-ng-4-sanitize-api-options

Conversation

@jeremywiebe
Copy link
Copy Markdown
Collaborator

@jeremywiebe jeremywiebe commented Apr 13, 2026

Summary:

This PR is part of a series building a typed, hook-based preview system for the Perseus editor. The new system replaces the untyped window.iframeDataStore + raw postMessage(string) communication with structured, validated message passing via usePreviewHost and usePreviewClient hooks. The new system is being built alongside the old one — no existing behaviour changes until the final PR in the series flips the switch.


Adds sanitizeApiOptions() and sanitizePreviewData() which strip non-serializable values (function callbacks, React components) from preview data before it's sent via postMessage. The structured clone algorithm used by postMessage can't handle functions, so they need to be removed before sending.

sanitizeApiOptions() destructures APIOptions to remove known non-serializable fields (onFocusChange, trackInteraction, imagePreloader, nativeKeypadProxy, placeholder components, etc.) and returns only the serializable remainder.

sanitizePreviewData() wraps this for all preview content types — question, hint, article, and article-all. The article-all case currently sanitizes per-section since each ArticlePreviewData carries its own apiOptions; this will be simplified when we restructure the preview data types in a later PR.

Purely additive — no existing behaviour is changed.

Depends on: #3474

Issue: LEMS-3741

Test plan:

pnpm test

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

🗄️ Schema Change: No Changes ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

🛠️ Item Splitting: No Changes ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (339d4e6) and published it to npm. You
can install it using the tag PR3492.

Example:

pnpm add @khanacademy/perseus@PR3492

If you are working in Khan Academy's frontend, you can run the below command.

./dev/tools/bump_perseus_version.ts -t PR3492

If you are working in Khan Academy's webapp, you can run the below command.

./dev/tools/bump_perseus_version.js -t PR3492

@jeremywiebe jeremywiebe changed the title ## Summary: Add functions to sanitize objects for sending to Preview Apr 14, 2026
@github-actions github-actions bot added item-splitting-change schema-change Attached to PRs when we detect Perseus Schema changes in it and removed schema-change Attached to PRs when we detect Perseus Schema changes in it item-splitting-change labels Apr 14, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Size Change: 0 B

Total Size: 499 kB

ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 20.5 kB
packages/keypad-context/dist/es/index.js 1 kB
packages/kmath/dist/es/index.js 6.36 kB
packages/math-input/dist/es/index.js 98.5 kB
packages/math-input/dist/es/strings.js 1.61 kB
packages/perseus-core/dist/es/index.item-splitting.js 11.9 kB
packages/perseus-core/dist/es/index.js 25.1 kB
packages/perseus-editor/dist/es/index.js 102 kB
packages/perseus-linter/dist/es/index.js 9.3 kB
packages/perseus-score/dist/es/index.js 9.7 kB
packages/perseus-utils/dist/es/index.js 403 B
packages/perseus/dist/es/index.js 196 kB
packages/perseus/dist/es/strings.js 8.27 kB
packages/pure-markdown/dist/es/index.js 1.39 kB
packages/simple-markdown/dist/es/index.js 6.71 kB

compressed-size-action

@jeremywiebe jeremywiebe changed the base branch from jer/preview-ng-3-message-types to main April 14, 2026 23:46
@jeremywiebe jeremywiebe force-pushed the jer/preview-ng-4-sanitize-api-options branch from 8bc23c9 to 25f974c Compare April 15, 2026 00:00
@jeremywiebe jeremywiebe changed the title Add functions to sanitize objects for sending to Preview [Preview NG] Add functions to sanitize objects for sending to Preview Apr 15, 2026
* carries its own apiOptions). This will be simplified to a single apiOptions
* when we restructure the preview data types.
*/
export function sanitizePreviewData(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preview system needs to send API options into the preview panel because some API Options can affect behaviour/rendering. But, some API Options are not serializable and deal with host integration (for example, callbacks) and so we need to sanitize the options before sending them over the "bridge".

imagePreloader: _____,
trackInteraction: ______,
setDrawingAreaAvailable: ________,
baseElements: _________,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one key that can affect rendering. It is used in some contexts in the frontend application, but since this contains React elements, we can't send it across the bridge. In reality, host applications only set the Link element within this key and generally use it to override the behaviour of handling the clicked link vs. actually changing how it renders.

@github-actions github-actions bot added schema-change Attached to PRs when we detect Perseus Schema changes in it item-splitting-change labels Apr 15, 2026
@jeremywiebe jeremywiebe marked this pull request as ready for review April 15, 2026 15:59
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@github-actions github-actions bot removed schema-change Attached to PRs when we detect Perseus Schema changes in it item-splitting-change labels Apr 15, 2026
@jeremywiebe jeremywiebe force-pushed the jer/preview-ng-4-sanitize-api-options branch from d534a50 to 0419ad1 Compare April 15, 2026 19:27
const result = sanitizePreviewData(previewContent);

expect(result.type).toBe("question");
if (result.type === "question") {
Copy link
Copy Markdown
Contributor

@mark-fitzgerald mark-fitzgerald Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this conditional needed? If result.type does not equal "question", then the assertion before it will fail and cause the test to exit, correct? Is this here for some TypeScript reason?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because the previous assertion doesn't "narrow" the type. Without the if block, line 63+ don't know that we're dealing with a result that is a question type. I'll see if I can change how we do that. I know we use the tinyinvariant library in places and I think that narrows properly.

expect(result).toEqual(previewContent);
});

it("does not mutate original question data", () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great callout!!

@jeremywiebe jeremywiebe merged commit 883133a into main Apr 16, 2026
11 checks passed
@jeremywiebe jeremywiebe deleted the jer/preview-ng-4-sanitize-api-options branch April 16, 2026 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants