Skip to content

[Preview NG] Add typed preview message protocol with validators#3474

Merged
jeremywiebe merged 4 commits intomainfrom
jer/preview-ng-3-message-types
Apr 14, 2026
Merged

[Preview NG] Add typed preview message protocol with validators#3474
jeremywiebe merged 4 commits intomainfrom
jer/preview-ng-3-message-types

Conversation

@jeremywiebe
Copy link
Copy Markdown
Collaborator

@jeremywiebe jeremywiebe commented Apr 9, 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 the typed message protocol that will underpin a new hook-based preview system for the Perseus editor. These types will allow us to understand and more easily control the data that is being sent between the editor and the preview iframe (in both directions). Purely additive — no existing behavior is changed.

The existing message-types.ts defined data types for preview content but had no structure for the messages themselves. This PR adds a PREVIEW_MESSAGE_SOURCE constant, base interfaces for structured messages, typed message definitions for both directions (iframe-to-parent and parent-to-iframe), and union types for use in message event handlers. New type guards in message-validators.ts safely narrow unknown postMessage events.

All existing types and the preview renderer are untouched — the new protocol types will be consumed by hooks in subsequent PRs.

Issue: LEMS-3741

Test plan:

pnpm test

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

🗄️ Schema Change: No Changes ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

🛠️ Item Splitting: No Changes ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 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 195 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 force-pushed the jer/preview-ng-3-message-types branch from ee718e7 to 65e0894 Compare April 9, 2026 19:02
@jeremywiebe jeremywiebe changed the base branch from jer/preview-ng-2-editor-minor-cleanups to main April 9, 2026 21:26
@jeremywiebe jeremywiebe force-pushed the jer/preview-ng-3-message-types branch 3 times, most recently from 90e2d9d to 2ea7fb6 Compare April 13, 2026 17:12
@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 (7a3dded) and published it to npm. You
can install it using the tag PR3474.

Example:

pnpm add @khanacademy/perseus@PR3474

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

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

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

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

@jeremywiebe jeremywiebe force-pushed the jer/preview-ng-3-message-types branch 2 times, most recently from 5557535 to 2ab6750 Compare April 13, 2026 22:40
…iew message types and validation functions with tests
@jeremywiebe jeremywiebe force-pushed the jer/preview-ng-3-message-types branch from 2ab6750 to ab31f4a Compare April 13, 2026 22:52
@jeremywiebe jeremywiebe marked this pull request as ready for review April 13, 2026 22: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.

Comment thread packages/perseus-editor/src/preview/message-validators.ts Outdated
* identifier to be from a Perseus preview host.
*
* @param message - Unknown message to validate
* @returns True if message is a valid ParentToIframeMessage
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.

Since these two functions are equivalent, does that mean that this scaffolding is here for future changes that would cause them to diverge? If such future changes are not expected in the near term, perhaps a comment somewhere on this page explaining the expected nature of the changes?

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.

Yes. These two function are used in upcoming PRs to filter and type check messages coming into a context via postMessage().

I wanted to make the PRs as small as possible so they are by themselves in a PR. I'd like to avoid hedging these comments and just state them as they'll be in the final state if that's ok.

Comment thread packages/perseus-editor/src/preview/message-validators.test.ts
@jeremywiebe jeremywiebe merged commit b78e2ce into main Apr 14, 2026
11 checks passed
@jeremywiebe jeremywiebe deleted the jer/preview-ng-3-message-types branch April 14, 2026 23:46
ivyolamit added a commit that referenced this pull request Apr 15, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @khanacademy/perseus-editor@30.3.0

### Minor Changes

- [#3474](#3474)
[`b78e2ce5c3`](b78e2ce)
Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add typed
preview message protocol with message types, validators, and tests

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d),
[`27e66ce3a6`](27e66ce),
[`b8ed10349d`](b8ed103)]:
    -   @khanacademy/perseus-core@24.1.1
    -   @khanacademy/perseus@77.2.2
    -   @khanacademy/keypad-context@3.2.43
    -   @khanacademy/kmath@2.4.1
    -   @khanacademy/math-input@26.4.14
    -   @khanacademy/perseus-linter@4.9.4
    -   @khanacademy/perseus-score@8.6.1

## @khanacademy/keypad-context@3.2.43

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1

## @khanacademy/kmath@2.4.1

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1

## @khanacademy/math-input@26.4.14

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1
    -   @khanacademy/keypad-context@3.2.43

## @khanacademy/perseus@77.2.2

### Patch Changes

- [#3491](#3491)
[`27e66ce3a6`](27e66ce)
Thanks [@ivyolamit](https://github.com/ivyolamit)! - Interactive Graph:
Fix Asymptote Line Thickness on Keyboard Focus for exponential and
logarithm


- [#3489](#3489)
[`b8ed10349d`](b8ed103)
Thanks [@ivyolamit](https://github.com/ivyolamit)! - Interactive Graph:
Fix Asymptote Drag Handle Blocked by Curve Line for Logarithm and
Exponential

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1
    -   @khanacademy/keypad-context@3.2.43
    -   @khanacademy/kmath@2.4.1
    -   @khanacademy/math-input@26.4.14
    -   @khanacademy/perseus-linter@4.9.4
    -   @khanacademy/perseus-score@8.6.1

## @khanacademy/perseus-core@24.1.1

### Patch Changes

- [#3480](#3480)
[`2f2724d244`](2f2724d)
Thanks [@benchristel](https://github.com/benchristel)! - Hide exports
that aren't used in frontend from the documentation.

## @khanacademy/perseus-linter@4.9.4

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1
    -   @khanacademy/kmath@2.4.1

## @khanacademy/perseus-score@8.6.1

### Patch Changes

- Updated dependencies
\[[`2f2724d244`](2f2724d)]:
    -   @khanacademy/perseus-core@24.1.1
    -   @khanacademy/kmath@2.4.1
@jeremywiebe jeremywiebe changed the title Add typed preview message protocol with validators [Preview NG] Add typed preview message protocol with validators Apr 15, 2026
@github-actions github-actions bot added 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 labels Apr 15, 2026
jeremywiebe added a commit that referenced this pull request Apr 16, 2026
…#3492)

## 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._

* #3464
* #3467 
* #3474

---

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`

Author: jeremywiebe

Reviewers: jeremywiebe, claude[bot], mark-fitzgerald, catandthemachines

Required Reviewers:

Approved By: mark-fitzgerald

Checks: ⏭️  1 check has been skipped, ✅ 10 checks were successful

Pull Request URL: #3492
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants