Repository navigation
Conversation
🦋 Changeset detectedLatest commit: c6132ad The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 packages
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 |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 3e63a60 | Sep 20 2026, 02:56 AM |
Scope checkThis PR changes 3,585 lines across 70 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-test
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-loader
@emdash-cms/registry-moderation
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
/accept-baselines |
|
✅ Baselines accepted by @ascorbic and committed to this PR. |
|
/review |
|
Review posted successfully at #3188 (review). Summary of findings:
|
|
/review |
|
Wait — this reset effect fires on mount too (since But OK, let me write and post my review. My verdict: The existing review by ask-bonk was strong. The two fixes look correct. The remaining nits (toast type, pending state) are either author-correct or pre-existing patterns. I found one minor new issue (rapid toggle race). Given that this is a targeted follow-up review after the previous one where the primary fixes are in, and my only new finding is a very low-severity edge case, I'll post a small focused review noting the rapid-toggle race and confirming the two fixes look correct. Actually — let me check one more time if the rapid open/close/open bug is real. React 18 batches setState in event handlers. Let me think about Actually,
So the race requires the two clicks to happen within one React batch. That would need synchronous programmatic clicks. Highly unlikely in practice. Not a real user-triggered bug. I'm going to skip that finding. My conclusion: the previous review's fixes are correct, and I have no new bugs to report at severity worth mentioning. Given the extensive validation, resolved review, and confirmed fixes, this looks good. LGTM! |
ab1bf67 to
7643ab0
Compare
7643ab0 to
3e63a60
Compare
There was a problem hiding this comment.
The PR adds saved-entry editor panels and actions for plugins in a sound way: it reloads and ownership-authorizes the entry before crossing the sandbox boundary, exposes only canonical identity/locale/version, and wires the UI lazily. The manifest, runtime, admin, and CLI changes are consistent, and the tests exercise auth, validation, and the plugin-test host.
There are two blockers in packages/core/src/plugins/http-route-dispatch.ts:
- The dispatch helper loads the saved entry before it has verified the caller. An unauthenticated or forged request can therefore trigger a content-table query and observe success/failure timing. It should reject unauthenticated callers (and ideally validate route permission/CSRF) before the database read.
- It rebuilds the request body while copying the original
Content-Lengthheader. That header describes the client’s original payload, so action requests (where the body is replaced with{ "type": "editor_action" }) can be sent to the plugin route with a stale length, risking truncated/padded body parsing.
A smaller suggestion: the marketplace manifest schema hand-maintains a copy of the core permission list; using the canonical Permissions object would prevent drift.
Once the auth-order and content-length issues are addressed, this should be good to land.
There was a problem hiding this comment.
Re-review of PR #3188: the two blockers from the previous review are resolved, and the marketplace/core schema parity gap is closed.
What changed since the last review:
packages/core/src/plugins/http-route-dispatch.tsnow authenticates the caller (route permission, admin token scope, and CSRF header) before it reloads the saved entry. Unauthenticated or forged requests no longer reachhandleContentGet.- The reconstructed plugin request now explicitly deletes
content-lengthandcontent-encoding, so the new JSON body cannot be parsed with stale chunked/length information. packages/marketplace/src/routes/author.tsnow validates route permissions against the canonicalPermissionsobject from@emdash-cms/authand includeseditorPanels/editorActionsschemas and duplicate/private-route checks matching core and@emdash-cms/plugin-types.- Regression tests cover the auth-order, content-length, and schema-parity cases.
I re-checked the whole diff for the other cross-cutting concerns in AGENTS.md:
- Authorization follows
requirePerm/requireOwnerPerm; permission strings are validated againstPermissions; inherited object keys are rejected withObject.hasOwn. - CSRF is enforced via
X-EmDash-Requestbefore any content query. - The route file follows Astro route conventions (
prerender = false, thin wrapper,apiError). - User-facing strings in the new React components are Lingui-wrapped, and no new physical-direction Tailwind classes were introduced.
- The changeset is user-facing and proportional to the feature.
- No SQL, index, or logged-out hot-path changes.
The implementation fits EmDash’s architecture: saved identity is reloaded and ownership-checked on the host side, only canonical collection/id/locale/version crosses to the plugin, unsaved field values never leave the browser, and responses are validated through the existing Block Kit/action validators. The tests exercise both the unit boundary and end-to-end browser behavior in RTL.
No further findings — this looks ready to land.
What does this PR do?
Adds saved-entry panels and actions for sandboxed plugins, stacked on the safe Block Kit navigation and locale work in #3174.
admin.editorPanelsandadmin.editorActionsdeclarations across the CLI schema, wire manifest, npm descriptor, configured and runtime-installed plugin paths, marketplace validation, and admin manifest.routeCtx.ui. Unsaved field values never cross the sandbox boundary.createPluginRuntimeTestHost()with production-boundary panel and action helpers and updates public docs plus canonical/generated plugin-authoring skills.Related feature discussion: #3004. The discussion's unsaved-draft snapshot and editor-patch proposal remains out of scope; this first release exposes saved identity only and operates on the persisted entry.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
The first screenshot shows the saved-entry action and collapsed plugin panel in the Arabic right-to-left editor. The second shows the same panel expanded after its lazy request, including host-attested saved identity and the explicit notice that unsaved editor changes are not sent to the plugin.
Validation completed at
1797935204c8cc18415cd3d6b6063a55674912df:pnpm buildpnpm typecheckpnpm lintpnpm lint:quickpnpm lint:json | jq '.diagnostics | length'(0)pnpm formatpnpm --dir docs build(85 pages)pnpm changeset status --since=origin/mainThe mandatory independent adversarial review found stale loaded panels and two marketplace/core schema parity failures. Those were fixed with regression coverage and re-reviewed at the current head; the final review reports no bugs.