@dudousxd/nestjs-agent-dashboard 0.8.0 → 0.9.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.
- package/README.md +85 -2
- package/dist/server/index.cjs +1115 -217
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +149 -8
- package/dist/server/index.d.ts +149 -8
- package/dist/server/index.js +1072 -177
- package/dist/server/index.js.map +1 -1
- package/package.json +6 -2
package/dist/server/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ToolStatRow, ThreadActivityRow, 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, StreamableFile } from '@nestjs/common';
|
|
4
|
+
import { DynamicModule, Type, CanActivate, Provider, InjectionToken, OptionalFactoryDependency, 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 {
|
|
@@ -112,6 +112,10 @@ declare class DashboardService {
|
|
|
112
112
|
/**
|
|
113
113
|
* JSON + SSE API consumed by the AI-gateway console SPA. Mounted at `apiBasePath` (set by
|
|
114
114
|
* `RouterModule` in {@link AgentDashboardModule.forRoot}), so the controller routes are relative.
|
|
115
|
+
*
|
|
116
|
+
* `@UseGuards(DashboardAuthGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
|
|
117
|
+
* that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
|
|
118
|
+
* this baseline by `stampGuards` (`./guards.js`), never replacing it.
|
|
115
119
|
*/
|
|
116
120
|
declare class AgentApiController {
|
|
117
121
|
private readonly dashboard;
|
|
@@ -183,6 +187,96 @@ declare class AgentApiController {
|
|
|
183
187
|
}>;
|
|
184
188
|
}
|
|
185
189
|
|
|
190
|
+
/** The session user the host's `login` hook returns to mint a cookie. */
|
|
191
|
+
interface DashboardSessionUser {
|
|
192
|
+
id: string;
|
|
193
|
+
name?: string;
|
|
194
|
+
roles?: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Host hook: validates submitted credentials for the built-in login screen. */
|
|
198
|
+
type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
199
|
+
/**
|
|
200
|
+
* Author-facing `dashboardAuth` option (see `AgentDashboardOptions.dashboardAuth`). Gates the
|
|
201
|
+
* console (SPA + API) behind a built-in cookie-session login screen — no host frontend changes,
|
|
202
|
+
* no SSO required. Mirrors `@dudousxd/nestjs-telescope`'s `dashboardAuth` Mode B (`login`).
|
|
203
|
+
*/
|
|
204
|
+
interface DashboardAuthOptions {
|
|
205
|
+
/** REQUIRED HMAC-SHA256 signing key (32+ bytes recommended). Missing/empty => boot error (fail closed). */
|
|
206
|
+
secret: string;
|
|
207
|
+
/** Cookie TTL (duration string `'<n><ms|s|m|h|d>'`, e.g. `'30m'`, `'7d'`). Default `'8h'`. */
|
|
208
|
+
ttl?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Validates submitted username/password. Return the session user to grant access, or `null` to
|
|
211
|
+
* deny — the login endpoint responds identically (generic failure) for an unknown user and a
|
|
212
|
+
* wrong password, so it never reveals which one was wrong.
|
|
213
|
+
*/
|
|
214
|
+
login: LoginHook;
|
|
215
|
+
}
|
|
216
|
+
/** Resolved, validated `dashboardAuth` config used by the guards/controller. */
|
|
217
|
+
interface ResolvedDashboardAuth {
|
|
218
|
+
secret: string;
|
|
219
|
+
ttlMs: number;
|
|
220
|
+
login: LoginHook;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Validate + resolve `dashboardAuth`. Returns `null` when unconfigured (behavior unchanged — the
|
|
224
|
+
* console stays open, front it with your own `guards`). Throws at boot (fail closed) when
|
|
225
|
+
* configured but missing a secret or a `login` hook — the host learns immediately rather than
|
|
226
|
+
* shipping an open or un-mintable console.
|
|
227
|
+
*/
|
|
228
|
+
declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
|
|
229
|
+
|
|
230
|
+
/** The slice of the platform request this controller reads — structural, no Express/Fastify dependency. */
|
|
231
|
+
interface AuthPageRequest {
|
|
232
|
+
headers: Record<string, string | string[] | undefined>;
|
|
233
|
+
}
|
|
234
|
+
/** The slice of the platform response this controller writes (passthrough mode — Nest still sends). */
|
|
235
|
+
interface AuthPageResponse {
|
|
236
|
+
status(code: number): unknown;
|
|
237
|
+
setHeader(name: string, value: string): unknown;
|
|
238
|
+
}
|
|
239
|
+
interface LoginFormBody {
|
|
240
|
+
username?: unknown;
|
|
241
|
+
password?: unknown;
|
|
242
|
+
returnTo?: unknown;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Mounted directly on `AgentDashboardModule` at `<basePath>/auth/*` — a SEPARATE controller from
|
|
246
|
+
* `AgentUiController`/`AgentApiController` so it carries neither `DashboardAuthPageGuard`,
|
|
247
|
+
* `DashboardAuthGuard`, nor any host `guards`: these routes MINT (and clear) the session cookie the
|
|
248
|
+
* built-in gates check for, so they can never be made to require the very auth they grant. Mirrors
|
|
249
|
+
* `@dudousxd/nestjs-telescope`'s own auth controller staying outside its `stampGuards` call.
|
|
250
|
+
*
|
|
251
|
+
* A dependency-free, server-rendered login form (GET/POST) rather than a JSON API + client-side
|
|
252
|
+
* screen — the bundled React SPA in this package is a built Vite artifact with no auth-aware UI of
|
|
253
|
+
* its own, so gating the actual page navigation needs a self-contained flow that doesn't touch it.
|
|
254
|
+
*
|
|
255
|
+
* 404s every route when `dashboardAuth` is unconfigured (`DASHBOARD_AUTH` resolves to `null`) — no
|
|
256
|
+
* dangling login page when the feature is off.
|
|
257
|
+
*/
|
|
258
|
+
declare class AgentDashboardAuthController {
|
|
259
|
+
private readonly auth;
|
|
260
|
+
private readonly basePath;
|
|
261
|
+
private readonly logger;
|
|
262
|
+
/** Warn once (not per request) so a broken hook can't be used to flood the logs. */
|
|
263
|
+
private warnedLoginHookThrow;
|
|
264
|
+
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
265
|
+
loginPage(req: AuthPageRequest, res: AuthPageResponse, returnToQuery?: string, error?: string): string;
|
|
266
|
+
login(body: LoginFormBody, req: unknown, res: AuthPageResponse): Promise<string>;
|
|
267
|
+
logout(req: unknown, res: AuthPageResponse): string;
|
|
268
|
+
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
269
|
+
private redirectToLoginError;
|
|
270
|
+
private currentSession;
|
|
271
|
+
/**
|
|
272
|
+
* Run the host's `login` hook defensively: a throw (sync or async) is treated as a denial
|
|
273
|
+
* (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the endpoint into a
|
|
274
|
+
* stack-trace leak nor floods the logs.
|
|
275
|
+
*/
|
|
276
|
+
private runLoginHook;
|
|
277
|
+
private requireAuth;
|
|
278
|
+
}
|
|
279
|
+
|
|
186
280
|
/** Same shape {@link AgentDashboardModule.forRoot} accepts — kept local so this stays a pure, DI-free helper. */
|
|
187
281
|
interface AgentDashboardMountPathsOptions {
|
|
188
282
|
basePath?: string;
|
|
@@ -234,10 +328,9 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
234
328
|
apiBasePath?: string;
|
|
235
329
|
/**
|
|
236
330
|
* Guard classes fronting BOTH dashboard controllers (the SPA at `basePath` and its JSON API at
|
|
237
|
-
* `apiBasePath`)
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* host fronts them another way, e.g. a global guard or reverse-proxy auth).
|
|
331
|
+
* `apiBasePath`) — APPENDED onto the built-in `dashboardAuth` gate (a no-op unless configured;
|
|
332
|
+
* see {@link dashboardAuth}), so a request must pass BOTH. Omit to leave the routes gated by
|
|
333
|
+
* `dashboardAuth` alone (or fully open when that's unset too).
|
|
241
334
|
*
|
|
242
335
|
* A guard's own DEPENDENCIES resolve from this module's `imports` (see {@link imports}) — the
|
|
243
336
|
* dashboard module has no application context of its own to pull them from otherwise.
|
|
@@ -261,6 +354,36 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
261
354
|
* override wins outright, with no resolver fallback.
|
|
262
355
|
*/
|
|
263
356
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
357
|
+
/**
|
|
358
|
+
* Gate the console (SPA + API) behind a BUILT-IN cookie-session login screen — the simplest way
|
|
359
|
+
* to protect `basePath` when the host has no ready-made guard (e.g. header-only auth that a
|
|
360
|
+
* browser navigation can't attach). Omit to leave the console open, or fronted only by
|
|
361
|
+
* {@link guards}. When set, an unauthenticated page navigation is redirected (302) to
|
|
362
|
+
* `<basePath>/auth/login`; an unauthenticated API call gets a `401`. Composes with `guards` —
|
|
363
|
+
* BOTH gates must pass. See `DashboardAuthOptions` for the `secret`/`ttl`/`login` shape.
|
|
364
|
+
*/
|
|
365
|
+
dashboardAuth?: DashboardAuthOptions;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Async variant of {@link AgentDashboardOptions}, for a `login` hook that needs injected services
|
|
369
|
+
* (e.g. an EntityManager to check credentials against a DB). Everything else stays static/sync —
|
|
370
|
+
* `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same constraint
|
|
371
|
+
* `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s document), so
|
|
372
|
+
* only the auth piece itself is resolved through DI.
|
|
373
|
+
*/
|
|
374
|
+
interface AgentDashboardAsyncOptions<TReq = unknown> {
|
|
375
|
+
basePath?: string;
|
|
376
|
+
apiBasePath?: string;
|
|
377
|
+
guards?: Type<CanActivate>[];
|
|
378
|
+
imports?: DynamicModule['imports'];
|
|
379
|
+
approvalActorRef?: (req: TReq) => string | undefined;
|
|
380
|
+
/** Providers injected into `useDashboardAuth`, in order. Shared with a guard class's own deps via `imports`. */
|
|
381
|
+
inject?: Array<InjectionToken | OptionalFactoryDependency>;
|
|
382
|
+
/**
|
|
383
|
+
* Build the `dashboardAuth` config from injected deps, or return `undefined` to leave the
|
|
384
|
+
* console open (or fronted only by `guards`). See {@link AgentDashboardOptions.dashboardAuth}.
|
|
385
|
+
*/
|
|
386
|
+
useDashboardAuth: (...deps: any[]) => DashboardAuthOptions | undefined | Promise<DashboardAuthOptions | undefined>;
|
|
264
387
|
}
|
|
265
388
|
/**
|
|
266
389
|
* Holds the JSON API + SSE controller and its read service, mounted on its own path by `forRoot`.
|
|
@@ -275,16 +398,19 @@ declare class AgentApiModule {
|
|
|
275
398
|
imports?: DynamicModule['imports'];
|
|
276
399
|
guards?: Type<CanActivate>[];
|
|
277
400
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
401
|
+
/** Provider for `DASHBOARD_AUTH` — a `useValue` (`forRoot`) or a `useFactory` (`forRootAsync`). */
|
|
402
|
+
dashboardAuth: Provider;
|
|
278
403
|
}): DynamicModule;
|
|
279
404
|
}
|
|
280
405
|
/**
|
|
281
406
|
* Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE
|
|
282
|
-
* API at `apiBasePath` (default `<basePath>/api`)
|
|
407
|
+
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in login screen's routes at
|
|
408
|
+
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set.
|
|
283
409
|
*
|
|
284
410
|
* Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module
|
|
285
411
|
* (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the
|
|
286
412
|
* routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —
|
|
287
|
-
* see {@link AgentDashboardOptions.guards}.
|
|
413
|
+
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` cookie login.
|
|
288
414
|
*
|
|
289
415
|
* Inertia hosts: the console is a full-page app, not an Inertia page. An in-app `<Link>` visit to
|
|
290
416
|
* `basePath` (an XHR carrying `X-Inertia`) is bounced with the protocol's own external-redirect
|
|
@@ -294,6 +420,7 @@ declare class AgentApiModule {
|
|
|
294
420
|
*/
|
|
295
421
|
declare class AgentDashboardModule {
|
|
296
422
|
static forRoot<TReq = unknown>(options?: AgentDashboardOptions<TReq>): DynamicModule;
|
|
423
|
+
static forRootAsync<TReq = unknown>(options: AgentDashboardAsyncOptions<TReq>): DynamicModule;
|
|
297
424
|
}
|
|
298
425
|
|
|
299
426
|
/**
|
|
@@ -314,6 +441,12 @@ interface UiPageResponse {
|
|
|
314
441
|
* Serves the bundled AI-gateway console SPA at the configured base (+ hashed assets at
|
|
315
442
|
* `<base>/assets`). The path comes from `RouterModule` (set by
|
|
316
443
|
* {@link AgentDashboardModule.forRoot}({ basePath })), so the controller routes are relative.
|
|
444
|
+
*
|
|
445
|
+
* `@UseGuards(DashboardAuthPageGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
|
|
446
|
+
* that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
|
|
447
|
+
* this baseline by `stampGuards` (`./guards.js`), never replacing it. `@UseFilters` turns the
|
|
448
|
+
* guard's redirect-on-deny into an actual 302 response; it is a no-op when the guard never throws
|
|
449
|
+
* (i.e. `dashboardAuth` unconfigured).
|
|
317
450
|
*/
|
|
318
451
|
declare class AgentUiController {
|
|
319
452
|
private readonly basePath;
|
|
@@ -388,5 +521,13 @@ declare const DASHBOARD_API_PATH: unique symbol;
|
|
|
388
521
|
* `@dudousxd/nestjs-agent`).
|
|
389
522
|
*/
|
|
390
523
|
declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
|
|
524
|
+
/**
|
|
525
|
+
* DI token carrying the resolved `dashboardAuth` config (`ResolvedDashboardAuth | null`) — `null`
|
|
526
|
+
* when the host didn't configure it (the built-in guards are then a no-op, today's behavior
|
|
527
|
+
* byte-for-byte). Bound once by `AgentApiModule.register` and re-exported so `AgentUiController`
|
|
528
|
+
* and `AgentDashboardAuthController` (hosted directly by `AgentDashboardModule`, which imports
|
|
529
|
+
* `AgentApiModule`) resolve the SAME instance rather than re-running a host's async factory twice.
|
|
530
|
+
*/
|
|
531
|
+
declare const DASHBOARD_AUTH: unique symbol;
|
|
391
532
|
|
|
392
|
-
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 SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput };
|
|
533
|
+
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, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ToolStatRow, ThreadActivityRow, 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, StreamableFile } from '@nestjs/common';
|
|
4
|
+
import { DynamicModule, Type, CanActivate, Provider, InjectionToken, OptionalFactoryDependency, 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 {
|
|
@@ -112,6 +112,10 @@ declare class DashboardService {
|
|
|
112
112
|
/**
|
|
113
113
|
* JSON + SSE API consumed by the AI-gateway console SPA. Mounted at `apiBasePath` (set by
|
|
114
114
|
* `RouterModule` in {@link AgentDashboardModule.forRoot}), so the controller routes are relative.
|
|
115
|
+
*
|
|
116
|
+
* `@UseGuards(DashboardAuthGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
|
|
117
|
+
* that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
|
|
118
|
+
* this baseline by `stampGuards` (`./guards.js`), never replacing it.
|
|
115
119
|
*/
|
|
116
120
|
declare class AgentApiController {
|
|
117
121
|
private readonly dashboard;
|
|
@@ -183,6 +187,96 @@ declare class AgentApiController {
|
|
|
183
187
|
}>;
|
|
184
188
|
}
|
|
185
189
|
|
|
190
|
+
/** The session user the host's `login` hook returns to mint a cookie. */
|
|
191
|
+
interface DashboardSessionUser {
|
|
192
|
+
id: string;
|
|
193
|
+
name?: string;
|
|
194
|
+
roles?: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Host hook: validates submitted credentials for the built-in login screen. */
|
|
198
|
+
type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
199
|
+
/**
|
|
200
|
+
* Author-facing `dashboardAuth` option (see `AgentDashboardOptions.dashboardAuth`). Gates the
|
|
201
|
+
* console (SPA + API) behind a built-in cookie-session login screen — no host frontend changes,
|
|
202
|
+
* no SSO required. Mirrors `@dudousxd/nestjs-telescope`'s `dashboardAuth` Mode B (`login`).
|
|
203
|
+
*/
|
|
204
|
+
interface DashboardAuthOptions {
|
|
205
|
+
/** REQUIRED HMAC-SHA256 signing key (32+ bytes recommended). Missing/empty => boot error (fail closed). */
|
|
206
|
+
secret: string;
|
|
207
|
+
/** Cookie TTL (duration string `'<n><ms|s|m|h|d>'`, e.g. `'30m'`, `'7d'`). Default `'8h'`. */
|
|
208
|
+
ttl?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Validates submitted username/password. Return the session user to grant access, or `null` to
|
|
211
|
+
* deny — the login endpoint responds identically (generic failure) for an unknown user and a
|
|
212
|
+
* wrong password, so it never reveals which one was wrong.
|
|
213
|
+
*/
|
|
214
|
+
login: LoginHook;
|
|
215
|
+
}
|
|
216
|
+
/** Resolved, validated `dashboardAuth` config used by the guards/controller. */
|
|
217
|
+
interface ResolvedDashboardAuth {
|
|
218
|
+
secret: string;
|
|
219
|
+
ttlMs: number;
|
|
220
|
+
login: LoginHook;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Validate + resolve `dashboardAuth`. Returns `null` when unconfigured (behavior unchanged — the
|
|
224
|
+
* console stays open, front it with your own `guards`). Throws at boot (fail closed) when
|
|
225
|
+
* configured but missing a secret or a `login` hook — the host learns immediately rather than
|
|
226
|
+
* shipping an open or un-mintable console.
|
|
227
|
+
*/
|
|
228
|
+
declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
|
|
229
|
+
|
|
230
|
+
/** The slice of the platform request this controller reads — structural, no Express/Fastify dependency. */
|
|
231
|
+
interface AuthPageRequest {
|
|
232
|
+
headers: Record<string, string | string[] | undefined>;
|
|
233
|
+
}
|
|
234
|
+
/** The slice of the platform response this controller writes (passthrough mode — Nest still sends). */
|
|
235
|
+
interface AuthPageResponse {
|
|
236
|
+
status(code: number): unknown;
|
|
237
|
+
setHeader(name: string, value: string): unknown;
|
|
238
|
+
}
|
|
239
|
+
interface LoginFormBody {
|
|
240
|
+
username?: unknown;
|
|
241
|
+
password?: unknown;
|
|
242
|
+
returnTo?: unknown;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Mounted directly on `AgentDashboardModule` at `<basePath>/auth/*` — a SEPARATE controller from
|
|
246
|
+
* `AgentUiController`/`AgentApiController` so it carries neither `DashboardAuthPageGuard`,
|
|
247
|
+
* `DashboardAuthGuard`, nor any host `guards`: these routes MINT (and clear) the session cookie the
|
|
248
|
+
* built-in gates check for, so they can never be made to require the very auth they grant. Mirrors
|
|
249
|
+
* `@dudousxd/nestjs-telescope`'s own auth controller staying outside its `stampGuards` call.
|
|
250
|
+
*
|
|
251
|
+
* A dependency-free, server-rendered login form (GET/POST) rather than a JSON API + client-side
|
|
252
|
+
* screen — the bundled React SPA in this package is a built Vite artifact with no auth-aware UI of
|
|
253
|
+
* its own, so gating the actual page navigation needs a self-contained flow that doesn't touch it.
|
|
254
|
+
*
|
|
255
|
+
* 404s every route when `dashboardAuth` is unconfigured (`DASHBOARD_AUTH` resolves to `null`) — no
|
|
256
|
+
* dangling login page when the feature is off.
|
|
257
|
+
*/
|
|
258
|
+
declare class AgentDashboardAuthController {
|
|
259
|
+
private readonly auth;
|
|
260
|
+
private readonly basePath;
|
|
261
|
+
private readonly logger;
|
|
262
|
+
/** Warn once (not per request) so a broken hook can't be used to flood the logs. */
|
|
263
|
+
private warnedLoginHookThrow;
|
|
264
|
+
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
265
|
+
loginPage(req: AuthPageRequest, res: AuthPageResponse, returnToQuery?: string, error?: string): string;
|
|
266
|
+
login(body: LoginFormBody, req: unknown, res: AuthPageResponse): Promise<string>;
|
|
267
|
+
logout(req: unknown, res: AuthPageResponse): string;
|
|
268
|
+
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
269
|
+
private redirectToLoginError;
|
|
270
|
+
private currentSession;
|
|
271
|
+
/**
|
|
272
|
+
* Run the host's `login` hook defensively: a throw (sync or async) is treated as a denial
|
|
273
|
+
* (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the endpoint into a
|
|
274
|
+
* stack-trace leak nor floods the logs.
|
|
275
|
+
*/
|
|
276
|
+
private runLoginHook;
|
|
277
|
+
private requireAuth;
|
|
278
|
+
}
|
|
279
|
+
|
|
186
280
|
/** Same shape {@link AgentDashboardModule.forRoot} accepts — kept local so this stays a pure, DI-free helper. */
|
|
187
281
|
interface AgentDashboardMountPathsOptions {
|
|
188
282
|
basePath?: string;
|
|
@@ -234,10 +328,9 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
234
328
|
apiBasePath?: string;
|
|
235
329
|
/**
|
|
236
330
|
* Guard classes fronting BOTH dashboard controllers (the SPA at `basePath` and its JSON API at
|
|
237
|
-
* `apiBasePath`)
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* host fronts them another way, e.g. a global guard or reverse-proxy auth).
|
|
331
|
+
* `apiBasePath`) — APPENDED onto the built-in `dashboardAuth` gate (a no-op unless configured;
|
|
332
|
+
* see {@link dashboardAuth}), so a request must pass BOTH. Omit to leave the routes gated by
|
|
333
|
+
* `dashboardAuth` alone (or fully open when that's unset too).
|
|
241
334
|
*
|
|
242
335
|
* A guard's own DEPENDENCIES resolve from this module's `imports` (see {@link imports}) — the
|
|
243
336
|
* dashboard module has no application context of its own to pull them from otherwise.
|
|
@@ -261,6 +354,36 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
261
354
|
* override wins outright, with no resolver fallback.
|
|
262
355
|
*/
|
|
263
356
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
357
|
+
/**
|
|
358
|
+
* Gate the console (SPA + API) behind a BUILT-IN cookie-session login screen — the simplest way
|
|
359
|
+
* to protect `basePath` when the host has no ready-made guard (e.g. header-only auth that a
|
|
360
|
+
* browser navigation can't attach). Omit to leave the console open, or fronted only by
|
|
361
|
+
* {@link guards}. When set, an unauthenticated page navigation is redirected (302) to
|
|
362
|
+
* `<basePath>/auth/login`; an unauthenticated API call gets a `401`. Composes with `guards` —
|
|
363
|
+
* BOTH gates must pass. See `DashboardAuthOptions` for the `secret`/`ttl`/`login` shape.
|
|
364
|
+
*/
|
|
365
|
+
dashboardAuth?: DashboardAuthOptions;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Async variant of {@link AgentDashboardOptions}, for a `login` hook that needs injected services
|
|
369
|
+
* (e.g. an EntityManager to check credentials against a DB). Everything else stays static/sync —
|
|
370
|
+
* `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same constraint
|
|
371
|
+
* `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s document), so
|
|
372
|
+
* only the auth piece itself is resolved through DI.
|
|
373
|
+
*/
|
|
374
|
+
interface AgentDashboardAsyncOptions<TReq = unknown> {
|
|
375
|
+
basePath?: string;
|
|
376
|
+
apiBasePath?: string;
|
|
377
|
+
guards?: Type<CanActivate>[];
|
|
378
|
+
imports?: DynamicModule['imports'];
|
|
379
|
+
approvalActorRef?: (req: TReq) => string | undefined;
|
|
380
|
+
/** Providers injected into `useDashboardAuth`, in order. Shared with a guard class's own deps via `imports`. */
|
|
381
|
+
inject?: Array<InjectionToken | OptionalFactoryDependency>;
|
|
382
|
+
/**
|
|
383
|
+
* Build the `dashboardAuth` config from injected deps, or return `undefined` to leave the
|
|
384
|
+
* console open (or fronted only by `guards`). See {@link AgentDashboardOptions.dashboardAuth}.
|
|
385
|
+
*/
|
|
386
|
+
useDashboardAuth: (...deps: any[]) => DashboardAuthOptions | undefined | Promise<DashboardAuthOptions | undefined>;
|
|
264
387
|
}
|
|
265
388
|
/**
|
|
266
389
|
* Holds the JSON API + SSE controller and its read service, mounted on its own path by `forRoot`.
|
|
@@ -275,16 +398,19 @@ declare class AgentApiModule {
|
|
|
275
398
|
imports?: DynamicModule['imports'];
|
|
276
399
|
guards?: Type<CanActivate>[];
|
|
277
400
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
401
|
+
/** Provider for `DASHBOARD_AUTH` — a `useValue` (`forRoot`) or a `useFactory` (`forRootAsync`). */
|
|
402
|
+
dashboardAuth: Provider;
|
|
278
403
|
}): DynamicModule;
|
|
279
404
|
}
|
|
280
405
|
/**
|
|
281
406
|
* Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE
|
|
282
|
-
* API at `apiBasePath` (default `<basePath>/api`)
|
|
407
|
+
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in login screen's routes at
|
|
408
|
+
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set.
|
|
283
409
|
*
|
|
284
410
|
* Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module
|
|
285
411
|
* (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the
|
|
286
412
|
* routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —
|
|
287
|
-
* see {@link AgentDashboardOptions.guards}.
|
|
413
|
+
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` cookie login.
|
|
288
414
|
*
|
|
289
415
|
* Inertia hosts: the console is a full-page app, not an Inertia page. An in-app `<Link>` visit to
|
|
290
416
|
* `basePath` (an XHR carrying `X-Inertia`) is bounced with the protocol's own external-redirect
|
|
@@ -294,6 +420,7 @@ declare class AgentApiModule {
|
|
|
294
420
|
*/
|
|
295
421
|
declare class AgentDashboardModule {
|
|
296
422
|
static forRoot<TReq = unknown>(options?: AgentDashboardOptions<TReq>): DynamicModule;
|
|
423
|
+
static forRootAsync<TReq = unknown>(options: AgentDashboardAsyncOptions<TReq>): DynamicModule;
|
|
297
424
|
}
|
|
298
425
|
|
|
299
426
|
/**
|
|
@@ -314,6 +441,12 @@ interface UiPageResponse {
|
|
|
314
441
|
* Serves the bundled AI-gateway console SPA at the configured base (+ hashed assets at
|
|
315
442
|
* `<base>/assets`). The path comes from `RouterModule` (set by
|
|
316
443
|
* {@link AgentDashboardModule.forRoot}({ basePath })), so the controller routes are relative.
|
|
444
|
+
*
|
|
445
|
+
* `@UseGuards(DashboardAuthPageGuard)` is a NO-OP unless the host configured `dashboardAuth` — see
|
|
446
|
+
* that guard's own doc. Host `guards` (see {@link AgentDashboardOptions.guards}) are APPENDED onto
|
|
447
|
+
* this baseline by `stampGuards` (`./guards.js`), never replacing it. `@UseFilters` turns the
|
|
448
|
+
* guard's redirect-on-deny into an actual 302 response; it is a no-op when the guard never throws
|
|
449
|
+
* (i.e. `dashboardAuth` unconfigured).
|
|
317
450
|
*/
|
|
318
451
|
declare class AgentUiController {
|
|
319
452
|
private readonly basePath;
|
|
@@ -388,5 +521,13 @@ declare const DASHBOARD_API_PATH: unique symbol;
|
|
|
388
521
|
* `@dudousxd/nestjs-agent`).
|
|
389
522
|
*/
|
|
390
523
|
declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
|
|
524
|
+
/**
|
|
525
|
+
* DI token carrying the resolved `dashboardAuth` config (`ResolvedDashboardAuth | null`) — `null`
|
|
526
|
+
* when the host didn't configure it (the built-in guards are then a no-op, today's behavior
|
|
527
|
+
* byte-for-byte). Bound once by `AgentApiModule.register` and re-exported so `AgentUiController`
|
|
528
|
+
* and `AgentDashboardAuthController` (hosted directly by `AgentDashboardModule`, which imports
|
|
529
|
+
* `AgentApiModule`) resolve the SAME instance rather than re-running a host's async factory twice.
|
|
530
|
+
*/
|
|
531
|
+
declare const DASHBOARD_AUTH: unique symbol;
|
|
391
532
|
|
|
392
|
-
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 SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput };
|
|
533
|
+
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, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
|