Skip to content

fix: validate sandbox plugin exports and fix plugin packaging#363

Merged
ascorbic merged 7 commits intomainfrom
fix/sandbox-source-validation
Apr 7, 2026
Merged

fix: validate sandbox plugin exports and fix plugin packaging#363
ascorbic merged 7 commits intomainfrom
fix/sandbox-source-validation

Conversation

@ascorbic
Copy link
Copy Markdown
Collaborator

@ascorbic ascorbic commented Apr 7, 2026

What does this PR do?

The webhook-notifier plugin exported raw TypeScript source from its package.json ("./sandbox": "./src/sandbox-entry.ts"). When the Vite plugin resolved this at site build time via require.resolve(), it embedded unbuilt TypeScript into the sandbox module, causing Unexpected token '{' errors at runtime.

The root cause is a missing build step — sandboxed-test already had the correct pattern (tsdown build + dist/*.mjs exports), but webhook-notifier was pointing directly at source.

This PR:

  1. Fixes webhook-notifier — adds a tsdown build step and updates package.json exports to point to dist/*.mjs (matching sandboxed-test's pattern).

  2. Adds build-time validationgenerateSandboxedPluginsModule() now throws a clear error if a sandbox entrypoint resolves to a TypeScript/JSX source file, catching misconfigured plugins at site build time.

  3. Adds bundle-time validationemdash bundle now checks that all package.json exports point to built files, catching the misconfiguration at plugin publish time before consumers are affected.

  4. Fixes oxlintrc override syntax — the e18e/prefer-static-regex test override used parenthesis syntax (e18e(prefer-static-regex)) instead of slash syntax, so the override wasn't taking effect.

Closes #150

Type of change

  • Bug fix
  • Feature (requires approved Discussion)
  • Refactor (no behavior change)
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm --silent lint:json | jq '.diagnostics | length' returns 0
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...

AI-generated code disclosure

  • This PR includes AI-generated code

Screenshots / test output

✓ tests/unit/astro/virtual-modules-sandbox.test.ts (6 tests) 11ms
✓ tests/unit/cli/bundle-utils.test.ts (31 tests) 40ms

 Test Files  2 passed (2)
      Tests  37 passed (37)

ascorbic added 5 commits April 7, 2026 21:04
The webhook-notifier plugin exported raw TypeScript source from its
package.json exports (./sandbox pointed to src/sandbox-entry.ts).
When the Vite plugin resolved this at site build time, it embedded
unbuilt TypeScript into the sandbox module, causing "Unexpected token
'{'" errors at runtime.

Add a tsdown build step (matching sandboxed-test's pattern) and update
the exports map to point to dist/*.mjs.

Fixes #150
…le validator

Add two validation checks to prevent plugins with misconfigured exports
from silently breaking site builds:

1. generateSandboxedPluginsModule() now throws a clear error if a
   sandbox entrypoint resolves to a TypeScript/JSX source file instead
   of pre-built JavaScript. This catches the problem at site build time
   with an actionable message.

2. The `emdash bundle` command now validates that all package.json
   exports point to built files (.js/.mjs), not source (.ts/.tsx/.jsx).
   This catches the misconfiguration at plugin publish time, before
   consumers are affected.

Fixes #150
The test file override for e18e/prefer-static-regex used parenthesis
syntax ("e18e(prefer-static-regex)") which is the diagnostic display
format, not the config format. Changed to slash syntax to match the
top-level rule declarations so the override actually takes effect.
Add tests for both validation checks:

- generateSandboxedPluginsModule: verifies it embeds pre-built JS,
  rejects .ts/.tsx/.mts source files, and includes the plugin ID in
  error messages.

- findSourceExports: verifies it flags .ts/.tsx/.mts/.cts/.jsx exports,
  accepts .mjs/.js exports, and handles conditional export maps.

Also extracts findSourceExports() from the inline bundle.ts validation
into bundle-utils.ts so it can be tested without the CLI harness.
Copilot AI review requested due to automatic review settings April 7, 2026 20:12
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 7, 2026

🦋 Changeset detected

Latest commit: 27311b9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
emdash Patch
@emdash-cms/plugin-webhook-notifier Patch
@emdash-cms/plugin-atproto Patch
@emdash-cms/plugin-audit-log Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-ai-moderation Patch
@emdash-cms/plugin-color Patch
@emdash-cms/plugin-embeds Patch
@emdash-cms/plugin-forms Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Apr 7, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 27311b9 Apr 07 2026, 08:36 PM

Same issue as webhook-notifier — both plugins exported raw TypeScript
source from their package.json sandbox exports. Add tsdown build steps
and update exports to point to dist/*.mjs.
@ascorbic ascorbic changed the title fix: validate sandbox plugin exports and fix webhook-notifier packaging fix: validate sandbox plugin exports and fix plugin packaging Apr 7, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 7, 2026

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@363

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@363

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@363

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@363

emdash

npm i https://pkg.pr.new/emdash@363

create-emdash

npm i https://pkg.pr.new/create-emdash@363

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@363

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@363

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@363

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@363

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@363

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@363

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@363

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@363

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@363

commit: 27311b9

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a sandboxed-plugin runtime failure caused by plugins exporting unbuilt TypeScript by (1) correcting webhook-notifier’s packaging to export built dist/*.mjs, and (2) adding build-time + bundle-time validation to catch similar misconfigurations earlier.

Changes:

  • Update @emdash-cms/plugin-webhook-notifier to build with tsdown and export built dist entrypoints (including ./sandbox).
  • Add validation in generateSandboxedPluginsModule() to error if a sandbox entry resolves to TS/JSX source.
  • Add emdash bundle validation + unit tests to flag package.json exports pointing to TS/JSX source, and fix an oxlint override key.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pnpm-lock.yaml Adds tsdown/typescript to the workspace lockfile for the plugin build.
packages/plugins/webhook-notifier/package.json Switches exports from src/* to built dist/* and adds tsdown build/dev scripts.
packages/core/tests/unit/cli/bundle-utils.test.ts Adds test coverage for new findSourceExports() validation.
packages/core/tests/unit/astro/virtual-modules-sandbox.test.ts Adds tests ensuring sandbox module generation rejects TS/TSX/MTS entries and includes plugin id in errors.
packages/core/src/cli/commands/bundle.ts Adds bundle-time validation to error on source-file exports.
packages/core/src/cli/commands/bundle-utils.ts Introduces findSourceExports() helper used by bundle validation.
packages/core/src/astro/integration/virtual-modules.ts Adds build-time guard to reject sandbox entrypoints that resolve to TS/JSX source.
.oxlintrc.json Fixes override rule key syntax so the rule is actually disabled for that override.
.changeset/major-boxes-juggle.md Adds changeset entries for emdash and @emdash-cms/plugin-webhook-notifier.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +224 to +234
export function findSourceExports(
exports: Record<string, unknown>,
): Array<{ exportPath: string; resolvedPath: string }> {
const issues: Array<{ exportPath: string; resolvedPath: string }> = [];
for (const [exportPath, exportValue] of Object.entries(exports)) {
const resolved =
typeof exportValue === "string"
? exportValue
: exportValue && typeof exportValue === "object" && "import" in exportValue
? (exportValue as { import: string }).import
: null;
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

findSourceExports() only inspects string exports and conditional exports with an import field. Valid package.json export objects can also use default/require (and can nest conditions), so a misconfigured plugin could still export ./src/*.ts and bypass this validation. Consider recursively walking export values and checking all string targets (excluding types) across common conditions (import/require/default) so the bundle-time check matches its intent.

Copilot uses AI. Check for mistakes.
…ive pnpm build

The build verification section was running `astro build` individually
and sequentially for every demo and template (~12 sites). Replace with
a single `pnpm run --recursive --filter {./demos/*} --filter
{./templates/*} build` which pnpm parallelizes automatically.
@ascorbic ascorbic merged commit 91e31fb into main Apr 7, 2026
27 checks passed
@ascorbic ascorbic deleted the fix/sandbox-source-validation branch April 7, 2026 21:34
@emdashbot emdashbot bot mentioned this pull request Apr 7, 2026
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.

webhook-notifier 400 error

2 participants