Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
662b81f
feat(admin)!: read snake_case config keys (duneorg/dune#96)
zumbrunn Nov 4, 2026
f2fc830
feat(admin)!: data directory comes from system.data_dir only
zumbrunn Nov 4, 2026
0264a5e
feat(admin)!: use core's plugin services for security, sessions, user…
zumbrunn Nov 4, 2026
b4c75c7
feat(admin)!: use core's engines and authz seeding (plugin-api slice 2)
zumbrunn Nov 4, 2026
4d34543
feat(admin)!: use core's blueprint and path services (plugin-api slic…
zumbrunn Nov 4, 2026
d3e6cea
feat(admin)!: remove the search analytics route
zumbrunn Nov 5, 2026
3817a4c
feat(admin)!: search analytics route reads core's recorder (slice 3b)
zumbrunn Nov 5, 2026
8e24ba3
feat(admin): analytics summary carries since
zumbrunn Nov 5, 2026
6446ba9
feat(admin)!: provide auth.session and scheduler.executor, consume ca…
zumbrunn Nov 5, 2026
39f335d
feat(admin): mount admin.routes behind authentication, CSRF and permi…
zumbrunn Nov 5, 2026
7e082b1
feat(admin): auth.session declares its session cookie (#97)
zumbrunn Nov 5, 2026
83ad834
feat(admin)!: admin.pages and admin.routes require a permission (#97)
zumbrunn Nov 5, 2026
64b0a27
test(admin): run the admin conformance suite against plugin-admin (#97)
zumbrunn Nov 5, 2026
37eb1d5
fix(admin): every route that writes a page fires its event (#97)
zumbrunn Nov 5, 2026
8044a71
test(admin): conformance driver covers page create and delete (#97)
zumbrunn Nov 5, 2026
b4a95b1
fix(admin): register wildcard sub-routes before the bare wildcard (#18)
zumbrunn Nov 5, 2026
6050ac2
feat(admin)!: mount() reads MountApi.runtime instead of the bootstrap…
zumbrunn Nov 5, 2026
5310522
feat(admin): narrow the contract's PluginApp to Fresh's App (#97)
zumbrunn Nov 5, 2026
5023d56
feat(admin)!: stop registering plugin public routes and form endpoint…
zumbrunn Nov 5, 2026
c8cedbd
feat(admin)!: remove the LDAP and SAML provider stubs (#97)
zumbrunn Nov 5, 2026
11e8860
refactor: drop the unused imageCache field, PluginRuntime no longer c…
zumbrunn Nov 6, 2026
0c06659
feat(admin)!: read the runtime directory from services.paths, not adm…
zumbrunn Nov 6, 2026
462fe1f
feat(admin)!: provide the admin.prefix capability
zumbrunn Nov 6, 2026
fda8ea3
feat(admin)!: own the audit trail and machine translation
zumbrunn Nov 6, 2026
0c40f61
feat(admin)!: the admin is a plugin you list: a factory that takes th…
zumbrunn Nov 6, 2026
09feb45
docs(admin): README and CHANGELOG for explicit loading
zumbrunn Nov 6, 2026
c9079a0
feat(admin)!: the plugin is called admin and its settings are its plu…
zumbrunn Nov 7, 2026
541b28e
feat(admin)!: machine_translation is part of the admin's plugin config
zumbrunn Nov 7, 2026
7225112
fix!: permissions are checked on app:site, not app:admin
zumbrunn Nov 7, 2026
c692e33
chore: use the editor.session and editor.inline slot names (duneorg/d…
zumbrunn Nov 7, 2026
0b494b8
feat!: the admin declares its own extension points (admin.pages, admi…
zumbrunn Nov 7, 2026
6d415e3
feat!: drop the inline-edit content routes; contribute the bar's admi…
zumbrunn Nov 7, 2026
e8fdb44
docs: changelog for the inline-edit HTTP gate and page-event actor (#…
zumbrunn Nov 7, 2026
f98b810
feat!: export extension points as typed capability keys, not module a…
zumbrunn Nov 8, 2026
6f11536
fix: export the plugin factory as a separate default so the package p…
zumbrunn Nov 8, 2026
47be6d7
feat: seed direct editing tuples only for accounts that can sign in t…
zumbrunn Nov 10, 2026
3503c79
test: role_grants {} with the admin installed
zumbrunn Nov 10, 2026
7021708
feat: audit page writes that no admin route announced (duneorg/dune#127)
zumbrunn Nov 10, 2026
b112437
Merge remote-tracking branch 'origin/fix/admin-factory-default-export…
zumbrunn Nov 10, 2026
d866bea
Merge remote-tracking branch 'origin/fix/staging-publish-route' into …
zumbrunn Nov 10, 2026
9f37398
chore: release 4.0.0 (core 0.36)
zumbrunn Nov 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dune/admin/csrf-secret
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e2d70ff6df338be68a3461e97fc83abfe5fa4ff393c4901a90f9d84fa88cabf6
219 changes: 219 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

88 changes: 54 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,77 @@ Optional: `sha256` (ZIP integrity), `demoUrl`, `screenshotUrl`, `tags`, `compati

## Usage

The plugin is auto-registered by `@dune/core` bootstrap unless explicitly disabled. No configuration is required for the default setup.
The admin is a plugin like any other: `@dune/core` loads it only when `config/site.yaml` lists it.
`dune new` writes the entry, and `dune migrate:config` adds it to an existing site.

### Explicit registration (for custom wiring)
```yaml
# config/site.yaml
plugins:
- src: jsr:@dune/plugin-admin@^4
```

No further configuration is required. Settings go under `config:` of that entry:

```yaml
plugins:
- src: jsr:@dune/plugin-admin@^4
config:
path: /cms # URL prefix (default /admin)
session_lifetime: 3600 # seconds (default 86400)
```
A site that does not list it has no admin panel: it serves,
builds and runs jobs as usual, and says once at boot that nothing provides the admin.

### Custom wiring

To pass a custom sign-in provider, build the plugin yourself and hand it to `bootstrap()` instead of
listing it:

```ts
import { createAdminPlugin } from "@dune/plugin-admin";
import { bootstrap } from "@dune/core";

const result = await bootstrap({ root: Deno.cwd() });
// Admin is auto-registered; pass options to override defaults:
const adminPlugin = createAdminPlugin(result.config, result.storage, {
root: Deno.cwd(),
dev: false,
// authProvider: myCustomAuthProvider,
const ctx = await bootstrap(Deno.cwd(), {
plugins: [createAdminPlugin({ root: Deno.cwd(), dev: false, authProvider: myCustomAuthProvider })],
});
```

### Disabling the admin panel

```yaml
# site.yaml
admin:
enabled: false
```
### Running without the admin

This produces a headless Dune deployment — useful for statically generated sites or when you want a fully custom management interface.
Do not list it. (`admin.enabled` no longer exists: core refuses it.) This is a headless Dune deployment,
useful for statically generated sites or when you want a fully custom management interface.

## Configuration

All admin configuration lives under the `admin:` key in `site.yaml`.
The admin's settings are its plugin config: `config:` under its entry in `plugins:` (`config/site.yaml`).
Core reads none of them.

```yaml
admin:
path: /admin # URL prefix for the admin panel (default: /admin)
enabled: true # Set to false to disable entirely
sessionLifetime: 86400 # Session duration in seconds (default: 24h)
dataDir: data # Directory for users, submissions, etc.
runtimeDir: .dune/admin # Directory for sessions, audit log, etc.

auth_provider:
type: local # Only "local" is supported today

audit:
enabled: true
logFile: .dune/admin/audit.log # Override the audit log path

session_store:
type: local # "local" (default) or "redis"
url: $REDIS_URL # Required when type is redis
plugins:
- src: jsr:@dune/plugin-admin@^4
config:
path: /admin # URL prefix for the admin panel (default /admin)
session_lifetime: 86400 # session duration in seconds (default 24h)
max_upload_mb: 100 # admin upload limit (default 100)
git_commit: false # commit to git after each page save (default false)
auth_provider:
type: local # the only supported value; omit for the same result
audit:
enabled: true
log_file: .dune/admin/audit.log # must resolve under the site root
machine_translation: # optional: translate pages from the editor
provider: deepl # deepl | google | libretranslate
api_key: $DEEPL_API_KEY
webhooks: # outbound webhooks on content events
- url: https://hooks.example.com/content
secret: $WEBHOOK_SECRET
events: [onPageUpdate]
```

A `path` that is not a clean prefix, or an `auth_provider` other than `local`, stops the site at boot.
Shared settings live in core's `system.yaml`: `data_dir` (users, submissions), `runtime_dir` (sessions, audit
log, revisions) and `max_revisions`.

### Roles and permissions

The admin panel uses a three-tier role system:
Expand Down
15 changes: 10 additions & 5 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
{
"name": "@dune/plugin-admin",
"version": "3.3.0",
"version": "4.0.0",
"license": "MIT",
"minimumDependencyAge": {
"age": "P1D",
"exclude": [
"jsr:@dune/core"
"jsr:@dune/core",
"jsr:@dune/testing"
]
},
"exports": {
".": "./mod.ts",
"./admin/mount": "./src/admin/mount.ts",
"./admin/context": "./src/admin/context.ts",
"./admin/types": "./src/admin/types.ts",
"./contributions": "./src/admin/contributions.ts",
"./admin/guards": "./src/admin/guards.ts",
"./admin/auth/middleware": "./src/admin/auth/middleware.ts",
"./admin/auth/provider": "./src/admin/auth/provider.ts"
"./admin/auth/provider": "./src/admin/auth/provider.ts",
"./audit": "./src/audit/mod.ts",
"./mt": "./src/mt/mod.ts"
},
"imports": {
"@dune/core": "jsr:@dune/core@^0.35.3",
"@dune/core": "jsr:@dune/core@0.36",
"@dune/testing": "jsr:@dune/testing@^2",
"fresh": "jsr:@fresh/core@^2",
"preact": "npm:preact@^10",
"preact/hooks": "npm:preact@^10/hooks",
Expand All @@ -44,7 +49,7 @@
},
"tasks": {
"test": "deno test -A tests/",
"check": "deno lint src/ && deno check src/**/*.ts src/**/*.tsx",
"check": "deno lint src/ && deno check mod.ts src/**/*.ts src/**/*.tsx",
"test:e2e": "deno run --allow-all --unstable-kv npm:playwright test --config playwright.config.ts",
"test:e2e:install": "deno run --allow-all npm:playwright install chromium",
"gen:admin-manifest": "deno run --allow-read --allow-write scripts/generate-admin-manifest.ts",
Expand Down
Loading
Loading