@adonis-agora/agent 0.20.0 → 0.21.0

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.
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>agent · governance console</title>
7
+ <script type="module" crossorigin src="./assets/index-CkOAJYbh.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-BYLm0nq8.css">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ </body>
13
+ </html>
@@ -3,16 +3,21 @@ import type Configure from '@adonisjs/core/commands/configure';
3
3
  * `node ace configure @adonis-agora/agent` — auto-wires the package:
4
4
  *
5
5
  * 1. registers the agent service provider in `adonisrc.ts`;
6
- * 2. registers the Assembler `init` hook that generates the typed `app/agent_tools` barrel at
6
+ * 2. registers the embedded dashboard provider — the governance console SPA, bundled into this
7
+ * package's own `dist/` (`@adonis-agora/agent-dashboard`'s build output, copied in at build time),
8
+ * served with no separate install. Toggle/relocate it with the optional `config('agent').dashboard`
9
+ * block (see `config/agent.ts`); it mounts only once `governanceAuthorize` is configured — see the
10
+ * provider's own doc comment for why;
11
+ * 3. registers the Assembler `init` hook that generates the typed `app/agent_tools` barrel at
7
12
  * build/dev time (the provider imports it instead of scanning at runtime; it falls back to the
8
13
  * runtime scan when the barrel is absent);
9
- * 3. publishes `config/agent.ts`;
10
- * 4. publishes `config/mcp.ts` (the MCP endpoint config; the MCP provider is separate);
11
- * 5. publishes the Lucid migration for the five agent tables (run `node ace migration:run`; delete it
14
+ * 4. publishes `config/agent.ts`;
15
+ * 5. publishes `config/mcp.ts` (the MCP endpoint config; the MCP provider is separate);
16
+ * 6. publishes the Lucid migration for the five agent tables (run `node ace migration:run`; delete it
12
17
  * if you only use the in-memory store);
13
- * 6. publishes the additive run-tracking migration (`agent_run` table + `run_id` columns) — run it
18
+ * 7. publishes the additive run-tracking migration (`agent_run` table + `run_id` columns) — run it
14
19
  * after the base migration; delete it with the base one if you only use the in-memory store;
15
- * 7. publishes the pgvector migration for the RAG chunk table (Postgres + pgvector only; delete it
20
+ * 8. publishes the pgvector migration for the RAG chunk table (Postgres + pgvector only; delete it
16
21
  * unless you use `retrievers.pgvector({...})`).
17
22
  */
18
23
  export declare function configure(command: Configure): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,mCAAmC,CAAC;AAG/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,SAAS,iBAcjD"}
1
+ {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,mCAAmC,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,SAAS,iBAejD"}
package/dist/configure.js CHANGED
@@ -3,22 +3,28 @@ import { stubsRoot } from './stubs/main.js';
3
3
  * `node ace configure @adonis-agora/agent` — auto-wires the package:
4
4
  *
5
5
  * 1. registers the agent service provider in `adonisrc.ts`;
6
- * 2. registers the Assembler `init` hook that generates the typed `app/agent_tools` barrel at
6
+ * 2. registers the embedded dashboard provider — the governance console SPA, bundled into this
7
+ * package's own `dist/` (`@adonis-agora/agent-dashboard`'s build output, copied in at build time),
8
+ * served with no separate install. Toggle/relocate it with the optional `config('agent').dashboard`
9
+ * block (see `config/agent.ts`); it mounts only once `governanceAuthorize` is configured — see the
10
+ * provider's own doc comment for why;
11
+ * 3. registers the Assembler `init` hook that generates the typed `app/agent_tools` barrel at
7
12
  * build/dev time (the provider imports it instead of scanning at runtime; it falls back to the
8
13
  * runtime scan when the barrel is absent);
9
- * 3. publishes `config/agent.ts`;
10
- * 4. publishes `config/mcp.ts` (the MCP endpoint config; the MCP provider is separate);
11
- * 5. publishes the Lucid migration for the five agent tables (run `node ace migration:run`; delete it
14
+ * 4. publishes `config/agent.ts`;
15
+ * 5. publishes `config/mcp.ts` (the MCP endpoint config; the MCP provider is separate);
16
+ * 6. publishes the Lucid migration for the five agent tables (run `node ace migration:run`; delete it
12
17
  * if you only use the in-memory store);
13
- * 6. publishes the additive run-tracking migration (`agent_run` table + `run_id` columns) — run it
18
+ * 7. publishes the additive run-tracking migration (`agent_run` table + `run_id` columns) — run it
14
19
  * after the base migration; delete it with the base one if you only use the in-memory store;
15
- * 7. publishes the pgvector migration for the RAG chunk table (Postgres + pgvector only; delete it
20
+ * 8. publishes the pgvector migration for the RAG chunk table (Postgres + pgvector only; delete it
16
21
  * unless you use `retrievers.pgvector({...})`).
17
22
  */
18
23
  export async function configure(command) {
19
24
  const codemods = await command.createCodemods();
20
25
  await codemods.updateRcFile((rcFile) => {
21
26
  rcFile.addProvider('@adonis-agora/agent/agent_provider');
27
+ rcFile.addProvider('@adonis-agora/agent/dashboard_provider');
22
28
  // Generate the typed app/agent_tools barrel at build/dev time (replaces the runtime readdir scan).
23
29
  rcFile.addAssemblerHook('init', '@adonis-agora/agent/hooks/tools');
24
30
  });
@@ -1 +1 @@
1
- {"version":3,"file":"configure.js","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAkB;IAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;IAEhD,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;QACzD,mGAAmG;QACnG,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACjE,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;IAC/D,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,8CAA8C,EAAE,EAAE,CAAC,CAAC;IAC5F,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,oDAAoD,EAAE,EAAE,CAAC,CAAC;IAClG,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,kDAAkD,EAAE,EAAE,CAAC,CAAC;AAClG,CAAC"}
1
+ {"version":3,"file":"configure.js","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAkB;IAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;IAEhD,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;QACzD,MAAM,CAAC,WAAW,CAAC,wCAAwC,CAAC,CAAC;QAC7D,mGAAmG;QACnG,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACjE,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;IAC/D,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,8CAA8C,EAAE,EAAE,CAAC,CAAC;IAC5F,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,oDAAoD,EAAE,EAAE,CAAC,CAAC;IAClG,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,kDAAkD,EAAE,EAAE,CAAC,CAAC;AAClG,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
+ /**
3
+ * Serves the `@adonis-agora/agent-dashboard` governance SPA **from this package's own build** — no
4
+ * separate install, no separate provider registration. `node ace configure @adonis-agora/agent`
5
+ * registers this provider alongside `agent_provider`, and the SPA it serves is bundled straight into
6
+ * `@adonis-agora/agent`'s own `dist/` at build time (`package.json`'s `copy:stubs` copies
7
+ * `../dashboard/dist/spa`, the `@adonis-agora/agent-dashboard` package's `vite build` output, into
8
+ * `dist/assets/spa`) — mirrors `@adonis-agora/durable`'s `dashboard_provider.ts` /
9
+ * `src/dashboard/spa.ts` split, which does the identical thing for its own dashboard.
10
+ *
11
+ * The routing/gating logic here is BYTE-FOR-BYTE the same as `@adonis-agora/agent-dashboard`'s own
12
+ * `agent_dashboard_provider.ts` — both call the SAME shared helpers from `../src/dashboard/index.js`
13
+ * (`decideDashboardMount`, `evaluateDashboardGate`, the path/content-type helpers). The two providers
14
+ * differ only in WHERE they read the built `index.html`/assets from: this one reads its own
15
+ * `dist/assets/spa` (copied in at build time); the standalone provider reads
16
+ * `@adonis-agora/agent-dashboard`'s own `dist/spa`.
17
+ *
18
+ * Why the logic lives HERE rather than in `@adonis-agora/agent-dashboard` (which would let this
19
+ * provider stay a one-line re-export): `@adonis-agora/agent-dashboard` already depends on
20
+ * `@adonis-agora/agent` (its provider imports `AgentConfig`/`ActorResolver`), so a dependency the
21
+ * other way — this package depending on the dashboard package's code at runtime — would be circular,
22
+ * and in this monorepo it would ALSO be a real `turbo`/pnpm build cycle (the dashboard package's own
23
+ * build needs `@adonis-agora/agent` built first, to typecheck its provider against it). Keeping the
24
+ * shared logic in `src/dashboard/` (owned by this package) avoids the cycle exactly the way
25
+ * `@adonis-agora/durable` avoids it — by owning its `spa.ts` serving helpers directly rather than
26
+ * depending on `@adonis-agora/durable-dashboard` for anything but the BUILT ASSET FILES (a
27
+ * build-time-only, one-directional filesystem copy in `copy:stubs`, no package.json dependency at
28
+ * all — see that script for how the dashboard's SPA output is located: a plain relative path,
29
+ * `../dashboard/dist/spa`, resolved by directory layout, not by module resolution).
30
+ *
31
+ * `@adonis-agora/agent-dashboard`'s own provider keeps working entirely unchanged for apps that
32
+ * already install and register it directly (e.g. on an older `@adonis-agora/agent` version, or where
33
+ * an app wants the standalone package's independent versioning/release cadence) — this provider is
34
+ * purely additive. An app that registers BOTH providers with the same mount path will hit AdonisJS's
35
+ * "duplicate route" error at boot; pick one (this is the intended migration signal, not a bug).
36
+ *
37
+ * Routes (mount = `<agentPath>/dashboard`, default `/agent/dashboard`) — identical to the standalone
38
+ * provider's:
39
+ * - `GET <mount>` → the SPA shell (`index.html`, with the resolved API base + `<base href>` injected)
40
+ * - `GET <mount>/*` → a built asset, or the SPA shell as a fallback (client-rendered console)
41
+ *
42
+ * Nothing mounts unless the agent config carries a `governanceAuthorize` gate: without it the
43
+ * `/agent/governance/*` routes the console reads do not exist, so the console would load and fail on
44
+ * every panel but Quota. The provider declines and logs why (see `decideDashboardMount`).
45
+ *
46
+ * Enable/disable and override the mount via the optional `config('agent').dashboard` block — the SAME
47
+ * block the standalone provider reads.
48
+ */
49
+ export default class DashboardProvider {
50
+ #private;
51
+ protected app: ApplicationService;
52
+ constructor(app: ApplicationService);
53
+ boot(): Promise<void>;
54
+ }
55
+ //# sourceMappingURL=dashboard_provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard_provider.d.ts","sourceRoot":"","sources":["../../providers/dashboard_provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAiB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAiB;;IACxB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAcvC,IAAI;CAuGX"}
@@ -0,0 +1,152 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve as resolvePath } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { apiBaseFor, contentTypeFor, decideDashboardMount, evaluateDashboardGate, injectApiBase, injectBaseHref, mountPathFor, resolveDashboardConfig, safeAssetSegments, } from '../src/dashboard/index.js';
5
+ /**
6
+ * Serves the `@adonis-agora/agent-dashboard` governance SPA **from this package's own build** — no
7
+ * separate install, no separate provider registration. `node ace configure @adonis-agora/agent`
8
+ * registers this provider alongside `agent_provider`, and the SPA it serves is bundled straight into
9
+ * `@adonis-agora/agent`'s own `dist/` at build time (`package.json`'s `copy:stubs` copies
10
+ * `../dashboard/dist/spa`, the `@adonis-agora/agent-dashboard` package's `vite build` output, into
11
+ * `dist/assets/spa`) — mirrors `@adonis-agora/durable`'s `dashboard_provider.ts` /
12
+ * `src/dashboard/spa.ts` split, which does the identical thing for its own dashboard.
13
+ *
14
+ * The routing/gating logic here is BYTE-FOR-BYTE the same as `@adonis-agora/agent-dashboard`'s own
15
+ * `agent_dashboard_provider.ts` — both call the SAME shared helpers from `../src/dashboard/index.js`
16
+ * (`decideDashboardMount`, `evaluateDashboardGate`, the path/content-type helpers). The two providers
17
+ * differ only in WHERE they read the built `index.html`/assets from: this one reads its own
18
+ * `dist/assets/spa` (copied in at build time); the standalone provider reads
19
+ * `@adonis-agora/agent-dashboard`'s own `dist/spa`.
20
+ *
21
+ * Why the logic lives HERE rather than in `@adonis-agora/agent-dashboard` (which would let this
22
+ * provider stay a one-line re-export): `@adonis-agora/agent-dashboard` already depends on
23
+ * `@adonis-agora/agent` (its provider imports `AgentConfig`/`ActorResolver`), so a dependency the
24
+ * other way — this package depending on the dashboard package's code at runtime — would be circular,
25
+ * and in this monorepo it would ALSO be a real `turbo`/pnpm build cycle (the dashboard package's own
26
+ * build needs `@adonis-agora/agent` built first, to typecheck its provider against it). Keeping the
27
+ * shared logic in `src/dashboard/` (owned by this package) avoids the cycle exactly the way
28
+ * `@adonis-agora/durable` avoids it — by owning its `spa.ts` serving helpers directly rather than
29
+ * depending on `@adonis-agora/durable-dashboard` for anything but the BUILT ASSET FILES (a
30
+ * build-time-only, one-directional filesystem copy in `copy:stubs`, no package.json dependency at
31
+ * all — see that script for how the dashboard's SPA output is located: a plain relative path,
32
+ * `../dashboard/dist/spa`, resolved by directory layout, not by module resolution).
33
+ *
34
+ * `@adonis-agora/agent-dashboard`'s own provider keeps working entirely unchanged for apps that
35
+ * already install and register it directly (e.g. on an older `@adonis-agora/agent` version, or where
36
+ * an app wants the standalone package's independent versioning/release cadence) — this provider is
37
+ * purely additive. An app that registers BOTH providers with the same mount path will hit AdonisJS's
38
+ * "duplicate route" error at boot; pick one (this is the intended migration signal, not a bug).
39
+ *
40
+ * Routes (mount = `<agentPath>/dashboard`, default `/agent/dashboard`) — identical to the standalone
41
+ * provider's:
42
+ * - `GET <mount>` → the SPA shell (`index.html`, with the resolved API base + `<base href>` injected)
43
+ * - `GET <mount>/*` → a built asset, or the SPA shell as a fallback (client-rendered console)
44
+ *
45
+ * Nothing mounts unless the agent config carries a `governanceAuthorize` gate: without it the
46
+ * `/agent/governance/*` routes the console reads do not exist, so the console would load and fail on
47
+ * every panel but Quota. The provider declines and logs why (see `decideDashboardMount`).
48
+ *
49
+ * Enable/disable and override the mount via the optional `config('agent').dashboard` block — the SAME
50
+ * block the standalone provider reads.
51
+ */
52
+ export default class DashboardProvider {
53
+ app;
54
+ constructor(app) {
55
+ this.app = app;
56
+ }
57
+ /**
58
+ * Directory of the built SPA (`dist/assets/spa`, copied in by `copy:stubs` — see `package.json`),
59
+ * relative to this compiled provider (`dist/providers`). Resolved lazily (not at module scope):
60
+ * `fileURLToPath` throws on any non-`file:` `import.meta.url`, which would make this provider
61
+ * unimportable under a test runner that doesn't use real file URLs.
62
+ */
63
+ #spaDir;
64
+ #spaDirectory() {
65
+ this.#spaDir ??= fileURLToPath(new URL('../assets/spa/', import.meta.url));
66
+ return this.#spaDir;
67
+ }
68
+ async boot() {
69
+ const agentConfig = this.app.config.get('agent', {});
70
+ const dashboardConfig = resolveDashboardConfig(this.app.config.get('agent.dashboard', {}));
71
+ // Mount only when the console can actually work: every panel but Quota reads the agent's
72
+ // cross-actor `/agent/governance/*` routes, and those do not exist without a `governanceAuthorize`
73
+ // gate. Refusing here — loudly — beats serving a shell that 404s its own data with no explanation.
74
+ const decision = decideDashboardMount(dashboardConfig.enabled, agentConfig.governanceAuthorize, agentConfig.governanceQueries);
75
+ if (!decision.mount) {
76
+ if (decision.reason !== 'disabled')
77
+ console.warn(decision.warning);
78
+ return;
79
+ }
80
+ // Resolve the router from the container, NOT from `@adonisjs/core/services/router`: that service's
81
+ // default export is assigned inside an `app.booted()` hook, which runs AFTER every provider's
82
+ // `boot()` — so at this point the module default is still `undefined` and `router.get(...)` throws.
83
+ const router = await this.app.container.make('router');
84
+ const agentPath = agentConfig.path ?? 'agent';
85
+ const apiBase = apiBaseFor(agentPath);
86
+ const mount = mountPathFor(agentPath, dashboardConfig.path);
87
+ const actorResolver = agentConfig.actorResolver;
88
+ const authorize = dashboardConfig.authorize;
89
+ // The SPA shell, served at the bare mount. We do NOT redirect to a trailing-slash variant: the
90
+ // AdonisJS router normalizes trailing slashes, so `mount` and `${mount}/` are the SAME route
91
+ // pattern — registering both throws "Duplicate route". Instead `sendIndex` injects a
92
+ // `<base href="${mount}/">`, so the SPA's relative `./assets/*` URLs resolve against the mount
93
+ // directory regardless of whether the browser's URL carries a trailing slash.
94
+ router.get(mount, async (ctx) => {
95
+ if (!(await this.#gate(ctx, actorResolver, authorize)))
96
+ return;
97
+ await this.#sendIndex(ctx, apiBase, mount);
98
+ });
99
+ // Built assets (JS/CSS/fonts/...), with an index fallback for any unmatched path so the
100
+ // client-rendered console still boots on a deep link.
101
+ router.get(`${mount}/*`, async (ctx) => {
102
+ if (!(await this.#gate(ctx, actorResolver, authorize)))
103
+ return;
104
+ const segments = safeAssetSegments(ctx.params['*']);
105
+ if (segments === null) {
106
+ return ctx.response.status(400).json({ error: 'bad asset path' });
107
+ }
108
+ await this.#sendAsset(ctx, segments, apiBase, mount);
109
+ });
110
+ }
111
+ /**
112
+ * Resolve the actor through the agent config's resolver, mirroring the governance routes, then run
113
+ * the optional `authorize` gate. Returns `true` to proceed; replies `401` on a missing/failed
114
+ * resolver and `403` when `authorize` denies the resolved actor. The decision itself lives in the
115
+ * router-free {@link evaluateDashboardGate} so it can be unit tested; this only writes the response.
116
+ */
117
+ async #gate(ctx, actorResolver, authorize) {
118
+ const verdict = await evaluateDashboardGate(ctx, actorResolver, authorize);
119
+ if (!verdict.ok) {
120
+ ctx.response.status(verdict.status).json({ error: verdict.error });
121
+ return false;
122
+ }
123
+ return true;
124
+ }
125
+ /**
126
+ * Read `dist/assets/spa/index.html`, inject the `<base href>` (so relative `./assets/*` resolve
127
+ * against the mount dir) and the API base, and send it.
128
+ */
129
+ async #sendIndex(ctx, apiBase, mount) {
130
+ const html = await readFile(resolvePath(this.#spaDirectory(), 'index.html'), 'utf8');
131
+ ctx.response.header('content-type', 'text/html; charset=utf-8');
132
+ ctx.response.header('cache-control', 'no-store, must-revalidate');
133
+ ctx.response.send(injectApiBase(injectBaseHref(html, mount), apiBase));
134
+ }
135
+ /** Send the requested built asset, or fall back to the SPA shell when it does not exist. */
136
+ async #sendAsset(ctx, segments, apiBase, mount) {
137
+ const filename = segments[segments.length - 1] ?? 'index.html';
138
+ try {
139
+ const buffer = await readFile(resolvePath(this.#spaDirectory(), ...segments));
140
+ ctx.response.header('content-type', contentTypeFor(filename));
141
+ ctx.response.send(buffer);
142
+ }
143
+ catch (error) {
144
+ if (error.code === 'ENOENT') {
145
+ await this.#sendIndex(ctx, apiBase, mount);
146
+ return;
147
+ }
148
+ throw error;
149
+ }
150
+ }
151
+ }
152
+ //# sourceMappingURL=dashboard_provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard_provider.js","sourceRoot":"","sources":["../../providers/dashboard_provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { AgentGovernanceAuthorize } from '../governance-gate.js';
3
+ import type { Actor } from '../types.js';
4
+ /**
5
+ * An extra authorization gate for the dashboard, run AFTER the agent config's `actorResolver` has
6
+ * resolved the caller. Return `false` (or throw) to deny — the request gets `403`. The governance
7
+ * read-model the SPA serves spans EVERY actor's spend/usage, so most apps restrict the console beyond
8
+ * mere authentication, e.g. `(actor) => actor.roles?.includes('ADMIN') ?? false`.
9
+ */
10
+ export type AgentDashboardAuthorize = (actor: Actor, ctx: HttpContext) => boolean | Promise<boolean>;
11
+ /**
12
+ * Optional `config('agent').dashboard` block. The dashboard reuses the agent config's `path` and
13
+ * `actorResolver` (so it sits behind the SAME actor gating as the governance routes); this block
14
+ * toggles it on/off, optionally overrides the mount path, and optionally adds an `authorize` gate.
15
+ *
16
+ * Shared by BOTH the embedded dashboard provider (`@adonis-agora/agent/dashboard_provider`, wired
17
+ * automatically when you `node ace configure @adonis-agora/agent`) and the standalone
18
+ * `@adonis-agora/agent-dashboard` package's provider — one config block controls whichever one is
19
+ * registered.
20
+ */
21
+ export interface AgentDashboardConfig {
22
+ /**
23
+ * Mount the SPA. Default `true` — set `false` to keep the routes off entirely. Note `true` is
24
+ * necessary but not sufficient: the console also needs the agent's `governanceAuthorize` gate, see
25
+ * {@link decideDashboardMount}.
26
+ */
27
+ enabled?: boolean;
28
+ /** Override the mount path. Default `<agentPath>/dashboard`. */
29
+ path?: string;
30
+ /**
31
+ * Extra authorization run after the actor resolves. Return `false` to deny (`403`). Omit to allow
32
+ * any resolved actor (the default) — note this is only an EXTRA gate on the SPA shell; whether the
33
+ * console mounts at all, and whether its data is readable, is decided by the agent config's
34
+ * `governanceAuthorize`.
35
+ */
36
+ authorize?: AgentDashboardAuthorize;
37
+ }
38
+ export interface ResolvedAgentDashboardConfig {
39
+ enabled: boolean;
40
+ path?: string;
41
+ authorize?: AgentDashboardAuthorize;
42
+ }
43
+ /** Fill defaults for the optional dashboard config block. */
44
+ export declare function resolveDashboardConfig(config: AgentDashboardConfig | undefined): ResolvedAgentDashboardConfig;
45
+ /** Whether the provider registers the console's routes, and (when it refuses) what to say about it. */
46
+ export type DashboardMountDecision = {
47
+ mount: true;
48
+ } | {
49
+ mount: false;
50
+ reason: 'disabled';
51
+ } | {
52
+ mount: false;
53
+ reason: 'no-governance-gate';
54
+ warning: string;
55
+ } | {
56
+ mount: false;
57
+ reason: 'no-governance-queries';
58
+ warning: string;
59
+ };
60
+ /**
61
+ * Decide whether to register the console's routes at all — the router-free core of the provider's
62
+ * mount check, extracted so it can be unit tested without booting an app.
63
+ *
64
+ * The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
65
+ * those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
66
+ * a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
67
+ * dead panels at click time with nothing anywhere explaining why. So the console follows the same
68
+ * fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
69
+ *
70
+ * This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
71
+ * every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
72
+ * not the data, and an app can set it and still have a console with nothing to render.
73
+ */
74
+ export declare function decideDashboardMount(enabled: boolean, governanceAuthorize: AgentGovernanceAuthorize | undefined, governanceQueries?: unknown): DashboardMountDecision;
75
+ //# sourceMappingURL=define_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,WAAW,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;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;AAED,uGAAuG;AACvG,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoBvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,mBAAmB,EAAE,wBAAwB,GAAG,SAAS,EACzD,iBAAiB,CAAC,EAAE,OAAO,GAC1B,sBAAsB,CAgBxB"}
@@ -0,0 +1,56 @@
1
+ /** Fill defaults for the optional dashboard config block. */
2
+ export function resolveDashboardConfig(config) {
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;
9
+ }
10
+ /**
11
+ * The exact wording the provider logs when it declines to mount. Mirrors the agent provider's own
12
+ * governance boot warning — same three facts, same vocabulary — so a reader who sees one recognises
13
+ * the other.
14
+ */
15
+ const NO_GOVERNANCE_GATE_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: every panel but Quota reads the cross-actor `/agent/governance/*` routes, and those are themselves not mounted because no `governanceAuthorize` gate is configured — so the console would load and then fail on every panel. Set `governanceAuthorize` in config/agent.ts (e.g. an ADMIN check) to mount the routes and this console gated, or `governanceAuthorize: () => true` to deliberately restore the old behaviour of letting ANY authenticated actor read them. `GET /agent/approvals/mine` is unaffected — it stays mounted and scoped to the calling actor. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
16
+ /**
17
+ * The wording logged when the read-model itself was turned off. Deliberately distinct from
18
+ * {@link NO_GOVERNANCE_GATE_WARNING}: both produce the same dead console, and an operator staring at
19
+ * a 404 must be able to tell from the log ALONE which of the two knobs is responsible. A shared
20
+ * "governance is not configured" message would recreate exactly the diagnosability problem this
21
+ * check exists to remove.
22
+ */
23
+ const NO_GOVERNANCE_QUERIES_WARNING = '[@adonis-agora/agent-dashboard] the governance console was NOT mounted: `governanceQueries` is set to `false` in config/agent.ts, so the cross-actor read-model was never built and the `/agent/governance/*` routes it serves do not exist — the console would load and then fail on every panel but Quota. A `governanceAuthorize` gate is NOT the missing piece here; it is already configured. Remove `governanceQueries: false` (omit it to get the Lucid read-model when the main store is Lucid, or pass a store/factory explicitly) to mount the read-model and this console. To keep the console off on purpose and silence this, set `dashboard: { enabled: false }`.';
24
+ /**
25
+ * Decide whether to register the console's routes at all — the router-free core of the provider's
26
+ * mount check, extracted so it can be unit tested without booting an app.
27
+ *
28
+ * The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and
29
+ * those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving
30
+ * a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven
31
+ * dead panels at click time with nothing anywhere explaining why. So the console follows the same
32
+ * fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot.
33
+ *
34
+ * This costs nothing that still works: every app affected is an app whose console is ALREADY dead in
35
+ * every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell,
36
+ * not the data, and an app can set it and still have a console with nothing to render.
37
+ */
38
+ export function decideDashboardMount(enabled, governanceAuthorize, governanceQueries) {
39
+ if (!enabled)
40
+ return { mount: false, reason: 'disabled' };
41
+ if (governanceAuthorize === undefined) {
42
+ return { mount: false, reason: 'no-governance-gate', warning: NO_GOVERNANCE_GATE_WARNING };
43
+ }
44
+ // ONLY an explicit `false` is decidable here. `undefined` does NOT mean "no read-model": the agent
45
+ // provider's `#resolveGovernance` defaults it to the Lucid read-model whenever the main store is
46
+ // Lucid, and reproducing that resolution would duplicate provider logic in the dashboard.
47
+ if (governanceQueries === false) {
48
+ return {
49
+ mount: false,
50
+ reason: 'no-governance-queries',
51
+ warning: NO_GOVERNANCE_QUERIES_WARNING,
52
+ };
53
+ }
54
+ return { mount: true };
55
+ }
56
+ //# sourceMappingURL=define_config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AAiDA,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;AASD;;;;GAIG;AACH,MAAM,0BAA0B,GAC9B,0sBAA0sB,CAAC;AAE7sB;;;;;;GAMG;AACH,MAAM,6BAA6B,GACjC,ipBAAipB,CAAC;AAEppB;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,mBAAyD,EACzD,iBAA2B;IAE3B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1D,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;IAC7F,CAAC;IACD,mGAAmG;IACnG,iGAAiG;IACjG,0FAA0F;IAC1F,IAAI,iBAAiB,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,uBAAuB;YAC/B,OAAO,EAAE,6BAA6B;SACvC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { ActorResolver } from '../spi/actor-resolver.js';
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: resolve the actor through the agent config's resolver
15
+ * (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
16
+ * (denied/threw → `403`).
17
+ *
18
+ * This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
19
+ * is readable, and it is no longer the last line of defence it once had to be:
20
+ *
21
+ * - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
22
+ * routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
23
+ * `governanceQueries` read-model exists. So this function never runs for a console that could only
24
+ * 404 its own panels.
25
+ * - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
26
+ * `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
27
+ * the shell open to any resolved actor but exposes no cross-actor data.
28
+ *
29
+ * Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
30
+ * expected to short-circuit on a missing resolver via the `401` here.
31
+ */
32
+ export declare function evaluateDashboardGate(ctx: HttpContext, actorResolver: ActorResolver | undefined, authorize?: AgentDashboardAuthorize): Promise<DashboardGateVerdict>;
33
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/dashboard/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,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;;;;;;;;;;;;;;;;;;;GAmBG;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,52 @@
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: resolve the actor through the agent config's resolver
4
+ * (missing/failed → `401`), then run the optional `authorize` gate over the resolved actor
5
+ * (denied/threw → `403`).
6
+ *
7
+ * This gates the SPA **shell**, and only the shell. It is NOT what decides whether the console's data
8
+ * is readable, and it is no longer the last line of defence it once had to be:
9
+ *
10
+ * - Whether the console mounts at all is decided earlier, by {@link decideDashboardMount} — the
11
+ * routes are not registered unless the agent config carries a `governanceAuthorize` gate AND its
12
+ * `governanceQueries` read-model exists. So this function never runs for a console that could only
13
+ * 404 its own panels.
14
+ * - Whether the DATA is readable is decided by the agent's own `governanceAuthorize` on the
15
+ * `/agent/governance/*` routes, not here. Omitting `authorize` while a gate is configured leaves
16
+ * the shell open to any resolved actor but exposes no cross-actor data.
17
+ *
18
+ * Omitting BOTH the resolver and `authorize` would expose the shell to any request; the provider is
19
+ * expected to short-circuit on a missing resolver via the `401` here.
20
+ */
21
+ export async function evaluateDashboardGate(ctx, actorResolver, authorize) {
22
+ if (actorResolver === undefined) {
23
+ return { ok: false, status: 401, error: 'no actor resolver configured' };
24
+ }
25
+ let actor;
26
+ try {
27
+ actor = await actorResolver.resolve(ctx);
28
+ }
29
+ catch (error) {
30
+ return {
31
+ ok: false,
32
+ status: 401,
33
+ error: error instanceof Error ? error.message : 'unauthorized',
34
+ };
35
+ }
36
+ if (authorize !== undefined) {
37
+ try {
38
+ if (!(await authorize(actor, ctx))) {
39
+ return { ok: false, status: 403, error: 'forbidden' };
40
+ }
41
+ }
42
+ catch (error) {
43
+ return {
44
+ ok: false,
45
+ status: 403,
46
+ error: error instanceof Error ? error.message : 'forbidden',
47
+ };
48
+ }
49
+ }
50
+ return { ok: true };
51
+ }
52
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/dashboard/gate.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Serving helpers for the `@adonis-agora/agent-dashboard` governance SPA — the config shape, the
3
+ * mount/gate decisions, and the pure path/asset helpers. Framework-light (no AdonisJS router/app
4
+ * dependency), so they're unit-testable in isolation and reusable by BOTH dashboard providers:
5
+ *
6
+ * - `@adonis-agora/agent/dashboard_provider` (this package, `providers/dashboard_provider.ts`) —
7
+ * embedded: registered automatically by `node ace configure @adonis-agora/agent`, serves the SPA
8
+ * bundle copied into THIS package's own `dist/assets/spa` at build time.
9
+ * - `@adonis-agora/agent-dashboard`'s own provider (`agent_dashboard_provider.ts`) — standalone: an
10
+ * independently installable/registrable package some apps already depend on directly.
11
+ *
12
+ * Living here (rather than in `@adonis-agora/agent-dashboard`) keeps the dependency direction
13
+ * one-way: the dashboard package already depends on this one for `AgentConfig`/`ActorResolver`/etc.,
14
+ * so a package.json edge back from here to there would be circular. See
15
+ * `providers/dashboard_provider.ts`'s module doc for the full story.
16
+ */
17
+ export { type AgentDashboardAuthorize, type AgentDashboardConfig, type DashboardMountDecision, type ResolvedAgentDashboardConfig, decideDashboardMount, resolveDashboardConfig, } from './define_config.js';
18
+ export { type DashboardGateVerdict, evaluateDashboardGate } from './gate.js';
19
+ export { apiBaseFor, contentTypeFor, injectApiBase, injectBaseHref, mountPathFor, safeAssetSegments, trimSlashes, } from './paths.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,WAAW,GACZ,MAAM,YAAY,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Serving helpers for the `@adonis-agora/agent-dashboard` governance SPA — the config shape, the
3
+ * mount/gate decisions, and the pure path/asset helpers. Framework-light (no AdonisJS router/app
4
+ * dependency), so they're unit-testable in isolation and reusable by BOTH dashboard providers:
5
+ *
6
+ * - `@adonis-agora/agent/dashboard_provider` (this package, `providers/dashboard_provider.ts`) —
7
+ * embedded: registered automatically by `node ace configure @adonis-agora/agent`, serves the SPA
8
+ * bundle copied into THIS package's own `dist/assets/spa` at build time.
9
+ * - `@adonis-agora/agent-dashboard`'s own provider (`agent_dashboard_provider.ts`) — standalone: an
10
+ * independently installable/registrable package some apps already depend on directly.
11
+ *
12
+ * Living here (rather than in `@adonis-agora/agent-dashboard`) keeps the dependency direction
13
+ * one-way: the dashboard package already depends on this one for `AgentConfig`/`ActorResolver`/etc.,
14
+ * so a package.json edge back from here to there would be circular. See
15
+ * `providers/dashboard_provider.ts`'s module doc for the full story.
16
+ */
17
+ export { decideDashboardMount, resolveDashboardConfig, } from './define_config.js';
18
+ export { evaluateDashboardGate } from './gate.js';
19
+ export { apiBaseFor, contentTypeFor, injectApiBase, injectBaseHref, mountPathFor, safeAssetSegments, trimSlashes, } from './paths.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAKL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA6B,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,WAAW,GACZ,MAAM,YAAY,CAAC"}