@dudousxd/nestjs-agent-dashboard 0.17.0 → 0.19.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.
Files changed (36) hide show
  1. package/README.md +28 -132
  2. package/dist/client/agent-client.d.ts +47 -1
  3. package/dist/client/agent-client.d.ts.map +1 -1
  4. package/dist/client/agent-client.js +0 -4
  5. package/dist/client/agent-client.js.map +1 -1
  6. package/dist/server/index.cjs +286 -1373
  7. package/dist/server/index.cjs.map +1 -1
  8. package/dist/server/index.d.cts +37 -287
  9. package/dist/server/index.d.ts +37 -287
  10. package/dist/server/index.js +239 -1323
  11. package/dist/server/index.js.map +1 -1
  12. package/dist/spa/assets/index-B1znMy6W.css +1 -0
  13. package/dist/spa/assets/{index-DKPuTuEx.js → index-DzukxAmy.js} +1 -1
  14. package/dist/spa/assets/index-eW1zMwDF.js +25 -0
  15. package/dist/spa/assets/{preview-BgeSHiwH.js → preview-Ch59R-LE.js} +1 -1
  16. package/dist/spa/index.html +3 -3
  17. package/dist/spa/preview.html +3 -3
  18. package/package.json +6 -20
  19. package/dist/client/console-session.d.ts +0 -63
  20. package/dist/client/console-session.d.ts.map +0 -1
  21. package/dist/client/console-session.js +0 -107
  22. package/dist/client/console-session.js.map +0 -1
  23. package/dist/react/index.d.ts +0 -4
  24. package/dist/react/index.d.ts.map +0 -1
  25. package/dist/react/index.js +0 -14
  26. package/dist/react/index.js.map +0 -1
  27. package/dist/react/open-console-button.d.ts +0 -26
  28. package/dist/react/open-console-button.d.ts.map +0 -1
  29. package/dist/react/open-console-button.js +0 -29
  30. package/dist/react/open-console-button.js.map +0 -1
  31. package/dist/react/use-open-console.d.ts +0 -34
  32. package/dist/react/use-open-console.d.ts.map +0 -1
  33. package/dist/react/use-open-console.js +0 -70
  34. package/dist/react/use-open-console.js.map +0 -1
  35. package/dist/spa/assets/index-B2rAzTPe.js +0 -25
  36. package/dist/spa/assets/index-P6B28Wyx.css +0 -1
@@ -1,7 +1,7 @@
1
- import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ThreadActivityRow, ToolStatRow, GenuiStats, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
1
+ import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, FeatureSpendRow, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ThreadActivityRow, ToolStatRow, GenuiStats, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
2
2
  export { ActorDirectory } from '@dudousxd/nestjs-agent-core';
3
3
  import { Observable } from 'rxjs';
4
- import { DynamicModule, Type, CanActivate, Provider, InjectionToken, OptionalFactoryDependency, StreamableFile } from '@nestjs/common';
4
+ import { DynamicModule, StreamableFile } from '@nestjs/common';
5
5
 
6
6
  /** An actor-scoped row decorated with its resolved display label — `null` when unbound or unresolved. */
7
7
  interface WithActorLabel {
@@ -27,6 +27,11 @@ interface SpendOverview {
27
27
  byModel: ModelSpendRow[];
28
28
  byActor: ActorSpendRowWithLabel[];
29
29
  trend: UsageTrendPoint[];
30
+ /**
31
+ * Spend per feature — agent turns and usage recorded outside them side by side. Absent when the
32
+ * bound governance adapter has no `spendByFeature`.
33
+ */
34
+ byFeature?: FeatureSpendRow[];
30
35
  }
31
36
  /** The run-reliability overview the SPA renders on its Reliability section (`GET <api>/reliability`). */
32
37
  interface ReliabilityOverview {
@@ -146,9 +151,8 @@ declare class DashboardService {
146
151
  * JSON + SSE API consumed by the AI-gateway console SPA. Mounted at `apiBasePath` (set by
147
152
  * `RouterModule` in {@link AgentDashboardModule.forRoot}), so the controller routes are relative.
148
153
  *
149
- * `@UseGuards(DashboardAuthGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
150
- * that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
151
- * this baseline by `stampGuards` (`./guards.js`), never replacing it.
154
+ * Who reaches it is the app's: `decorators` on `AgentDashboardModule.forRoot`, or the app mounts it
155
+ * itself (`routes: false`) — with `@nestjs/authentication` / `@nestjs/authorization`.
152
156
  */
153
157
  declare class AgentApiController {
154
158
  private readonly dashboard;
@@ -258,185 +262,6 @@ declare class AgentApiController {
258
262
  }>;
259
263
  }
260
264
 
261
- /** The session user the host's `login` hook returns to mint a cookie. */
262
- interface DashboardSessionUser {
263
- id: string;
264
- name?: string;
265
- roles?: string[];
266
- }
267
-
268
- /**
269
- * Host hook for Mode A: validates the host's own auth on the raw request POSTed to
270
- * `<basePath>/auth/session`. Return the session user to grant access, or `null` to deny.
271
- */
272
- type SessionHook = (request: unknown) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
273
- /** Host hook for Mode B: validates submitted credentials for the built-in login screen. */
274
- type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
275
- /**
276
- * Re-checks a LIVE session when the cookie is slid forward. Runs at most once per `ttl/2` PER
277
- * COOKIE GENERATION — the gate is on the inbound cookie's `iat`, so every request still carrying a
278
- * not-yet-renewed cookie would, on its own, invoke this hook again; `maybeRenewSession` de-dupes
279
- * concurrent calls for the same session (`sub` + `iat`) into a single in-flight call, so a page
280
- * load that fires N parallel API calls still costs exactly ONE host round-trip, not N. Still not a
281
- * per-session-lifetime cap — this can run again every `ttl/2` as the session keeps sliding, so a
282
- * slow or expensive check should still debounce/cache across renewal windows on its own. Return
283
- * `false` to revoke (the cookie is cleared and the request denied). Distinct from `session`: that
284
- * hook reads the host's auth off a fresh request, which a console XHR does not carry — this one
285
- * receives the already-minted session.
286
- */
287
- type RevalidateHook = (session: DashboardSessionUser) => Promise<boolean> | boolean;
288
- /** What `unauthenticatedPage` receives. An object (not positional args) so fields can be added later. */
289
- interface UnauthenticatedPageContext {
290
- /**
291
- * The platform-native request — Express' `Request`, Fastify's `FastifyRequest`. Typed `unknown`
292
- * for the same reason `SessionHook`'s is: this package refuses to depend on either platform.
293
- * Cast it to whatever your app actually runs on.
294
- */
295
- request: unknown;
296
- /**
297
- * The platform-native response. The hook OWNS it: it must write AND end it (`res.render(...)`,
298
- * `res.status(401).send(...)`, an Inertia render, ...). If the hook returns without writing, the
299
- * library falls back to its own built-in page rather than leaving the request hanging.
300
- */
301
- response: unknown;
302
- /** Where this console is mounted (e.g. `/ai-gateway`) — useful for a "back to the console" link. */
303
- basePath: string;
304
- }
305
- /**
306
- * Host-owned page for an unauthenticated navigation to the console.
307
- *
308
- * The built-in page cannot know who hosts the console, so it can only say "open this console from
309
- * your application" in the abstract — it can't name the launcher, link to it, or look like the rest
310
- * of the host's product. This hook hands the whole response to the host instead: render through
311
- * your own template engine, your own Inertia page, whatever.
312
- *
313
- * Served at `<basePath>/auth/session-required`, which is where `DashboardAuthPageGuard` already
314
- * redirects a denied Mode-A navigation today — this hook changes what that page CONTAINS, not the
315
- * flow that reaches it.
316
- *
317
- * Deliberately NOT a replacement for Mode B's built-in login form. A host that wants its own login
318
- * UI uses Mode A plus this hook, and posts to `<basePath>/auth/session` from its own page — the
319
- * mint endpoint is the supported primitive for that.
320
- *
321
- * Fail-closed by construction: it only ever runs on a request that has ALREADY been denied. A hook
322
- * that throws, or that returns without writing, falls back to the built-in page — it cannot let
323
- * anyone in.
324
- */
325
- type UnauthenticatedPageHook = (context: UnauthenticatedPageContext) => void | Promise<void>;
326
- /** Which `dashboardAuth` hook(s) a resolved config was given — see `resolveDashboardAuth`. */
327
- type AuthMode = 'session' | 'login';
328
- /**
329
- * Author-facing `dashboardAuth` option (see `AgentDashboardOptions.dashboardAuth`). Gates the
330
- * console (SPA + API) behind a signed session cookie. Two ways to mint that cookie: Mode A
331
- * (`session`) — the host frontend, already carrying its own auth, POSTs to
332
- * `<basePath>/auth/session` and the host hook decides — or Mode B (`login`) — the built-in,
333
- * dependency-free server-rendered login screen. Mirrors `@dudousxd/nestjs-telescope`'s
334
- * `dashboardAuth` two-mode shape. At least one of the two is required so an un-mintable gate is a
335
- * boot error, not a silently-open (or silently-stuck) console.
336
- */
337
- interface DashboardAuthOptions {
338
- /** REQUIRED HMAC-SHA256 signing key (32+ bytes recommended). Missing/empty => boot error (fail closed). */
339
- secret: string;
340
- /** Cookie TTL (duration string `'<n><ms|s|m|h|d>'`, e.g. `'30m'`, `'7d'`). Default `'8h'`. */
341
- ttl?: string;
342
- /**
343
- * Mode A: validates the host's own auth on the raw request POSTed to `<basePath>/auth/session`.
344
- * Return the session user to grant access, or `null` to deny. No credential reaches this
345
- * library — the host decides from whatever it already has (a header, an SSO cookie, ...).
346
- */
347
- session?: SessionHook;
348
- /**
349
- * Mode B: validates submitted username/password. Return the session user to grant access, or
350
- * `null` to deny — the login endpoint responds identically (generic failure) for an unknown user
351
- * and a wrong password, so it never reveals which one was wrong.
352
- */
353
- login?: LoginHook;
354
- /** Re-checks a live session on sliding renewal; see `RevalidateHook`. Not a mode — it cannot
355
- * mint a session, only revoke one already minted by `session`/`login`. */
356
- revalidate?: RevalidateHook;
357
- /** Renders the host's own page for an unauthenticated navigation, in place of the built-in
358
- * "open this console from your application" card; see `UnauthenticatedPageHook`. */
359
- unauthenticatedPage?: UnauthenticatedPageHook;
360
- }
361
- /** Resolved, validated `dashboardAuth` config used by the guards/controller. */
362
- interface ResolvedDashboardAuth {
363
- secret: string;
364
- ttlMs: number;
365
- modes: AuthMode[];
366
- session?: SessionHook;
367
- login?: LoginHook;
368
- revalidate?: RevalidateHook;
369
- unauthenticatedPage?: UnauthenticatedPageHook;
370
- }
371
- /**
372
- * Validate + resolve `dashboardAuth`. Returns `null` when unconfigured (behavior unchanged — the
373
- * console stays open, front it with your own `guards`). Throws at boot (fail closed) when
374
- * configured but missing a secret, when neither `session` nor `login` is given, or when a given
375
- * hook isn't a function — the host learns immediately rather than shipping an open, stuck, or
376
- * un-mintable console.
377
- */
378
- declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
379
-
380
- /** The slice of the platform request this controller reads — structural, no Express/Fastify dependency. */
381
- interface AuthPageRequest {
382
- headers: Record<string, string | string[] | undefined>;
383
- }
384
- /** The slice of the platform response this controller writes (passthrough mode — Nest still sends). */
385
- interface AuthPageResponse {
386
- status(code: number): unknown;
387
- setHeader(name: string, value: string): unknown;
388
- }
389
- interface LoginFormBody {
390
- username?: unknown;
391
- password?: unknown;
392
- returnTo?: unknown;
393
- }
394
- /**
395
- * Mounted directly on `AgentDashboardModule` at `<basePath>/auth/*` — a SEPARATE controller from
396
- * `AgentUiController`/`AgentApiController` so it carries neither `DashboardAuthPageGuard`,
397
- * `DashboardAuthGuard`, nor any host `guards`: these routes MINT (and clear) the session cookie the
398
- * built-in gates check for, so they can never be made to require the very auth they grant. Mirrors
399
- * `@dudousxd/nestjs-telescope`'s own auth controller staying outside its `stampGuards` call.
400
- *
401
- * Two ways to mint that cookie, matching `resolveDashboardAuth`'s modes: Mode A (`session`) — the
402
- * host frontend, already carrying its own auth, POSTs to `<basePath>/auth/session` and the host
403
- * hook decides — or Mode B (`login`), a dependency-free, server-rendered login form (GET/POST) —
404
- * the bundled React SPA in this package is a built Vite artifact with no auth-aware UI of its own,
405
- * so gating the actual page navigation needs a self-contained flow that doesn't touch it. Each
406
- * mode's routes 404 when that mode isn't listed in `auth.modes` — the single source of truth for
407
- * which mode(s) are configured, not hook-presence truthiness — and every route 404s outright when
408
- * `dashboardAuth` is unconfigured (`DASHBOARD_AUTH` resolves to `null`) — no dangling login page
409
- * when the feature is off.
410
- */
411
- declare class AgentDashboardAuthController {
412
- private readonly auth;
413
- private readonly basePath;
414
- private readonly logger;
415
- /** Warn once PER HOOK KIND (not per request) so a broken hook can't be used to flood the logs. */
416
- private readonly warnedHooks;
417
- constructor(auth: ResolvedDashboardAuth | null, basePath: string);
418
- loginPage(req: AuthPageRequest, res: AuthPageResponse, returnToQuery?: string, error?: string): string;
419
- login(body: LoginFormBody, req: unknown, res: AuthPageResponse): Promise<string>;
420
- logout(req: unknown, res: AuthPageResponse): string;
421
- session(request: unknown, response: unknown): Promise<void>;
422
- sessionRequiredPage(req: AuthPageRequest, res: unknown): Promise<void>;
423
- /** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
424
- private redirectToLoginError;
425
- private currentSession;
426
- /**
427
- * Run a host hook (`login` or `session`) defensively: a throw (sync or async) is treated as a
428
- * denial (`null`) and warn-logged ONCE PER KIND, so a buggy/unreachable hook never 500s the
429
- * endpoint into a stack-trace leak nor floods the logs on repeated bad attempts.
430
- */
431
- private runHook;
432
- /**
433
- * Warn once per hook kind for the life of the process, not once per request: a broken hook fires
434
- * on every denied navigation and would otherwise flood the logs.
435
- */
436
- private warnHookOnce;
437
- private requireAuth;
438
- }
439
-
440
265
  /** Same shape {@link AgentDashboardModule.forRoot} accepts — kept local so this stays a pure, DI-free helper. */
441
266
  interface AgentDashboardMountPathsOptions {
442
267
  basePath?: string;
@@ -470,9 +295,7 @@ declare function agentDashboardMountPaths(options?: AgentDashboardMountPathsOpti
470
295
 
471
296
  /**
472
297
  * `TReq` mirrors core's `ActorResolver<TReq>` convention: the transport request type
473
- * {@link AgentDashboardOptions.approvalActorRef} receives. Defaults to `unknown` so untyped usage
474
- * compiles unchanged; a host may narrow it (e.g. `forRoot<Request>({ approvalActorRef: ... })`)
475
- * instead of writing its own `unknown`-narrowing type guard.
298
+ * {@link AgentDashboardOptions.approvalActorRef} receives. Defaults to `unknown`.
476
299
  */
477
300
  interface AgentDashboardOptions<TReq = unknown> {
478
301
  /**
@@ -487,20 +310,26 @@ interface AgentDashboardOptions<TReq = unknown> {
487
310
  */
488
311
  apiBasePath?: string;
489
312
  /**
490
- * Guard classes fronting BOTH dashboard controllers (the SPA at `basePath` and its JSON API at
491
- * `apiBasePath`) — APPENDED onto the built-in `dashboardAuth` gate (a no-op unless configured;
492
- * see {@link dashboardAuth}), so a request must pass BOTH. Omit to leave the routes gated by
493
- * `dashboardAuth` alone (or fully open when that's unset too).
313
+ * Who reaches the console: class decorators applied to every controller this module mounts — the
314
+ * ecosystem's convention, like `@nestjs/mcp`'s `decorators` — with the official tools, e.g.
315
+ * `[UseGuards(AuthenticationGuard), Can(ConsolePolicy, 'view')]` from `@nestjs/authentication` /
316
+ * `@nestjs/authorization`, or a function as a guard instance, `UseGuards({ canActivate })`.
317
+ * Applied to a per-registration subclass, so nothing sticks to the shared classes.
494
318
  *
495
- * A guard's own DEPENDENCIES resolve from this module's `imports` (see {@link imports}) — the
496
- * dashboard module has no application context of its own to pull them from otherwise.
319
+ * In production (`NODE_ENV=production`) the console refuses to boot without them, unless the app
320
+ * mounts the routes itself (`routes: false`): a governance console is never served open there by
321
+ * default. Outside production the routes are open (and to `@nestjs/authorization`'s
322
+ * deny-by-default guard: `CanAnyone()`). Static wiring.
497
323
  */
498
- guards?: Type<CanActivate>[];
324
+ decorators?: ClassDecorator[];
499
325
  /**
500
- * Extra `imports` merged into the dashboard's dynamic module — the DI resolution path for a class
501
- * passed to {@link guards} (or any other provider the controllers need reachable). Typically the
502
- * host's own auth module, e.g. `imports: [AuthModule]` alongside `guards: [JwtAuthGuard]`.
326
+ * `false` mounts none of the console's routes, while its services still run — the way NestJS's
327
+ * own packages leave routes to you: serve them from controllers of your own, protected with the
328
+ * official tools, by extending the exported `AgentApiController` / `AgentUiController` under your
329
+ * own path and decorators (the module exports what they inject). Static wiring.
503
330
  */
331
+ routes?: boolean;
332
+ /** Extra `imports` merged into the console's modules — what a decorator's guard injects. */
504
333
  imports?: DynamicModule['imports'];
505
334
  /**
506
335
  * OVERRIDE for WHO is deciding a HITL approval — invoked on the incoming
@@ -509,95 +338,27 @@ interface AgentDashboardOptions<TReq = unknown> {
509
338
  * DEFAULT (option omitted): the AgentModule-configured actor resolver (`AGENT_ACTOR_RESOLVER`) is
510
339
  * consulted — the same identity seam chat requests use — and its actor id becomes the decider ref
511
340
  * (a throwing resolver, i.e. an unauthenticated request, just omits the ref). Set this only when
512
- * console auth differs from chat auth (e.g. the console sits behind a separate SSO whose principal
513
- * the chat resolver can't read); returning `undefined` leaves `executedByRef` unset — the explicit
514
- * override wins outright, with no resolver fallback.
515
- */
516
- approvalActorRef?: (req: TReq) => string | undefined;
517
- /**
518
- * Gate the console (SPA + API) behind a built-in, signed session cookie. Two ways to mint it:
519
- *
520
- * - **Mode A (`session`, recommended)**: your host app already has its own auth (SSO/OIDC/
521
- * whatever) — the host frontend, carrying that auth, POSTs to `<basePath>/auth/session`, your
522
- * `session` hook validates the raw request and returns the session user, and this library
523
- * mints its cookie from that. No credential this library understands ever exists; you keep
524
- * your own identity provider as the source of truth. A page-level request with no valid
525
- * session (and only Mode A configured) gets a small server-rendered instruction page telling
526
- * the visitor to sign in through your host app, since there is no login page to redirect to.
527
- * - **Mode B (`login`, standalone fallback)**: no host frontend/IdP to lean on — the console
528
- * serves its own small, dependency-free, server-rendered login page (`GET
529
- * <basePath>/auth/login`) and your `login` hook validates submitted username/password. A
530
- * missing/invalid/expired session redirects a page-level request to that login page with
531
- * `?returnTo=<original url>`.
532
- *
533
- * Either mode can be used alone, or both together (e.g. Mode A for normal use, Mode B as a
534
- * break-glass fallback) — at least one is required, or `forRoot`/`forRootAsync` throws at boot
535
- * (an un-mintable gate is a boot error, not a silently-open or silently-stuck console). An
536
- * unauthenticated API call always gets a plain `401`, regardless of mode — the caller reads the
537
- * status code, not HTML. Composes with `guards` — BOTH gates must pass. See
538
- * `DashboardAuthOptions` for the `secret`/`ttl`/`session`/`login` shape.
341
+ * the console's caller is identified differently from chat's; returning `undefined` leaves
342
+ * `executedByRef` unset — the explicit override wins outright, with no resolver fallback.
539
343
  */
540
- dashboardAuth?: DashboardAuthOptions;
541
- }
542
- /**
543
- * Async variant of {@link AgentDashboardOptions}, for a `session`/`login` hook that needs injected
544
- * services (e.g. an EntityManager to check credentials against a DB). Everything else stays
545
- * static/sync — `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same
546
- * constraint `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s
547
- * document), so only the auth piece itself is resolved through DI.
548
- */
549
- interface AgentDashboardAsyncOptions<TReq = unknown> {
550
- basePath?: string;
551
- apiBasePath?: string;
552
- guards?: Type<CanActivate>[];
553
- imports?: DynamicModule['imports'];
554
344
  approvalActorRef?: (req: TReq) => string | undefined;
555
- /** Providers injected into `useDashboardAuth`, in order. Shared with a guard class's own deps via `imports`. */
556
- inject?: Array<InjectionToken | OptionalFactoryDependency>;
557
- /**
558
- * Build the `dashboardAuth` config from injected deps, or return `undefined` to leave the
559
- * console open (or fronted only by `guards`). See {@link AgentDashboardOptions.dashboardAuth}.
560
- */
561
- useDashboardAuth: (...deps: any[]) => DashboardAuthOptions | undefined | Promise<DashboardAuthOptions | undefined>;
562
345
  }
563
- /**
564
- * Holds the JSON API + SSE controller and its read service, mounted on its own path by `forRoot`.
565
- * Dynamic: guards are DI-instantiated by the CONTROLLER's host module, so this module — not the
566
- * outer wrapper — must carry the guard classes as providers plus the host's `imports` that resolve
567
- * their dependencies. A static module here made `guards: [SomeGuardWithDeps]` fail at boot with
568
- * "Nest can't resolve dependencies ... in the AgentApiModule context" even when the host passed
569
- * the right `imports` to `forRoot`.
570
- */
346
+ /** Holds the JSON API + SSE controller and its read service, mounted on its own path. */
571
347
  declare class AgentApiModule {
572
348
  static register<TReq = unknown>(options: {
573
349
  imports?: DynamicModule['imports'];
574
- guards?: Type<CanActivate>[];
350
+ decorators?: ClassDecorator[];
351
+ routes?: boolean;
575
352
  approvalActorRef?: (req: TReq) => string | undefined;
576
- /** Provider for `DASHBOARD_AUTH` — a `useValue` (`forRoot`) or a `useFactory` (`forRootAsync`). */
577
- dashboardAuth: Provider;
578
353
  }): DynamicModule;
579
354
  }
580
355
  /**
581
- * Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE
582
- * API at `apiBasePath` (default `<basePath>/api`), plus the built-in `dashboardAuth` routes at
583
- * `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set — `POST
584
- * <basePath>/auth/session` for Mode A (the host mints the session from its own auth) and/or `GET`/
585
- * `POST <basePath>/auth/login` for Mode B (the built-in login screen).
586
- *
587
- * Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module
588
- * (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the
589
- * routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —
590
- * see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` session cookie.
591
- *
592
- * Inertia hosts: the console is a full-page app, not an Inertia page. An in-app `<Link>` visit to
593
- * `basePath` (an XHR carrying `X-Inertia`) is bounced with the protocol's own external-redirect
594
- * mechanism — `409 Conflict` + `X-Inertia-Location: <the visited URL>` — so the Inertia client
595
- * performs a full `window.location` load and the console renders normally. In-app links to the
596
- * console therefore just work; no host-side special-casing needed.
356
+ * The AI-gateway console: the SPA at `basePath` and its JSON API at `apiBasePath`. Who reaches them
357
+ * is the app's — `decorators`, or the app mounts them itself (`routes: false`) — with
358
+ * `@nestjs/authentication` / `@nestjs/authorization`.
597
359
  */
598
360
  declare class AgentDashboardModule {
599
361
  static forRoot<TReq = unknown>(options?: AgentDashboardOptions<TReq>): DynamicModule;
600
- static forRootAsync<TReq = unknown>(options: AgentDashboardAsyncOptions<TReq>): DynamicModule;
601
362
  }
602
363
 
603
364
  /**
@@ -619,11 +380,8 @@ interface UiPageResponse {
619
380
  * `<base>/assets`). The path comes from `RouterModule` (set by
620
381
  * {@link AgentDashboardModule.forRoot}({ basePath })), so the controller routes are relative.
621
382
  *
622
- * `@UseGuards(DashboardAuthPageGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
623
- * that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
624
- * this baseline by `stampGuards` (`./guards.js`), never replacing it. `@UseFilters` turns the
625
- * guard's redirect-on-deny into an actual 302 response; it is a no-op when the guard never throws
626
- * (i.e. `dashboardAuth` unconfigured).
383
+ * Who reaches it is the app's: `decorators` on `AgentDashboardModule.forRoot`, or the app mounts it
384
+ * itself (`routes: false`) — with `@nestjs/authentication` / `@nestjs/authorization`.
627
385
  */
628
386
  declare class AgentUiController {
629
387
  private readonly basePath;
@@ -697,13 +455,5 @@ declare const DASHBOARD_API_PATH: unique symbol;
697
455
  * injecting it needs no `@Optional()`.
698
456
  */
699
457
  declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
700
- /**
701
- * DI token carrying the resolved `dashboardAuth` config (`ResolvedDashboardAuth | null`) — `null`
702
- * when the host didn't configure it (the built-in guards are then a no-op, today's behavior
703
- * byte-for-byte). Bound once by `AgentApiModule.register` and re-exported so `AgentUiController`
704
- * and `AgentDashboardAuthController` (hosted directly by `AgentDashboardModule`, which imports
705
- * `AgentApiModule`) resolve the SAME instance rather than re-running a host's async factory twice.
706
- */
707
- declare const DASHBOARD_AUTH: unique symbol;
708
458
 
709
- export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, type AgentDashboardAsyncOptions, AgentDashboardAuthController, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, type AuthMode, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type RevalidateHook, type RunDetailWithLabel, type SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadDetailWithLabel, type ThreadSpendRowWithLabel, type UnauthenticatedPageContext, type UnauthenticatedPageHook, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
459
+ export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_BASE_PATH, DashboardService, type LiveAgentEvent, type ReliabilityOverview, type RunDetailWithLabel, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadDetailWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput };