fix(admin): implement mountEarly() so plugin-registered routes see adminContext/auth - #4
Merged
Merged
Conversation
…minContext/auth Third-party-plugin-guarded-route bug: a plugin's own mount()-registered route could never see ctx.state.adminContext or ctx.state.auth, no matter how the request was authenticated, because this plugin always mounts last (bootstrap() can't construct it until authz/hmac-key/history are ready) and Fresh 2 snapshots each route's middleware chain at registration time. Implements the new DunePlugin.mountEarly() hook (@dune/core@0.34.4): mountDuneAdminEarly() registers just the ctx.state.adminContext and admin-auth middleware early, guarded against double-registration (WeakSet, mirrors the existing registerPluginPublicRoutes() pattern) so headless-mode direct callers of mountDuneAdmin() are unaffected. The AdminContext object itself is still built inside mount() (unchanged, too large/risky to restructure here) — mountEarly()'s middleware reads it through a lazily-resolved getter that starts returning the real value once mount() finishes building it, well before the app can serve a request. Also discovered while writing the regression test: a plugin's guarded route must be registered under the admin path prefix (e.g. /admin/my-plugin/...) — the admin auth middleware that sets ctx.state.auth only runs for requests under that prefix. Documented in duneorg/dune-docs#4. Requires @dune/core@^0.34.4 or later. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…unePlugin.mountEarly() Same class of bug as the 3.0.0 publish failure: PR #4's own deno.json edit bumped @dune/core to ^0.34.4 by hand without updating this generator's CORE_RANGE constant to match, so CI's check:core-imports correctly caught the mismatch. Confirmed the fix with a real isolated deno publish --dry-run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A third-party plugin's own
mount()-registered route could never seectx.state.adminContextorctx.state.auth, no matter how the request was authenticated —withGuards()always treated it as unauthenticated.Root cause
This plugin's own
mount()always runs last (bootstrap()in@dune/corecan't construct it until authz, the HMAC key, and the history engine are ready — well after every site-configured plugin already registered). Fresh 2 snapshots each route's middleware chain at the moment the route is registered, so any other plugin's own route was compiled before this plugin'sctx.state.adminContext = …and admin-auth middleware existed at all.Fix
Implements the new
DunePlugin.mountEarly()hook from duneorg/dune#17:mountDuneAdminEarly()registers just the two pieces of middleware other plugins' routes depend on —ctx.state.adminContextand the admin auth middleware (ctx.state.auth) — before any plugin'smount()runs.The
AdminContextobject itself is still built insidemount(), unchanged — restructuring where it's built was out of scope and too risky for this fix.mountEarly()'s middleware reads it through a lazily-resolved getter closure that starts returning the real value oncemount()finishes building it, well before the app can actually serve a request. Both new middleware registrations are guarded against double-registration (WeakSet, mirrors the existingregisterPluginPublicRoutes()pattern in@dune/core) so headless-mode direct callers ofmountDuneAdmin()— who never callmountEarly()— are unaffected.Also discovered
A plugin's own guarded route must be registered under the admin path prefix (e.g.
/admin/my-plugin/…) — the admin auth middleware that setsctx.state.authonly runs for requests under that prefix, same as every built-in admin route. Documented inadmin/guards.ts's example and in duneorg/dune-docs#4.Requires
@dune/core@^0.34.4(fix(plugins): add mountEarly() so third-party plugins can use admin-guarded routes dune#17) — bumped in this PR'sdeno.json.Testing
tests/admin/mount_early_test.ts— verified it fails (bothsawAdminContext/sawAuthfalse, and a TS2724 against pre-fixmount.tsfor the missing export) without the fix, passes with it.deno test -A— 233 passed, 0 failed.deno lint src/anddeno checkclean.🤖 Generated with Claude Code