@adonis-agora/agent-dashboard 0.7.4 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @adonis-agora/agent-dashboard
|
|
2
2
|
|
|
3
|
+
## 0.7.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#90](https://github.com/DavideCarvalho/adonis-agora-agent/pull/90) [`c540ed5`](https://github.com/DavideCarvalho/adonis-agora-agent/commit/c540ed5884d8dc2ad4a22c0f29f9ec9c68ace6be) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Governance console: a refused request now gets a real page instead of `{"error":"forbidden"}`.
|
|
8
|
+
|
|
9
|
+
Opening the console without permission used to answer the browser with JSON. Both providers
|
|
10
|
+
(the embedded `@adonis-agora/agent/dashboard_provider` and the standalone
|
|
11
|
+
`@adonis-agora/agent-dashboard`) now serve a built-in access-denied page in the console's own
|
|
12
|
+
visual language — the status, a sentence explaining the refusal and a "Back to app" link.
|
|
13
|
+
Statuses are unchanged (`401` when no actor resolves, `403` when `authorize` denies), and a
|
|
14
|
+
redirect written by `onUnauthenticated`/`authorize` still wins.
|
|
15
|
+
|
|
16
|
+
The page carries no inline `<script>`, so a nonce'd `script-src` CSP cannot break it; its inline
|
|
17
|
+
`<style>` takes `@adonisjs/shield`'s request nonce when one exists.
|
|
18
|
+
|
|
19
|
+
New `dashboard.accessDenied` option on `config/agent.ts` to customise it — an object (`brand`,
|
|
20
|
+
`title`, `message`, `homeHref`, `accent`, labels) to tweak the built-in page, or a function
|
|
21
|
+
`(info, ctx) => html | void` to render it yourself or redirect. `@adonis-agora/agent/dashboard`
|
|
22
|
+
exports the shared `answerDashboardDenial` + `renderAccessDeniedPage`.
|
|
23
|
+
|
|
3
24
|
## 0.7.4
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -38,7 +38,9 @@ export default class AgentDashboardProvider {
|
|
|
38
38
|
* Resolve the actor through the agent config's resolver, mirroring the governance routes, then run
|
|
39
39
|
* the optional `authorize` gate. Returns `true` to proceed; replies `401` on a missing/failed
|
|
40
40
|
* resolver and `403` when `authorize` denies the resolved actor. The decision itself lives in the
|
|
41
|
-
* router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response
|
|
41
|
+
* router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response
|
|
42
|
+
* — the access-denied PAGE (a browser is what hits these routes), via the shared
|
|
43
|
+
* {@link answerDashboardDenial}, which also stands down when `authorize` already redirected.
|
|
42
44
|
*/
|
|
43
45
|
private gate;
|
|
44
46
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IAC7B,SAAS,CAAC,GAAG,EAAE,kBAAkB;IAA7C,YAAsB,GAAG,EAAE,kBAAkB,EAAI;IAEjD,+FAA+F;IAC/F,OAAO,CAAC,SAAS,CAAuC;IAElD,IAAI,kBAyDT;IAED;;;;;;;OAOG;YACW,IAAI;IAclB;;;OAGG;YACW,SAAS;IAOvB,4FAA4F;YAC9E,SAAS;CAmBxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { apiBaseFor, contentTypeFor, decideDashboardMount, evaluateDashboardGate, injectApiBase, injectBaseHref, mountPathFor, resolveDashboardConfig, safeAssetSegments, } from '@adonis-agora/agent/dashboard';
|
|
2
|
+
import { answerDashboardDenial, apiBaseFor, contentTypeFor, decideDashboardMount, evaluateDashboardGate, injectApiBase, injectBaseHref, mountPathFor, resolveDashboardConfig, safeAssetSegments, } from '@adonis-agora/agent/dashboard';
|
|
3
3
|
/**
|
|
4
4
|
* Serves the `@adonis-agora/agent-dashboard` governance SPA (a Vite build in `dist/spa`) as static
|
|
5
5
|
* assets under `<agentPath>/dashboard`, behind the SAME actor gating as the agent's governance
|
|
@@ -58,20 +58,25 @@ export default class AgentDashboardProvider {
|
|
|
58
58
|
const mount = mountPathFor(agentPath, dashboardConfig.path);
|
|
59
59
|
const actorResolver = agentConfig.actorResolver;
|
|
60
60
|
const authorize = dashboardConfig.authorize;
|
|
61
|
+
// What a refused browser sees — the built-in access-denied page unless the host customised it.
|
|
62
|
+
const denial = {
|
|
63
|
+
basePath: mount,
|
|
64
|
+
accessDenied: dashboardConfig.accessDenied,
|
|
65
|
+
};
|
|
61
66
|
// The SPA shell, served at the bare mount. We do NOT redirect to a trailing-slash variant: the
|
|
62
67
|
// AdonisJS router normalizes trailing slashes, so `mount` and `${mount}/` are the SAME route
|
|
63
68
|
// pattern — registering both throws "Duplicate route". Instead `sendIndex` injects a
|
|
64
69
|
// `<base href="${mount}/">`, so the SPA's relative `./assets/*` URLs resolve against the mount
|
|
65
70
|
// directory regardless of whether the browser's URL carries a trailing slash.
|
|
66
71
|
router.get(mount, async (ctx) => {
|
|
67
|
-
if (!(await this.gate(ctx, actorResolver, authorize)))
|
|
72
|
+
if (!(await this.gate(ctx, actorResolver, authorize, denial)))
|
|
68
73
|
return;
|
|
69
74
|
await this.sendIndex(ctx, apiBase, mount);
|
|
70
75
|
});
|
|
71
76
|
// Built assets (JS/CSS/fonts/...), with an index fallback for any unmatched path so the
|
|
72
77
|
// client-rendered console still boots on a deep link.
|
|
73
78
|
router.get(`${mount}/*`, async (ctx) => {
|
|
74
|
-
if (!(await this.gate(ctx, actorResolver, authorize)))
|
|
79
|
+
if (!(await this.gate(ctx, actorResolver, authorize, denial)))
|
|
75
80
|
return;
|
|
76
81
|
const segments = safeAssetSegments(ctx.params['*']);
|
|
77
82
|
if (segments === null) {
|
|
@@ -84,12 +89,14 @@ export default class AgentDashboardProvider {
|
|
|
84
89
|
* Resolve the actor through the agent config's resolver, mirroring the governance routes, then run
|
|
85
90
|
* the optional `authorize` gate. Returns `true` to proceed; replies `401` on a missing/failed
|
|
86
91
|
* resolver and `403` when `authorize` denies the resolved actor. The decision itself lives in the
|
|
87
|
-
* router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response
|
|
92
|
+
* router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response
|
|
93
|
+
* — the access-denied PAGE (a browser is what hits these routes), via the shared
|
|
94
|
+
* {@link answerDashboardDenial}, which also stands down when `authorize` already redirected.
|
|
88
95
|
*/
|
|
89
|
-
async gate(ctx, actorResolver, authorize) {
|
|
96
|
+
async gate(ctx, actorResolver, authorize, denial) {
|
|
90
97
|
const verdict = await evaluateDashboardGate(ctx, actorResolver, authorize);
|
|
91
98
|
if (!verdict.ok) {
|
|
92
|
-
ctx
|
|
99
|
+
await answerDashboardDenial(ctx, verdict, denial);
|
|
93
100
|
return false;
|
|
94
101
|
}
|
|
95
102
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAGL,UAAU,EACV,cAAc,
|
|
1
|
+
{"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/agent-dashboard",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "Read-only governance console (spend by model/actor, usage trend, recent threads & tool calls, quota) for @adonis-agora/agent — a dependency-light React SPA served by a thin AdonisJS provider. Part of the Agora ecosystem.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
],
|
|
38
38
|
"sideEffects": false,
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@adonis-agora/agent": ">=0.
|
|
40
|
+
"@adonis-agora/agent": ">=0.26.0 <1.0.0",
|
|
41
41
|
"@adonisjs/core": "^7.3.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependenciesMeta": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@adonis-agora/agent": "0.
|
|
49
|
+
"@adonis-agora/agent": "0.26.0",
|
|
50
50
|
"@adonisjs/core": "7.5.0",
|
|
51
51
|
"@tanstack/intent": "^0.3.7",
|
|
52
52
|
"@testing-library/react": "16.3.3",
|