Skip to content

release 4.0.0: the admin as a plugin for core 0.36 (the whole stack, #12-#25, #19, #23) - #26

Merged
zumbrunn merged 41 commits into
mainfrom
release/4.0.0
Nov 10, 2026
Merged

zumbrunn merged 41 commits into
mainfrom
release/4.0.0

Conversation

@zumbrunn

Copy link
Copy Markdown
Member

Lands the whole 4.0 stack as one change, as for @dune/testing: its intermediate commits were written against intermediate core APIs and only the top type-checks against @dune/core 0.36. Contains #12-#17, #19, #21, #23, #24 and #25, plus the release housekeeping (version 4.0.0, CORE_RANGE 0.36, dated changelog, @dune/testing in the age-gate exclude, the staging-publish test adapted to the plugin being listed and to actor on page events).

Verified against the published @dune/core 0.36.0 and @dune/testing 2.0.0: deno task check clean, 305 tests pass, check:core-imports up to date, deno publish --dry-run succeeds.

🤖 Generated with Claude Code

zumbrunn and others added 30 commits November 4, 2026 10:10
The admin: block, audit.log_file, content.allow_tsx_format and the LDAP/SAML
provider config types follow core's snake_case rename. Requires @dune/core 0.36
(the dependency range is bumped when it is published).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
admin.data_dir is removed in core; resolve the directory with resolveDataDir().

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s and passwords (slice 1)

Value imports of @dune/core security/session/user-store/passwords/logger: 21 -> 0.
Errors matched by code; AdminContext carries services.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e 3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Nothing ever wrote search-analytics.jsonl, so it always returned an empty summary.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pabilities (#97, step 4)

Admin no longer fills core's adminContext bag or implements mountEarly:
it declares auth.session and scheduler.executor in setup(), reads inline-edit,
editor.content and admin.pages through MountApi.capabilities, and reads the job
scheduler from BootstrapResult.jobScheduler. mountDuneAdminEarly() is removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ssion checks (#97)

A plugin contributes { method, path, permission?, handler } and the admin
registers it under its prefix; the handler only runs after the admin login, the
CSRF check on non-GET methods and the permission check. Replaces registering
guarded mutation routes in mount() with withGuards(), which stops working now that
the admin no longer mounts first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An entry without a permission is skipped and logged instead of being exposed to
every authenticated admin. The pages mounting moves into mountPluginAdminPages()
so it can be tested.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Restore, staging publish, translate x2, dev apply, reorder (new onPageMove) and
collab auto-save wrote pages and fired nothing. They now share
announcePageEvent(), which fires the hook and the content webhooks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The manifest generator put /api/staging/:path* ahead of
/api/staging/:path*/publish, so publish was unreachable (the upsert handler
ran and 500ed). Same for the page comments routes. Routes with more segments
after a shared wildcard now sort first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… result (#97)

Adds mountAdminPanel() (panel only); mount() no longer re-registers public
plugin routes and form endpoints, which createDuneApp() owns.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
mount() casts app to Fresh's App (the admin uses fsRoutes, layout, route) and
the block editor declares a FreshContext handler. deno task check now also
type-checks mod.ts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s; drop the createSubmissionManager re-export (#97, slice 4)

Core's createDuneApp() owns both registrations (the admin's second call was a
no-op), and the submission store is PluginRuntime.submissions. Lets core stop
exporting registerPluginPublicRoutes, registerFormRoutes and createSubmissionManager.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both authenticate() implementations threw, and mount() refused ldap/saml config
anyway. Custom providers still go through the authProvider plugin option.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…arries it

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…in.runtime_dir

Core moved runtime_dir and max_revisions to system.* because its own history,
job state and analytics use them. The admin takes the resolved value from
services.paths.runtimeDir (webhook logs, email preview, CSRF secret, workflow
and page events). /api/introspect reports pageCacheEnabled: core no longer has
system.cache.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Core stops reading admin.path and learns where the admin is mounted from this
slot. With the admin disabled nothing is provided and core treats /admin as an
ordinary path.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
AuditLogger, the audit types and the DeepL/Google/LibreTranslate translators move
here from @dune/core (the @dune/core/audit and @dune/core/mt entry points are gone).
The admin builds both in setup(); translators take the fetch they use, and the
admin passes services.security.safeFetch so core's SSRF policy still applies.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e site facts it cannot get from PluginApi

createAdminPlugin(opts) no longer takes config and storage (they come from PluginApi in setup()),
and the default export is the plugin-loader factory (config, { root, dev }) so
plugins: [{ src: jsr:@dune/plugin-admin@^4 }] is enough. admin.enabled is gone (core refuses it:
list the admin to run it). Tests list the admin explicitly; the conformance driver uses the
2.0.0 @dune/testing shape (hostsContributions, prefix from the admin.prefix slot).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…gin config

name dune-admin -> admin, so the settings are config.plugins.admin (the config: of its entry in
plugins:). adminSettings(config) is the one reader; it applies the defaults and refuses a path
or auth_provider that would desync the admin. WebhookEndpointConfig, WebhookContentEvent and
AuthProviderConfig move here from @dune/core, which now has no admin config at all.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Read from config.plugins.admin.machine_translation with api_key / base_url (were apiKey / baseUrl).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Matches @dune/core's rename (duneorg/dune#130): the resource names the site
content being protected, not the panel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…une#125)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
zumbrunn and others added 11 commits November 7, 2026 19:36
…n.routes, admin.editor) (#127)

The registration types leave core's contract and live here; the keys are
declared by declaration merging. editor.content is renamed admin.editor.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…n buttons; webhooks follow page events (duneorg/dune#127)

The source/commit/fields routes moved to @dune/plugin-inline-edit
(/api/inline-edit/content/*), so /admin/api/content/* is gone. The admin now
contributes its own buttons to the bar's `bar.actions` point (edit source in an
overlay, open in admin) instead of the bar hard-coding them.

Content webhooks are a listener on the page events (onPageCreate, onPageUpdate,
onPageDelete, onPageMove, onWorkflowChange), so writes from any writer reach
them, not only admin routes. announcePageEvent names the signed-in user as
`actor`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…127)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ugmentation (duneorg/dune#127)

JSR rejects 'declare module' in a published package.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ublishes

'export default function adminPluginFactory' next to 'adminPluginFactory.pluginName = ...'
is a merged declaration; JSR's type output rejects it (TS2652), so 'deno publish'
failed. Same runtime shape: a function with a pluginName property.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…o the admin (duneorg/dune#139)

A site user holding editor or author is governed by core's system.role_grants; the direct
tuple an earlier version seeded for such an account is revoked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Inline edits and other writers fire the page event with the person as actor; the admin now logs
page.create/update/delete for them. Events its own routes announce are marked and skipped.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…HEAD

# Conflicts:
#	src/admin/manifest.gen.ts
CORE_RANGE and the deno.json import go to 0.36 (bare minor, floors JSR's publish
check at 0.36.0), the version is 4.0.0, the 4.0.0 changelog entry is dated,
@dune/testing joins @dune/core in the dependency-age exclude list, and the
staging-publish test installs the admin plugin explicitly and expects the
`actor` that page events now carry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.

1 participant