@adonis-agora/agent-dashboard 0.2.2 → 0.3.1

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,47 @@
1
1
  # @adonis-agora/agent-dashboard
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#12](https://github.com/DavideCarvalho/adonis-agent/pull/12) [`4021b6b`](https://github.com/DavideCarvalho/adonis-agent/commit/4021b6b5355ec7679f44f035a2c1dfafeb3c5e61) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Fix the dashboard provider crashing every app boot (and a duplicate-route crash)
8
+
9
+ Two bugs that made the provider unbootable in a real app — surfaced the first time
10
+ it was registered in one (entre-textos):
11
+
12
+ - **`router` was `undefined` at boot.** The provider imported `router` from
13
+ `@adonisjs/core/services/router` and called `router.get(...)` in `boot()`. That
14
+ service's default export is only assigned inside an `app.booted()` hook, which
15
+ runs AFTER every provider's `boot()`, so it was still `undefined` — `router.get`
16
+ threw `Cannot read properties of undefined (reading 'get')` and crashed the whole
17
+ app. It now resolves the router from the container (`app.container.make('router')`),
18
+ available during boot, mirroring how the agent provider registers its routes.
19
+
20
+ - **Duplicate `GET <mount>` route.** The provider registered a bare-mount redirect
21
+ (`<mount>` → `<mount>/`) plus the shell at `<mount>/`. The AdonisJS router
22
+ normalizes trailing slashes, so both are the SAME pattern — the second
23
+ registration threw `Duplicate route found`. The shell now serves at the bare
24
+ `<mount>` (one route), and `sendIndex` injects a `<base href="<mount>/">` so the
25
+ SPA's relative `./assets/*` URLs (Vite `base: './'`) still resolve against the
26
+ mount directory regardless of the URL's trailing slash.
27
+
28
+ ## 0.3.0
29
+
30
+ ### Minor Changes
31
+
32
+ - [#10](https://github.com/DavideCarvalho/adonis-agent/pull/10) [`c2ddde3`](https://github.com/DavideCarvalho/adonis-agent/commit/c2ddde3d4fdb5f87f3c49984c5cbbe145fbd1038) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Add an optional `authorize` gate to the dashboard config
33
+
34
+ The console serves the governance read-model, which spans EVERY actor's spend and
35
+ usage — so authenticating the caller (the default gate, shared with
36
+ `/agent/governance/*`) is often not enough; you want to restrict it to admins.
37
+
38
+ `config('agent').dashboard.authorize` is an optional `(actor, ctx) => boolean |
39
+ Promise<boolean>` run after the actor resolves. Return `false` (or throw) to deny
40
+ — the request gets `403`. Omit it to keep the previous behavior (any resolved
41
+ actor allowed). Typical use: `authorize: (actor) => actor.roles?.includes('ADMIN')
42
+ ?? false`. The gate decision lives in a router-free `evaluateDashboardGate` helper
43
+ so it is unit tested directly.
44
+
3
45
  ## 0.2.2
4
46
 
5
47
  ### Patch Changes
@@ -21,11 +21,16 @@ export default class AgentDashboardProvider {
21
21
  private spaDirUrl;
22
22
  boot(): Promise<void>;
23
23
  /**
24
- * Resolve the actor through the agent config's resolver, mirroring the governance routes. Returns
25
- * `true` to proceed; on a missing/failed resolver replies `401` and returns `false`.
24
+ * Resolve the actor through the agent config's resolver, mirroring the governance routes, then run
25
+ * the optional `authorize` gate. Returns `true` to proceed; replies `401` on a missing/failed
26
+ * resolver and `403` when `authorize` denies the resolved actor. The decision itself lives in the
27
+ * router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response.
26
28
  */
27
29
  private gate;
28
- /** Read `dist/spa/index.html`, inject the API base, and send it. */
30
+ /**
31
+ * Read `dist/spa/index.html`, inject the `<base href>` (so relative `./assets/*` resolve against
32
+ * the mount dir) and the API base, and send it.
33
+ */
29
34
  private sendIndex;
30
35
  /** Send the requested built asset, or fall back to the SPA shell when it does not exist. */
31
36
  private sendAsset;
@@ -1 +1 @@
1
- {"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAU/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IAC7B,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,+FAA+F;IAC/F,OAAO,CAAC,SAAS,CAAuC;IAElD,IAAI;IAkCV;;;OAGG;YACW,IAAI;IAgBlB,oEAAoE;YACtD,SAAS;IAOvB,4FAA4F;YAC9E,SAAS;CAcxB"}
1
+ {"version":3,"file":"agent_dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAgB/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IAC7B,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,+FAA+F;IAC/F,OAAO,CAAC,SAAS,CAAuC;IAElD,IAAI;IA0CV;;;;;OAKG;YACW,IAAI;IAalB;;;OAGG;YACW,SAAS;IAOvB,4FAA4F;YAC9E,SAAS;CAmBxB"}
@@ -1,7 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import router from '@adonisjs/core/services/router';
3
- import { resolveDashboardConfig } from '../src/server/define_config.js';
4
- import { apiBaseFor, contentTypeFor, injectApiBase, mountPathFor, safeAssetSegments, } from '../src/server/paths.js';
2
+ import { resolveDashboardConfig, } from '../src/server/define_config.js';
3
+ import { evaluateDashboardGate } from '../src/server/gate.js';
4
+ import { apiBaseFor, contentTypeFor, injectApiBase, injectBaseHref, mountPathFor, safeAssetSegments, } from '../src/server/paths.js';
5
5
  /**
6
6
  * Serves the `@adonis-agora/agent-dashboard` governance SPA (a Vite build in `dist/spa`) as static
7
7
  * assets under `<agentPath>/dashboard`, behind the SAME actor gating as the agent's governance
@@ -29,60 +29,64 @@ export default class AgentDashboardProvider {
29
29
  const dashboardConfig = resolveDashboardConfig(this.app.config.get('agent.dashboard', {}));
30
30
  if (!dashboardConfig.enabled)
31
31
  return;
32
+ // Resolve the router from the container, NOT from `@adonisjs/core/services/router`: that service's
33
+ // default export is assigned inside an `app.booted()` hook, which runs AFTER every provider's
34
+ // `boot()` — so at this point the module default is still `undefined` and `router.get(...)` throws.
35
+ // The container binding is available now (mirrors how the agent provider registers its routes).
36
+ const router = await this.app.container.make('router');
32
37
  const agentPath = agentConfig.path ?? 'agent';
33
38
  const apiBase = apiBaseFor(agentPath);
34
39
  const mount = mountPathFor(agentPath, dashboardConfig.path);
35
40
  const actorResolver = agentConfig.actorResolver;
36
- // Bare mount → canonical trailing slash so the SPA's relative `./assets/*` URLs resolve against
37
- // the mount directory rather than its parent.
38
- router.get(mount, (ctx) => ctx.response.redirect().toPath(`${mount}/`));
39
- // The SPA shell.
40
- router.get(`${mount}/`, async (ctx) => {
41
- if (!(await this.gate(ctx, actorResolver)))
41
+ const authorize = dashboardConfig.authorize;
42
+ // The SPA shell, served at the bare mount. We do NOT redirect to a trailing-slash variant: the
43
+ // AdonisJS router normalizes trailing slashes, so `mount` and `${mount}/` are the SAME route
44
+ // pattern — registering both throws "Duplicate route". Instead `sendIndex` injects a
45
+ // `<base href="${mount}/">`, so the SPA's relative `./assets/*` URLs resolve against the mount
46
+ // directory regardless of whether the browser's URL carries a trailing slash.
47
+ router.get(mount, async (ctx) => {
48
+ if (!(await this.gate(ctx, actorResolver, authorize)))
42
49
  return;
43
- await this.sendIndex(ctx, apiBase);
50
+ await this.sendIndex(ctx, apiBase, mount);
44
51
  });
45
52
  // Built assets (JS/CSS/fonts/...), with an index fallback for any unmatched path so the
46
53
  // client-rendered console still boots on a deep link.
47
54
  router.get(`${mount}/*`, async (ctx) => {
48
- if (!(await this.gate(ctx, actorResolver)))
55
+ if (!(await this.gate(ctx, actorResolver, authorize)))
49
56
  return;
50
57
  const segments = safeAssetSegments(ctx.params['*']);
51
58
  if (segments === null) {
52
59
  return ctx.response.status(400).json({ error: 'bad asset path' });
53
60
  }
54
- await this.sendAsset(ctx, segments, apiBase);
61
+ await this.sendAsset(ctx, segments, apiBase, mount);
55
62
  });
56
63
  }
57
64
  /**
58
- * Resolve the actor through the agent config's resolver, mirroring the governance routes. Returns
59
- * `true` to proceed; on a missing/failed resolver replies `401` and returns `false`.
65
+ * Resolve the actor through the agent config's resolver, mirroring the governance routes, then run
66
+ * the optional `authorize` gate. Returns `true` to proceed; replies `401` on a missing/failed
67
+ * resolver and `403` when `authorize` denies the resolved actor. The decision itself lives in the
68
+ * router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response.
60
69
  */
61
- async gate(ctx, actorResolver) {
62
- if (actorResolver === undefined) {
63
- ctx.response.status(401).json({ error: 'no actor resolver configured' });
64
- return false;
65
- }
66
- try {
67
- await actorResolver.resolve(ctx);
68
- return true;
69
- }
70
- catch (error) {
71
- ctx.response
72
- .status(401)
73
- .json({ error: error instanceof Error ? error.message : 'unauthorized' });
70
+ async gate(ctx, actorResolver, authorize) {
71
+ const verdict = await evaluateDashboardGate(ctx, actorResolver, authorize);
72
+ if (!verdict.ok) {
73
+ ctx.response.status(verdict.status).json({ error: verdict.error });
74
74
  return false;
75
75
  }
76
+ return true;
76
77
  }
77
- /** Read `dist/spa/index.html`, inject the API base, and send it. */
78
- async sendIndex(ctx, apiBase) {
78
+ /**
79
+ * Read `dist/spa/index.html`, inject the `<base href>` (so relative `./assets/*` resolve against
80
+ * the mount dir) and the API base, and send it.
81
+ */
82
+ async sendIndex(ctx, apiBase, mount) {
79
83
  const html = await readFile(new URL('index.html', this.spaDirUrl), 'utf8');
80
84
  ctx.response.header('content-type', 'text/html; charset=utf-8');
81
85
  ctx.response.header('cache-control', 'no-store, must-revalidate');
82
- ctx.response.send(injectApiBase(html, apiBase));
86
+ ctx.response.send(injectApiBase(injectBaseHref(html, mount), apiBase));
83
87
  }
84
88
  /** Send the requested built asset, or fall back to the SPA shell when it does not exist. */
85
- async sendAsset(ctx, segments, apiBase) {
89
+ async sendAsset(ctx, segments, apiBase, mount) {
86
90
  const filename = segments[segments.length - 1] ?? 'index.html';
87
91
  try {
88
92
  const buffer = await readFile(new URL(segments.join('/'), this.spaDirUrl));
@@ -91,7 +95,7 @@ export default class AgentDashboardProvider {
91
95
  }
92
96
  catch (error) {
93
97
  if (error.code === 'ENOENT') {
94
- await this.sendIndex(ctx, apiBase);
98
+ await this.sendIndex(ctx, apiBase, mount);
95
99
  return;
96
100
  }
97
101
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent_dashboard_provider.js","sourceRoot":"","sources":["../../providers/agent_dashboard_provider.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,32 @@
1
+ import type { Actor } from '@adonis-agora/agent';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
+ /**
4
+ * An extra authorization gate for the dashboard, run AFTER the agent config's `actorResolver` has
5
+ * resolved the caller. Return `false` (or throw) to deny — the request gets `403`. The governance
6
+ * read-model the SPA serves spans EVERY actor's spend/usage, so most apps restrict the console beyond
7
+ * mere authentication, e.g. `(actor) => actor.roles?.includes('ADMIN') ?? false`.
8
+ */
9
+ export type AgentDashboardAuthorize = (actor: Actor, ctx: HttpContext) => boolean | Promise<boolean>;
1
10
  /**
2
11
  * Optional `config('agent').dashboard` block. The dashboard reuses the agent config's `path` and
3
- * `actorResolver` (so it sits behind the SAME actor gating as the governance routes); this block only
4
- * toggles it on/off and optionally overrides the mount path.
12
+ * `actorResolver` (so it sits behind the SAME actor gating as the governance routes); this block
13
+ * toggles it on/off, optionally overrides the mount path, and optionally adds an `authorize` gate.
5
14
  */
6
15
  export interface AgentDashboardConfig {
7
16
  /** Mount the SPA. Default `true` — set `false` to keep the routes off entirely. */
8
17
  enabled?: boolean;
9
18
  /** Override the mount path. Default `<agentPath>/dashboard`. */
10
19
  path?: string;
20
+ /**
21
+ * Extra authorization run after the actor resolves. Return `false` to deny (`403`). Omit to allow
22
+ * any resolved actor (the default), matching the `/agent/governance/*` routes' gating.
23
+ */
24
+ authorize?: AgentDashboardAuthorize;
11
25
  }
12
26
  export interface ResolvedAgentDashboardConfig {
13
27
  enabled: boolean;
14
28
  path?: string;
29
+ authorize?: AgentDashboardAuthorize;
15
30
  }
16
31
  /** Fill defaults for the optional dashboard config block. */
17
32
  export declare function resolveDashboardConfig(config: AgentDashboardConfig | undefined): ResolvedAgentDashboardConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,4BAA4B,CAG9B"}
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,WAAW,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,4BAA4B,CAK9B"}
@@ -1,6 +1,10 @@
1
1
  /** Fill defaults for the optional dashboard config block. */
2
2
  export function resolveDashboardConfig(config) {
3
- const enabled = config?.enabled ?? true;
4
- return config?.path !== undefined ? { enabled, path: config.path } : { enabled };
3
+ const resolved = { enabled: config?.enabled ?? true };
4
+ if (config?.path !== undefined)
5
+ resolved.path = config.path;
6
+ if (config?.authorize !== undefined)
7
+ resolved.authorize = config.authorize;
8
+ return resolved;
5
9
  }
6
10
  //# sourceMappingURL=define_config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAiBA,6DAA6D;AAC7D,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC;IACxC,OAAO,MAAM,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;AACnF,CAAC"}
1
+ {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/server/define_config.ts"],"names":[],"mappings":"AAqCA,6DAA6D;AAC7D,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,QAAQ,GAAiC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACpF,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC5D,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC3E,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { ActorResolver } from '@adonis-agora/agent';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
+ import type { AgentDashboardAuthorize } from './define_config.js';
4
+ /** The outcome of the dashboard access gate: proceed, or deny with an HTTP status + message. */
5
+ export type DashboardGateVerdict = {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ status: 401 | 403;
10
+ error: string;
11
+ };
12
+ /**
13
+ * Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
14
+ * testable free of the AdonisJS router/app. Mirrors the `/agent/governance/*` gating: resolve the
15
+ * actor through the agent config's resolver (missing/failed → `401`), then run the optional
16
+ * `authorize` gate over the resolved actor (denied/threw → `403`). No resolver and no `authorize`
17
+ * means the SPA is exposed to any request — the caller (the provider) is expected to short-circuit on
18
+ * a missing resolver via the `401` here.
19
+ */
20
+ export declare function evaluateDashboardGate(ctx: HttpContext, actorResolver: ActorResolver | undefined, authorize?: AgentDashboardAuthorize): Promise<DashboardGateVerdict>;
21
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,SAAS,CAAC,EAAE,uBAAuB,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Decide whether a request may reach the dashboard, WITHOUT touching the response — so it is unit
3
+ * testable free of the AdonisJS router/app. Mirrors the `/agent/governance/*` gating: resolve the
4
+ * actor through the agent config's resolver (missing/failed → `401`), then run the optional
5
+ * `authorize` gate over the resolved actor (denied/threw → `403`). No resolver and no `authorize`
6
+ * means the SPA is exposed to any request — the caller (the provider) is expected to short-circuit on
7
+ * a missing resolver via the `401` here.
8
+ */
9
+ export async function evaluateDashboardGate(ctx, actorResolver, authorize) {
10
+ if (actorResolver === undefined) {
11
+ return { ok: false, status: 401, error: 'no actor resolver configured' };
12
+ }
13
+ let actor;
14
+ try {
15
+ actor = await actorResolver.resolve(ctx);
16
+ }
17
+ catch (error) {
18
+ return {
19
+ ok: false,
20
+ status: 401,
21
+ error: error instanceof Error ? error.message : 'unauthorized',
22
+ };
23
+ }
24
+ if (authorize !== undefined) {
25
+ try {
26
+ if (!(await authorize(actor, ctx))) {
27
+ return { ok: false, status: 403, error: 'forbidden' };
28
+ }
29
+ }
30
+ catch (error) {
31
+ return {
32
+ ok: false,
33
+ status: 403,
34
+ error: error instanceof Error ? error.message : 'forbidden',
35
+ };
36
+ }
37
+ }
38
+ return { ok: true };
39
+ }
40
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/server/gate.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAgB,EAChB,aAAwC,EACxC,SAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,KAAoD,CAAC;IACzD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc;SAC/D,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
@@ -24,4 +24,12 @@ export declare function safeAssetSegments(wildcard: string | string[] | undefine
24
24
  * per response — inserted right before `</head>`.
25
25
  */
26
26
  export declare function injectApiBase(html: string, apiBase: string): string;
27
+ /**
28
+ * Inject a `<base href="${mount}/">` as the FIRST thing inside `<head>`, so the SPA's relative
29
+ * `./assets/*` URLs (Vite `base: './'`) resolve against the mount directory no matter whether the
30
+ * browser's URL carries a trailing slash. This replaces the old trailing-slash redirect, which the
31
+ * AdonisJS router (it normalizes trailing slashes) turned into a duplicate-route crash. `mount` is a
32
+ * leading-slash, no-trailing-slash path (e.g. `/agent/dashboard`).
33
+ */
34
+ export declare function injectBaseHref(html: string, mount: string): string;
27
35
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/server/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAM9E;AAsBD,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,CAU1F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAInE"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/server/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAM9E;AAsBD,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,CAU1F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAInE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQlE"}
@@ -75,4 +75,20 @@ export function injectApiBase(html, apiBase) {
75
75
  return html.replace('</head>', `${tag}</head>`);
76
76
  return `${tag}${html}`;
77
77
  }
78
+ /**
79
+ * Inject a `<base href="${mount}/">` as the FIRST thing inside `<head>`, so the SPA's relative
80
+ * `./assets/*` URLs (Vite `base: './'`) resolve against the mount directory no matter whether the
81
+ * browser's URL carries a trailing slash. This replaces the old trailing-slash redirect, which the
82
+ * AdonisJS router (it normalizes trailing slashes) turned into a duplicate-route crash. `mount` is a
83
+ * leading-slash, no-trailing-slash path (e.g. `/agent/dashboard`).
84
+ */
85
+ export function injectBaseHref(html, mount) {
86
+ const tag = `<base href="${mount}/">`;
87
+ const headOpen = html.match(/<head[^>]*>/i);
88
+ if (headOpen?.index !== undefined) {
89
+ const at = headOpen.index + headOpen[0].length;
90
+ return html.slice(0, at) + tag + html.slice(at);
91
+ }
92
+ return `${tag}${html}`;
93
+ }
78
94
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/server/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/server/paths.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.2.2",
3
+ "version": "0.3.1",
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": {
@@ -57,7 +57,7 @@
57
57
  "typescript": "^5.4.0",
58
58
  "vite": "^7.0.0",
59
59
  "vitest": "^3.0.0",
60
- "@adonis-agora/agent": "0.4.0"
60
+ "@adonis-agora/agent": "0.4.1"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22.0.0"