@dudousxd/nestjs-agent-dashboard 0.9.1 → 0.10.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 +41 -5
- package/dist/server/index.cjs +176 -78
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +94 -37
- package/dist/server/index.d.ts +94 -37
- package/dist/server/index.js +177 -79
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.d.cts
CHANGED
|
@@ -194,12 +194,35 @@ interface DashboardSessionUser {
|
|
|
194
194
|
roles?: string[];
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Host hook for Mode A: validates the host's own auth on the raw request POSTed to
|
|
199
|
+
* `<basePath>/auth/session`. Return the session user to grant access, or `null` to deny.
|
|
200
|
+
*/
|
|
201
|
+
type SessionHook = (request: unknown) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
202
|
+
/** Host hook for Mode B: validates submitted credentials for the built-in login screen. */
|
|
198
203
|
type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
204
|
+
/**
|
|
205
|
+
* Re-checks a LIVE session when the cookie is slid forward. Runs at most once per `ttl/2` PER
|
|
206
|
+
* COOKIE GENERATION, per in-flight request — the gate is on the inbound cookie's `iat`, so every
|
|
207
|
+
* request still carrying a not-yet-renewed cookie invokes this hook, not just the first: a page
|
|
208
|
+
* load that fires N parallel API calls can trigger up to N calls before the refreshed cookie lands
|
|
209
|
+
* on the client. Bounded and cheap for typical console traffic, but not a per-session-lifetime
|
|
210
|
+
* cap — a slow or expensive check should debounce/cache on its own. Return `false` to revoke (the
|
|
211
|
+
* cookie is cleared and the request denied). Distinct from `session`: that hook reads the host's
|
|
212
|
+
* auth off a fresh request, which a console XHR does not carry — this one receives the
|
|
213
|
+
* already-minted session.
|
|
214
|
+
*/
|
|
215
|
+
type RevalidateHook = (session: DashboardSessionUser) => Promise<boolean> | boolean;
|
|
216
|
+
/** Which `dashboardAuth` hook(s) a resolved config was given — see `resolveDashboardAuth`. */
|
|
217
|
+
type AuthMode = 'session' | 'login';
|
|
199
218
|
/**
|
|
200
219
|
* Author-facing `dashboardAuth` option (see `AgentDashboardOptions.dashboardAuth`). Gates the
|
|
201
|
-
* console (SPA + API) behind a
|
|
202
|
-
*
|
|
220
|
+
* console (SPA + API) behind a signed session cookie. Two ways to mint that cookie: Mode A
|
|
221
|
+
* (`session`) — the host frontend, already carrying its own auth, POSTs to
|
|
222
|
+
* `<basePath>/auth/session` and the host hook decides — or Mode B (`login`) — the built-in,
|
|
223
|
+
* dependency-free server-rendered login screen. Mirrors `@dudousxd/nestjs-telescope`'s
|
|
224
|
+
* `dashboardAuth` two-mode shape. At least one of the two is required so an un-mintable gate is a
|
|
225
|
+
* boot error, not a silently-open (or silently-stuck) console.
|
|
203
226
|
*/
|
|
204
227
|
interface DashboardAuthOptions {
|
|
205
228
|
/** REQUIRED HMAC-SHA256 signing key (32+ bytes recommended). Missing/empty => boot error (fail closed). */
|
|
@@ -207,23 +230,36 @@ interface DashboardAuthOptions {
|
|
|
207
230
|
/** Cookie TTL (duration string `'<n><ms|s|m|h|d>'`, e.g. `'30m'`, `'7d'`). Default `'8h'`. */
|
|
208
231
|
ttl?: string;
|
|
209
232
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
233
|
+
* Mode A: validates the host's own auth on the raw request POSTed to `<basePath>/auth/session`.
|
|
234
|
+
* Return the session user to grant access, or `null` to deny. No credential reaches this
|
|
235
|
+
* library — the host decides from whatever it already has (a header, an SSO cookie, ...).
|
|
213
236
|
*/
|
|
214
|
-
|
|
237
|
+
session?: SessionHook;
|
|
238
|
+
/**
|
|
239
|
+
* Mode B: validates submitted username/password. Return the session user to grant access, or
|
|
240
|
+
* `null` to deny — the login endpoint responds identically (generic failure) for an unknown user
|
|
241
|
+
* and a wrong password, so it never reveals which one was wrong.
|
|
242
|
+
*/
|
|
243
|
+
login?: LoginHook;
|
|
244
|
+
/** Re-checks a live session on sliding renewal; see `RevalidateHook`. Not a mode — it cannot
|
|
245
|
+
* mint a session, only revoke one already minted by `session`/`login`. */
|
|
246
|
+
revalidate?: RevalidateHook;
|
|
215
247
|
}
|
|
216
248
|
/** Resolved, validated `dashboardAuth` config used by the guards/controller. */
|
|
217
249
|
interface ResolvedDashboardAuth {
|
|
218
250
|
secret: string;
|
|
219
251
|
ttlMs: number;
|
|
220
|
-
|
|
252
|
+
modes: AuthMode[];
|
|
253
|
+
session?: SessionHook;
|
|
254
|
+
login?: LoginHook;
|
|
255
|
+
revalidate?: RevalidateHook;
|
|
221
256
|
}
|
|
222
257
|
/**
|
|
223
258
|
* Validate + resolve `dashboardAuth`. Returns `null` when unconfigured (behavior unchanged — the
|
|
224
259
|
* console stays open, front it with your own `guards`). Throws at boot (fail closed) when
|
|
225
|
-
* configured but missing a secret
|
|
226
|
-
* shipping an open or
|
|
260
|
+
* configured but missing a secret, when neither `session` nor `login` is given, or when a given
|
|
261
|
+
* hook isn't a function — the host learns immediately rather than shipping an open, stuck, or
|
|
262
|
+
* un-mintable console.
|
|
227
263
|
*/
|
|
228
264
|
declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
|
|
229
265
|
|
|
@@ -248,32 +284,36 @@ interface LoginFormBody {
|
|
|
248
284
|
* built-in gates check for, so they can never be made to require the very auth they grant. Mirrors
|
|
249
285
|
* `@dudousxd/nestjs-telescope`'s own auth controller staying outside its `stampGuards` call.
|
|
250
286
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
287
|
+
* Two ways to mint that cookie, matching `resolveDashboardAuth`'s modes: Mode A (`session`) — the
|
|
288
|
+
* host frontend, already carrying its own auth, POSTs to `<basePath>/auth/session` and the host
|
|
289
|
+
* hook decides — or Mode B (`login`), a dependency-free, server-rendered login form (GET/POST) —
|
|
290
|
+
* the bundled React SPA in this package is a built Vite artifact with no auth-aware UI of its own,
|
|
291
|
+
* so gating the actual page navigation needs a self-contained flow that doesn't touch it. Each
|
|
292
|
+
* mode's routes 404 when that mode isn't configured (`auth.session`/`auth.login` absent), and
|
|
293
|
+
* every route 404s outright when `dashboardAuth` is unconfigured (`DASHBOARD_AUTH` resolves to
|
|
294
|
+
* `null`) — no dangling login page when the feature is off.
|
|
257
295
|
*/
|
|
258
296
|
declare class AgentDashboardAuthController {
|
|
259
297
|
private readonly auth;
|
|
260
298
|
private readonly basePath;
|
|
261
299
|
private readonly logger;
|
|
262
|
-
/** Warn once (not per request) so a broken hook can't be used to flood the logs. */
|
|
263
|
-
private
|
|
300
|
+
/** Warn once PER HOOK KIND (not per request) so a broken hook can't be used to flood the logs. */
|
|
301
|
+
private readonly warnedHooks;
|
|
264
302
|
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
265
303
|
loginPage(req: AuthPageRequest, res: AuthPageResponse, returnToQuery?: string, error?: string): string;
|
|
266
304
|
login(body: LoginFormBody, req: unknown, res: AuthPageResponse): Promise<string>;
|
|
267
305
|
logout(req: unknown, res: AuthPageResponse): string;
|
|
306
|
+
session(request: unknown, response: unknown): Promise<void>;
|
|
307
|
+
sessionRequiredPage(): string;
|
|
268
308
|
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
269
309
|
private redirectToLoginError;
|
|
270
310
|
private currentSession;
|
|
271
311
|
/**
|
|
272
|
-
* Run
|
|
273
|
-
* (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the
|
|
274
|
-
* stack-trace leak nor floods the logs.
|
|
312
|
+
* Run a host hook (`login` or `session`) defensively: a throw (sync or async) is treated as a
|
|
313
|
+
* denial (`null`) and warn-logged ONCE PER KIND, so a buggy/unreachable hook never 500s the
|
|
314
|
+
* endpoint into a stack-trace leak nor floods the logs on repeated bad attempts.
|
|
275
315
|
*/
|
|
276
|
-
private
|
|
316
|
+
private runHook;
|
|
277
317
|
private requireAuth;
|
|
278
318
|
}
|
|
279
319
|
|
|
@@ -355,21 +395,36 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
355
395
|
*/
|
|
356
396
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
357
397
|
/**
|
|
358
|
-
* Gate the console (SPA + API) behind a
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
398
|
+
* Gate the console (SPA + API) behind a built-in, signed session cookie. Two ways to mint it:
|
|
399
|
+
*
|
|
400
|
+
* - **Mode A (`session`, recommended)**: your host app already has its own auth (SSO/OIDC/
|
|
401
|
+
* whatever) — the host frontend, carrying that auth, POSTs to `<basePath>/auth/session`, your
|
|
402
|
+
* `session` hook validates the raw request and returns the session user, and this library
|
|
403
|
+
* mints its cookie from that. No credential this library understands ever exists; you keep
|
|
404
|
+
* your own identity provider as the source of truth. A page-level request with no valid
|
|
405
|
+
* session (and only Mode A configured) gets a small server-rendered instruction page telling
|
|
406
|
+
* the visitor to sign in through your host app, since there is no login page to redirect to.
|
|
407
|
+
* - **Mode B (`login`, standalone fallback)**: no host frontend/IdP to lean on — the console
|
|
408
|
+
* serves its own small, dependency-free, server-rendered login page (`GET
|
|
409
|
+
* <basePath>/auth/login`) and your `login` hook validates submitted username/password. A
|
|
410
|
+
* missing/invalid/expired session redirects a page-level request to that login page with
|
|
411
|
+
* `?returnTo=<original url>`.
|
|
412
|
+
*
|
|
413
|
+
* Either mode can be used alone, or both together (e.g. Mode A for normal use, Mode B as a
|
|
414
|
+
* break-glass fallback) — at least one is required, or `forRoot`/`forRootAsync` throws at boot
|
|
415
|
+
* (an un-mintable gate is a boot error, not a silently-open or silently-stuck console). An
|
|
416
|
+
* unauthenticated API call always gets a plain `401`, regardless of mode — the caller reads the
|
|
417
|
+
* status code, not HTML. Composes with `guards` — BOTH gates must pass. See
|
|
418
|
+
* `DashboardAuthOptions` for the `secret`/`ttl`/`session`/`login` shape.
|
|
364
419
|
*/
|
|
365
420
|
dashboardAuth?: DashboardAuthOptions;
|
|
366
421
|
}
|
|
367
422
|
/**
|
|
368
|
-
* Async variant of {@link AgentDashboardOptions}, for a `login` hook that needs injected
|
|
369
|
-
* (e.g. an EntityManager to check credentials against a DB). Everything else stays
|
|
370
|
-
* `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same
|
|
371
|
-
* `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s
|
|
372
|
-
* only the auth piece itself is resolved through DI.
|
|
423
|
+
* Async variant of {@link AgentDashboardOptions}, for a `session`/`login` hook that needs injected
|
|
424
|
+
* services (e.g. an EntityManager to check credentials against a DB). Everything else stays
|
|
425
|
+
* static/sync — `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same
|
|
426
|
+
* constraint `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s
|
|
427
|
+
* document), so only the auth piece itself is resolved through DI.
|
|
373
428
|
*/
|
|
374
429
|
interface AgentDashboardAsyncOptions<TReq = unknown> {
|
|
375
430
|
basePath?: string;
|
|
@@ -404,13 +459,15 @@ declare class AgentApiModule {
|
|
|
404
459
|
}
|
|
405
460
|
/**
|
|
406
461
|
* Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE
|
|
407
|
-
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in
|
|
408
|
-
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set
|
|
462
|
+
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in `dashboardAuth` routes at
|
|
463
|
+
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set — `POST
|
|
464
|
+
* <basePath>/auth/session` for Mode A (the host mints the session from its own auth) and/or `GET`/
|
|
465
|
+
* `POST <basePath>/auth/login` for Mode B (the built-in login screen).
|
|
409
466
|
*
|
|
410
467
|
* Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module
|
|
411
468
|
* (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the
|
|
412
469
|
* routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —
|
|
413
|
-
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` cookie
|
|
470
|
+
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` session cookie.
|
|
414
471
|
*
|
|
415
472
|
* Inertia hosts: the console is a full-page app, not an Inertia page. An in-app `<Link>` visit to
|
|
416
473
|
* `basePath` (an XHR carrying `X-Inertia`) is bounced with the protocol's own external-redirect
|
|
@@ -530,4 +587,4 @@ declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
|
|
|
530
587
|
*/
|
|
531
588
|
declare const DASHBOARD_AUTH: unique symbol;
|
|
532
589
|
|
|
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 };
|
|
590
|
+
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 SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -194,12 +194,35 @@ interface DashboardSessionUser {
|
|
|
194
194
|
roles?: string[];
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Host hook for Mode A: validates the host's own auth on the raw request POSTed to
|
|
199
|
+
* `<basePath>/auth/session`. Return the session user to grant access, or `null` to deny.
|
|
200
|
+
*/
|
|
201
|
+
type SessionHook = (request: unknown) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
202
|
+
/** Host hook for Mode B: validates submitted credentials for the built-in login screen. */
|
|
198
203
|
type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
204
|
+
/**
|
|
205
|
+
* Re-checks a LIVE session when the cookie is slid forward. Runs at most once per `ttl/2` PER
|
|
206
|
+
* COOKIE GENERATION, per in-flight request — the gate is on the inbound cookie's `iat`, so every
|
|
207
|
+
* request still carrying a not-yet-renewed cookie invokes this hook, not just the first: a page
|
|
208
|
+
* load that fires N parallel API calls can trigger up to N calls before the refreshed cookie lands
|
|
209
|
+
* on the client. Bounded and cheap for typical console traffic, but not a per-session-lifetime
|
|
210
|
+
* cap — a slow or expensive check should debounce/cache on its own. Return `false` to revoke (the
|
|
211
|
+
* cookie is cleared and the request denied). Distinct from `session`: that hook reads the host's
|
|
212
|
+
* auth off a fresh request, which a console XHR does not carry — this one receives the
|
|
213
|
+
* already-minted session.
|
|
214
|
+
*/
|
|
215
|
+
type RevalidateHook = (session: DashboardSessionUser) => Promise<boolean> | boolean;
|
|
216
|
+
/** Which `dashboardAuth` hook(s) a resolved config was given — see `resolveDashboardAuth`. */
|
|
217
|
+
type AuthMode = 'session' | 'login';
|
|
199
218
|
/**
|
|
200
219
|
* Author-facing `dashboardAuth` option (see `AgentDashboardOptions.dashboardAuth`). Gates the
|
|
201
|
-
* console (SPA + API) behind a
|
|
202
|
-
*
|
|
220
|
+
* console (SPA + API) behind a signed session cookie. Two ways to mint that cookie: Mode A
|
|
221
|
+
* (`session`) — the host frontend, already carrying its own auth, POSTs to
|
|
222
|
+
* `<basePath>/auth/session` and the host hook decides — or Mode B (`login`) — the built-in,
|
|
223
|
+
* dependency-free server-rendered login screen. Mirrors `@dudousxd/nestjs-telescope`'s
|
|
224
|
+
* `dashboardAuth` two-mode shape. At least one of the two is required so an un-mintable gate is a
|
|
225
|
+
* boot error, not a silently-open (or silently-stuck) console.
|
|
203
226
|
*/
|
|
204
227
|
interface DashboardAuthOptions {
|
|
205
228
|
/** REQUIRED HMAC-SHA256 signing key (32+ bytes recommended). Missing/empty => boot error (fail closed). */
|
|
@@ -207,23 +230,36 @@ interface DashboardAuthOptions {
|
|
|
207
230
|
/** Cookie TTL (duration string `'<n><ms|s|m|h|d>'`, e.g. `'30m'`, `'7d'`). Default `'8h'`. */
|
|
208
231
|
ttl?: string;
|
|
209
232
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
233
|
+
* Mode A: validates the host's own auth on the raw request POSTed to `<basePath>/auth/session`.
|
|
234
|
+
* Return the session user to grant access, or `null` to deny. No credential reaches this
|
|
235
|
+
* library — the host decides from whatever it already has (a header, an SSO cookie, ...).
|
|
213
236
|
*/
|
|
214
|
-
|
|
237
|
+
session?: SessionHook;
|
|
238
|
+
/**
|
|
239
|
+
* Mode B: validates submitted username/password. Return the session user to grant access, or
|
|
240
|
+
* `null` to deny — the login endpoint responds identically (generic failure) for an unknown user
|
|
241
|
+
* and a wrong password, so it never reveals which one was wrong.
|
|
242
|
+
*/
|
|
243
|
+
login?: LoginHook;
|
|
244
|
+
/** Re-checks a live session on sliding renewal; see `RevalidateHook`. Not a mode — it cannot
|
|
245
|
+
* mint a session, only revoke one already minted by `session`/`login`. */
|
|
246
|
+
revalidate?: RevalidateHook;
|
|
215
247
|
}
|
|
216
248
|
/** Resolved, validated `dashboardAuth` config used by the guards/controller. */
|
|
217
249
|
interface ResolvedDashboardAuth {
|
|
218
250
|
secret: string;
|
|
219
251
|
ttlMs: number;
|
|
220
|
-
|
|
252
|
+
modes: AuthMode[];
|
|
253
|
+
session?: SessionHook;
|
|
254
|
+
login?: LoginHook;
|
|
255
|
+
revalidate?: RevalidateHook;
|
|
221
256
|
}
|
|
222
257
|
/**
|
|
223
258
|
* Validate + resolve `dashboardAuth`. Returns `null` when unconfigured (behavior unchanged — the
|
|
224
259
|
* console stays open, front it with your own `guards`). Throws at boot (fail closed) when
|
|
225
|
-
* configured but missing a secret
|
|
226
|
-
* shipping an open or
|
|
260
|
+
* configured but missing a secret, when neither `session` nor `login` is given, or when a given
|
|
261
|
+
* hook isn't a function — the host learns immediately rather than shipping an open, stuck, or
|
|
262
|
+
* un-mintable console.
|
|
227
263
|
*/
|
|
228
264
|
declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
|
|
229
265
|
|
|
@@ -248,32 +284,36 @@ interface LoginFormBody {
|
|
|
248
284
|
* built-in gates check for, so they can never be made to require the very auth they grant. Mirrors
|
|
249
285
|
* `@dudousxd/nestjs-telescope`'s own auth controller staying outside its `stampGuards` call.
|
|
250
286
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
287
|
+
* Two ways to mint that cookie, matching `resolveDashboardAuth`'s modes: Mode A (`session`) — the
|
|
288
|
+
* host frontend, already carrying its own auth, POSTs to `<basePath>/auth/session` and the host
|
|
289
|
+
* hook decides — or Mode B (`login`), a dependency-free, server-rendered login form (GET/POST) —
|
|
290
|
+
* the bundled React SPA in this package is a built Vite artifact with no auth-aware UI of its own,
|
|
291
|
+
* so gating the actual page navigation needs a self-contained flow that doesn't touch it. Each
|
|
292
|
+
* mode's routes 404 when that mode isn't configured (`auth.session`/`auth.login` absent), and
|
|
293
|
+
* every route 404s outright when `dashboardAuth` is unconfigured (`DASHBOARD_AUTH` resolves to
|
|
294
|
+
* `null`) — no dangling login page when the feature is off.
|
|
257
295
|
*/
|
|
258
296
|
declare class AgentDashboardAuthController {
|
|
259
297
|
private readonly auth;
|
|
260
298
|
private readonly basePath;
|
|
261
299
|
private readonly logger;
|
|
262
|
-
/** Warn once (not per request) so a broken hook can't be used to flood the logs. */
|
|
263
|
-
private
|
|
300
|
+
/** Warn once PER HOOK KIND (not per request) so a broken hook can't be used to flood the logs. */
|
|
301
|
+
private readonly warnedHooks;
|
|
264
302
|
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
265
303
|
loginPage(req: AuthPageRequest, res: AuthPageResponse, returnToQuery?: string, error?: string): string;
|
|
266
304
|
login(body: LoginFormBody, req: unknown, res: AuthPageResponse): Promise<string>;
|
|
267
305
|
logout(req: unknown, res: AuthPageResponse): string;
|
|
306
|
+
session(request: unknown, response: unknown): Promise<void>;
|
|
307
|
+
sessionRequiredPage(): string;
|
|
268
308
|
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
269
309
|
private redirectToLoginError;
|
|
270
310
|
private currentSession;
|
|
271
311
|
/**
|
|
272
|
-
* Run
|
|
273
|
-
* (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the
|
|
274
|
-
* stack-trace leak nor floods the logs.
|
|
312
|
+
* Run a host hook (`login` or `session`) defensively: a throw (sync or async) is treated as a
|
|
313
|
+
* denial (`null`) and warn-logged ONCE PER KIND, so a buggy/unreachable hook never 500s the
|
|
314
|
+
* endpoint into a stack-trace leak nor floods the logs on repeated bad attempts.
|
|
275
315
|
*/
|
|
276
|
-
private
|
|
316
|
+
private runHook;
|
|
277
317
|
private requireAuth;
|
|
278
318
|
}
|
|
279
319
|
|
|
@@ -355,21 +395,36 @@ interface AgentDashboardOptions<TReq = unknown> {
|
|
|
355
395
|
*/
|
|
356
396
|
approvalActorRef?: (req: TReq) => string | undefined;
|
|
357
397
|
/**
|
|
358
|
-
* Gate the console (SPA + API) behind a
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
398
|
+
* Gate the console (SPA + API) behind a built-in, signed session cookie. Two ways to mint it:
|
|
399
|
+
*
|
|
400
|
+
* - **Mode A (`session`, recommended)**: your host app already has its own auth (SSO/OIDC/
|
|
401
|
+
* whatever) — the host frontend, carrying that auth, POSTs to `<basePath>/auth/session`, your
|
|
402
|
+
* `session` hook validates the raw request and returns the session user, and this library
|
|
403
|
+
* mints its cookie from that. No credential this library understands ever exists; you keep
|
|
404
|
+
* your own identity provider as the source of truth. A page-level request with no valid
|
|
405
|
+
* session (and only Mode A configured) gets a small server-rendered instruction page telling
|
|
406
|
+
* the visitor to sign in through your host app, since there is no login page to redirect to.
|
|
407
|
+
* - **Mode B (`login`, standalone fallback)**: no host frontend/IdP to lean on — the console
|
|
408
|
+
* serves its own small, dependency-free, server-rendered login page (`GET
|
|
409
|
+
* <basePath>/auth/login`) and your `login` hook validates submitted username/password. A
|
|
410
|
+
* missing/invalid/expired session redirects a page-level request to that login page with
|
|
411
|
+
* `?returnTo=<original url>`.
|
|
412
|
+
*
|
|
413
|
+
* Either mode can be used alone, or both together (e.g. Mode A for normal use, Mode B as a
|
|
414
|
+
* break-glass fallback) — at least one is required, or `forRoot`/`forRootAsync` throws at boot
|
|
415
|
+
* (an un-mintable gate is a boot error, not a silently-open or silently-stuck console). An
|
|
416
|
+
* unauthenticated API call always gets a plain `401`, regardless of mode — the caller reads the
|
|
417
|
+
* status code, not HTML. Composes with `guards` — BOTH gates must pass. See
|
|
418
|
+
* `DashboardAuthOptions` for the `secret`/`ttl`/`session`/`login` shape.
|
|
364
419
|
*/
|
|
365
420
|
dashboardAuth?: DashboardAuthOptions;
|
|
366
421
|
}
|
|
367
422
|
/**
|
|
368
|
-
* Async variant of {@link AgentDashboardOptions}, for a `login` hook that needs injected
|
|
369
|
-
* (e.g. an EntityManager to check credentials against a DB). Everything else stays
|
|
370
|
-
* `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same
|
|
371
|
-
* `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s
|
|
372
|
-
* only the auth piece itself is resolved through DI.
|
|
423
|
+
* Async variant of {@link AgentDashboardOptions}, for a `session`/`login` hook that needs injected
|
|
424
|
+
* services (e.g. an EntityManager to check credentials against a DB). Everything else stays
|
|
425
|
+
* static/sync — `basePath`/`apiBasePath`/`guards` are needed at module-build time (the same
|
|
426
|
+
* constraint `@dudousxd/nestjs-telescope`'s and `@dudousxd/nestjs-media`'s own `forRootAsync`s
|
|
427
|
+
* document), so only the auth piece itself is resolved through DI.
|
|
373
428
|
*/
|
|
374
429
|
interface AgentDashboardAsyncOptions<TReq = unknown> {
|
|
375
430
|
basePath?: string;
|
|
@@ -404,13 +459,15 @@ declare class AgentApiModule {
|
|
|
404
459
|
}
|
|
405
460
|
/**
|
|
406
461
|
* Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE
|
|
407
|
-
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in
|
|
408
|
-
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set
|
|
462
|
+
* API at `apiBasePath` (default `<basePath>/api`), plus the built-in `dashboardAuth` routes at
|
|
463
|
+
* `<basePath>/auth/*` when {@link AgentDashboardOptions.dashboardAuth} is set — `POST
|
|
464
|
+
* <basePath>/auth/session` for Mode A (the host mints the session from its own auth) and/or `GET`/
|
|
465
|
+
* `POST <basePath>/auth/login` for Mode B (the built-in login screen).
|
|
409
466
|
*
|
|
410
467
|
* Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module
|
|
411
468
|
* (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the
|
|
412
469
|
* routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —
|
|
413
|
-
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` cookie
|
|
470
|
+
* see {@link AgentDashboardOptions.guards} — and/or the built-in `dashboardAuth` session cookie.
|
|
414
471
|
*
|
|
415
472
|
* Inertia hosts: the console is a full-page app, not an Inertia page. An in-app `<Link>` visit to
|
|
416
473
|
* `basePath` (an XHR carrying `X-Inertia`) is bounced with the protocol's own external-redirect
|
|
@@ -530,4 +587,4 @@ declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
|
|
|
530
587
|
*/
|
|
531
588
|
declare const DASHBOARD_AUTH: unique symbol;
|
|
532
589
|
|
|
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 };
|
|
590
|
+
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 SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
|