@dudousxd/nestjs-agent-dashboard 0.10.1 → 0.12.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 +24 -0
- package/dist/client/agent-client.d.ts +1 -0
- package/dist/client/agent-client.d.ts.map +1 -1
- package/dist/client/agent-client.js +4 -0
- package/dist/client/agent-client.js.map +1 -1
- package/dist/client/console-session.d.ts +63 -0
- package/dist/client/console-session.d.ts.map +1 -0
- package/dist/client/console-session.js +107 -0
- package/dist/client/console-session.js.map +1 -0
- package/dist/server/index.cjs +60 -10
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +49 -2
- package/dist/server/index.d.ts +49 -2
- package/dist/server/index.js +60 -10
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,6 +112,30 @@ AgentDashboardModule.forRoot({
|
|
|
112
112
|
|
|
113
113
|
Have your host frontend call `POST <basePath>/auth/session` once it knows the visitor is signed in — no body this library reads. Success is `204` with the `Set-Cookie`; a denial is `401` and no cookie is set. An unauthenticated PAGE navigation under Mode-A-only has nowhere to redirect to (there's no login form) — it's served a small, static instruction page at `<basePath>/auth/session-required` instead, telling the visitor to sign in through the host app and reload.
|
|
114
114
|
|
|
115
|
+
##### `unauthenticatedPage` — render that instruction page yourself
|
|
116
|
+
|
|
117
|
+
The built-in page cannot know who hosts the console, so it can only say "open this console from your application" in the abstract — it can't name your launcher, link to it, or look like the rest of your product. Pass `unauthenticatedPage` and the whole response is yours:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
AgentDashboardModule.forRoot({
|
|
121
|
+
dashboardAuth: {
|
|
122
|
+
secret: process.env.AGENT_DASHBOARD_SECRET,
|
|
123
|
+
session: (request) => resolveAdmin(request),
|
|
124
|
+
unauthenticatedPage: ({ request, response, basePath }) => {
|
|
125
|
+
// `request`/`response` are your platform's own objects (Express here). Render however you
|
|
126
|
+
// already render — a template engine, @dudousxd/nestjs-inertia, a plain string.
|
|
127
|
+
(response as Response).status(401).render('console-locked', { returnTo: basePath });
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The hook **owns** the response: it must write AND end it. It replaces what `<basePath>/auth/session-required` *contains*, not the flow that reaches it — a denied navigation is still redirected there.
|
|
134
|
+
|
|
135
|
+
It cannot open the console: it only ever runs on a request that has already been denied. If it throws, or returns without writing, the library logs one warning and falls back to the built-in page, so a broken page can't hang the request or turn a denial into a `500`. It is also not a mode — `unauthenticatedPage` alone still fails boot on the "at least one of `session` or `login`" check.
|
|
136
|
+
|
|
137
|
+
Under Mode B this route stays `404`: there is no session-required page to customise, because a denied navigation goes to the login form instead. To ship your own **login** UI, combine Mode A with this hook and `POST <basePath>/auth/session` from your page — that mint endpoint is the supported primitive for it.
|
|
138
|
+
|
|
115
139
|
#### Mode B — `login` (built-in login screen)
|
|
116
140
|
|
|
117
141
|
No host frontend/IdP to lean on — the console serves its own small, dependency-free, server-rendered login page. An unauthenticated page visit is redirected (302) to a built-in login form at `<basePath>/auth/login`.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Inclusive UTC day range, each `YYYY-MM-DD`. */
|
|
2
|
+
export { ConsoleSessionError, agentConsoleSessionUrl, agentConsoleUrl, mintAgentConsoleSession, openAgentConsole, type OpenConsoleOptions, } from './console-session.js';
|
|
2
3
|
export interface GovernanceRange {
|
|
3
4
|
fromDay: string;
|
|
4
5
|
toDay: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-client.d.ts","sourceRoot":"","sources":["../../src/client/agent-client.ts"],"names":[],"mappings":"AAIA,kDAAkD;
|
|
1
|
+
{"version":3,"file":"agent-client.d.ts","sourceRoot":"","sources":["../../src/client/agent-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Typed API client for the AI-gateway console. Self-contained: the row shapes are re-declared here
|
|
2
2
|
// (identical to core's `AgentGovernanceQueries` contract) so `@dudousxd/nestjs-agent-dashboard/client`
|
|
3
3
|
// is dependency-free for an external front-end that only wants to call the API.
|
|
4
|
+
/** Inclusive UTC day range, each `YYYY-MM-DD`. */
|
|
5
|
+
// Headless console-launcher primitives (path derivation + mint-then-navigate). Re-exported here
|
|
6
|
+
// because `./client` resolves to this file — see the package's `exports` map.
|
|
7
|
+
export { ConsoleSessionError, agentConsoleSessionUrl, agentConsoleUrl, mintAgentConsoleSession, openAgentConsole, } from './console-session.js';
|
|
4
8
|
function apiBase() {
|
|
5
9
|
if (typeof window !== 'undefined' && window.__AGENT_API__)
|
|
6
10
|
return window.__AGENT_API__;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-client.js","sourceRoot":"","sources":["../../src/client/agent-client.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,uGAAuG;AACvG,gFAAgF;
|
|
1
|
+
{"version":3,"file":"agent-client.js","sourceRoot":"","sources":["../../src/client/agent-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless client for opening the console from YOUR app.
|
|
3
|
+
*
|
|
4
|
+
* The console SPA is served at a literal path and knows nothing about your app's auth, so a plain
|
|
5
|
+
* browser navigation to it carries no identity. Mode A closes that gap: an XHR from inside your app
|
|
6
|
+
* — which DOES carry your auth — posts to the console's session endpoint, the `session` hook
|
|
7
|
+
* decides, and the library answers with its own signed cookie. The navigation that follows rides it.
|
|
8
|
+
*
|
|
9
|
+
* No UI here on purpose: you own the button, the page and the copy. This module owns the two things
|
|
10
|
+
* a host would otherwise have to rediscover — where the session endpoint actually lives, and how to
|
|
11
|
+
* call it without the failure mode below.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Where `POST` mints the console session cookie.
|
|
15
|
+
*
|
|
16
|
+
* Derived from `basePath` rather than hardcoded by the caller: this package owns the route (the
|
|
17
|
+
* auth controller is mounted relative to `basePath` by `RouterModule`), so a host that hardcodes it
|
|
18
|
+
* is guessing at something that can change under a version bump — with no compile error when it
|
|
19
|
+
* does, because the break only shows up as a 404 at runtime.
|
|
20
|
+
*/
|
|
21
|
+
export declare function agentConsoleSessionUrl(basePath?: string): string;
|
|
22
|
+
/** Where the console SPA itself is served. */
|
|
23
|
+
export declare function agentConsoleUrl(basePath?: string): string;
|
|
24
|
+
export interface OpenConsoleOptions {
|
|
25
|
+
/** Where the console is mounted. MUST match `AgentDashboardModule.forRoot({ basePath })`. */
|
|
26
|
+
basePath?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Headers for the mint request — in practice your app's `Authorization` header. A function (sync
|
|
29
|
+
* or async) is accepted so a token can be read at call time rather than captured at wiring time,
|
|
30
|
+
* which is what a refreshing token needs.
|
|
31
|
+
*/
|
|
32
|
+
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
|
|
33
|
+
/** Injected for tests and non-browser callers. Defaults to the global `fetch`. */
|
|
34
|
+
fetch?: typeof globalThis.fetch;
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
/**
|
|
37
|
+
* Performs the navigation after a successful mint. Defaults to `location.assign`. Override to
|
|
38
|
+
* route through your own router, or to open in a new tab.
|
|
39
|
+
*/
|
|
40
|
+
navigate?: (url: string) => void;
|
|
41
|
+
}
|
|
42
|
+
/** Thrown when the session could not be minted. Never thrown after a successful mint. */
|
|
43
|
+
export declare class ConsoleSessionError extends Error {
|
|
44
|
+
readonly url: string;
|
|
45
|
+
/** The HTTP status, or `undefined` when the request never produced one (network error). */
|
|
46
|
+
readonly status?: number | undefined;
|
|
47
|
+
constructor(message: string, url: string,
|
|
48
|
+
/** The HTTP status, or `undefined` when the request never produced one (network error). */
|
|
49
|
+
status?: number | undefined);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Mint the console session cookie. Resolves on success; throws {@link ConsoleSessionError} on
|
|
53
|
+
* refusal. Use this directly when you want to mint without navigating (a pre-flight check, or a
|
|
54
|
+
* link the user opens later).
|
|
55
|
+
*/
|
|
56
|
+
export declare function mintAgentConsoleSession(options?: OpenConsoleOptions): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Mint the session, then navigate to the console. Throws without navigating when the mint is
|
|
59
|
+
* refused, so a denied user gets a real error instead of landing on the console's
|
|
60
|
+
* "no session" page — which reads as a bug rather than a permission decision.
|
|
61
|
+
*/
|
|
62
|
+
export declare function openAgentConsole(options?: OpenConsoleOptions): Promise<void>;
|
|
63
|
+
//# sourceMappingURL=console-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-session.d.ts","sourceRoot":"","sources":["../../src/client/console-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,GAAE,MAA0B,GAAG,MAAM,CAEnF;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAA0B,GAAG,MAAM,CAE5E;AAED,MAAM,WAAW,kBAAkB;IACjC,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACnE,kFAAkF;IAClF,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,yFAAyF;AACzF,qBAAa,mBAAoB,SAAQ,KAAK;IAG1C,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;gBAHxB,OAAO,EAAE,MAAM,EACN,GAAG,EAAE,MAAM;IACpB,2FAA2F;IAClF,MAAM,CAAC,EAAE,MAAM,YAAA;CAK3B;AAOD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD7F;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless client for opening the console from YOUR app.
|
|
3
|
+
*
|
|
4
|
+
* The console SPA is served at a literal path and knows nothing about your app's auth, so a plain
|
|
5
|
+
* browser navigation to it carries no identity. Mode A closes that gap: an XHR from inside your app
|
|
6
|
+
* — which DOES carry your auth — posts to the console's session endpoint, the `session` hook
|
|
7
|
+
* decides, and the library answers with its own signed cookie. The navigation that follows rides it.
|
|
8
|
+
*
|
|
9
|
+
* No UI here on purpose: you own the button, the page and the copy. This module owns the two things
|
|
10
|
+
* a host would otherwise have to rediscover — where the session endpoint actually lives, and how to
|
|
11
|
+
* call it without the failure mode below.
|
|
12
|
+
*/
|
|
13
|
+
/** The mount default; matches `AgentDashboardModule.forRoot()`'s own default. */
|
|
14
|
+
const DEFAULT_BASE_PATH = '/ai-gateway';
|
|
15
|
+
function normalizeBasePath(basePath) {
|
|
16
|
+
const trimmed = basePath.trim().replace(/\/+$/, '');
|
|
17
|
+
if (trimmed === '')
|
|
18
|
+
return '';
|
|
19
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Where `POST` mints the console session cookie.
|
|
23
|
+
*
|
|
24
|
+
* Derived from `basePath` rather than hardcoded by the caller: this package owns the route (the
|
|
25
|
+
* auth controller is mounted relative to `basePath` by `RouterModule`), so a host that hardcodes it
|
|
26
|
+
* is guessing at something that can change under a version bump — with no compile error when it
|
|
27
|
+
* does, because the break only shows up as a 404 at runtime.
|
|
28
|
+
*/
|
|
29
|
+
export function agentConsoleSessionUrl(basePath = DEFAULT_BASE_PATH) {
|
|
30
|
+
return `${normalizeBasePath(basePath)}/auth/session`;
|
|
31
|
+
}
|
|
32
|
+
/** Where the console SPA itself is served. */
|
|
33
|
+
export function agentConsoleUrl(basePath = DEFAULT_BASE_PATH) {
|
|
34
|
+
return normalizeBasePath(basePath) || '/';
|
|
35
|
+
}
|
|
36
|
+
/** Thrown when the session could not be minted. Never thrown after a successful mint. */
|
|
37
|
+
export class ConsoleSessionError extends Error {
|
|
38
|
+
url;
|
|
39
|
+
status;
|
|
40
|
+
constructor(message, url,
|
|
41
|
+
/** The HTTP status, or `undefined` when the request never produced one (network error). */
|
|
42
|
+
status) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.url = url;
|
|
45
|
+
this.status = status;
|
|
46
|
+
this.name = 'ConsoleSessionError';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function resolveHeaders(headers) {
|
|
50
|
+
if (headers === undefined)
|
|
51
|
+
return {};
|
|
52
|
+
return typeof headers === 'function' ? await headers() : headers;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Mint the console session cookie. Resolves on success; throws {@link ConsoleSessionError} on
|
|
56
|
+
* refusal. Use this directly when you want to mint without navigating (a pre-flight check, or a
|
|
57
|
+
* link the user opens later).
|
|
58
|
+
*/
|
|
59
|
+
export async function mintAgentConsoleSession(options = {}) {
|
|
60
|
+
const url = agentConsoleSessionUrl(options.basePath);
|
|
61
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
62
|
+
if (typeof doFetch !== 'function') {
|
|
63
|
+
throw new ConsoleSessionError('No `fetch` available; pass one via `options.fetch`.', url);
|
|
64
|
+
}
|
|
65
|
+
let response;
|
|
66
|
+
try {
|
|
67
|
+
response = await doFetch(url, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
// The whole point: the response's Set-Cookie must stick, and the cookie must ride the
|
|
70
|
+
// navigation that follows.
|
|
71
|
+
credentials: 'include',
|
|
72
|
+
headers: await resolveHeaders(options.headers),
|
|
73
|
+
// Load-bearing, and the reason this helper exists rather than three lines at the call site.
|
|
74
|
+
// `fetch` FOLLOWS redirects by default, so an app whose auth layer rewrites a 401 into a
|
|
75
|
+
// "go to /signin" redirect makes this request resolve 200 against the sign-in HTML —
|
|
76
|
+
// `response.ok` reads true, the caller navigates, and the user lands in a console with no
|
|
77
|
+
// session, which looks exactly like a permissions bug. Handling the redirect explicitly turns
|
|
78
|
+
// that into a clear error instead of a silent false success.
|
|
79
|
+
redirect: 'manual',
|
|
80
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (cause) {
|
|
84
|
+
throw new ConsoleSessionError(`Could not reach the console session endpoint at ${url}: ${String(cause)}`, url);
|
|
85
|
+
}
|
|
86
|
+
// `redirect: 'manual'` surfaces differently per runtime: browsers give an opaque response
|
|
87
|
+
// (`type: 'opaqueredirect'`, status 0), Node/undici gives the real 3xx. Both mean the same thing.
|
|
88
|
+
const redirected = response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400);
|
|
89
|
+
if (redirected) {
|
|
90
|
+
throw new ConsoleSessionError(`The console session endpoint at ${url} answered with a redirect instead of minting a session. Something in front of it — usually an auth middleware or exception filter that rewrites 401s into a sign-in redirect — is intercepting the response. Exempt this path from that rewrite so the real status reaches this caller.`, url, response.status || undefined);
|
|
91
|
+
}
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new ConsoleSessionError(`The console refused to open (HTTP ${response.status}).`, url, response.status);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Mint the session, then navigate to the console. Throws without navigating when the mint is
|
|
98
|
+
* refused, so a denied user gets a real error instead of landing on the console's
|
|
99
|
+
* "no session" page — which reads as a bug rather than a permission decision.
|
|
100
|
+
*/
|
|
101
|
+
export async function openAgentConsole(options = {}) {
|
|
102
|
+
await mintAgentConsoleSession(options);
|
|
103
|
+
const target = agentConsoleUrl(options.basePath);
|
|
104
|
+
const navigate = options.navigate ?? ((url) => globalThis.location?.assign(url));
|
|
105
|
+
navigate(target);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=console-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-session.js","sourceRoot":"","sources":["../../src/client/console-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AACjF,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAExC,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB,iBAAiB;IACzE,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,eAAe,CAAC;AACvD,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,eAAe,CAAC,WAAmB,iBAAiB;IAClE,OAAO,iBAAiB,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;AAC5C,CAAC;AAqBD,yFAAyF;AACzF,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAGjC;IAEA;IAJX,YACE,OAAe,EACN,GAAW;IACpB,2FAA2F;IAClF,MAAe;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,QAAG,GAAH,GAAG,CAAQ;QAEX,WAAM,GAAN,MAAM,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,KAAK,UAAU,cAAc,CAAC,OAAsC;IAClE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,UAA8B,EAAE;IAC5E,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IAClD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,mBAAmB,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;IAC5F,CAAC;IAED,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;YAC5B,MAAM,EAAE,MAAM;YACd,sFAAsF;YACtF,2BAA2B;YAC3B,WAAW,EAAE,SAAS;YACtB,OAAO,EAAE,MAAM,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC;YAC9C,4FAA4F;YAC5F,yFAAyF;YACzF,qFAAqF;YACrF,0FAA0F;YAC1F,8FAA8F;YAC9F,6DAA6D;YAC7D,QAAQ,EAAE,QAAQ;YAClB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,mBAAmB,CAC3B,mDAAmD,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,EAC1E,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,0FAA0F;IAC1F,kGAAkG;IAClG,MAAM,UAAU,GACd,QAAQ,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC1F,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,mBAAmB,CAC3B,mCAAmC,GAAG,yRAAyR,EAC/T,GAAG,EACH,QAAQ,CAAC,MAAM,IAAI,SAAS,CAC7B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,mBAAmB,CAC3B,qCAAqC,QAAQ,CAAC,MAAM,IAAI,EACxD,GAAG,EACH,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAA8B,EAAE;IACrE,MAAM,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACzF,QAAQ,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC"}
|
package/dist/server/index.cjs
CHANGED
|
@@ -189,6 +189,20 @@ function resolveRawResponse(response) {
|
|
|
189
189
|
return null;
|
|
190
190
|
}
|
|
191
191
|
__name(resolveRawResponse, "resolveRawResponse");
|
|
192
|
+
function responseAlreadyWritten(response) {
|
|
193
|
+
const raw = resolveRawResponse(response);
|
|
194
|
+
return raw?.headersSent === true;
|
|
195
|
+
}
|
|
196
|
+
__name(responseAlreadyWritten, "responseAlreadyWritten");
|
|
197
|
+
function sendHtml(response, status, html) {
|
|
198
|
+
const raw = resolveRawResponse(response);
|
|
199
|
+
if (!raw) return;
|
|
200
|
+
raw.statusCode = status;
|
|
201
|
+
raw.setHeader("content-type", "text/html; charset=utf-8");
|
|
202
|
+
raw.setHeader("cache-control", "no-store, must-revalidate");
|
|
203
|
+
raw.end(html);
|
|
204
|
+
}
|
|
205
|
+
__name(sendHtml, "sendHtml");
|
|
192
206
|
function sendRedirect(response, status, location) {
|
|
193
207
|
const raw = resolveRawResponse(response);
|
|
194
208
|
if (!raw) return;
|
|
@@ -1426,10 +1440,31 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1426
1440
|
// Mode-A-only landing: the host mints the session, so there is nothing to submit here. Serves
|
|
1427
1441
|
// as the redirect target `DashboardAuthPageGuard` bounces to instead of `/auth/login`, which
|
|
1428
1442
|
// 404s under Mode A (see `loginPage` above).
|
|
1429
|
-
|
|
1443
|
+
//
|
|
1444
|
+
// Non-passthrough `@Res()` (unlike its sibling routes) because `dashboardAuth.unauthenticatedPage`
|
|
1445
|
+
// hands the response to the HOST, which writes and ends it itself — there is no return value for
|
|
1446
|
+
// Nest to send, and letting Nest also send one would double-write. The `Content-Type` /
|
|
1447
|
+
// `Cache-Control` this route used to carry as decorators move into `sendHtml` for the built-in
|
|
1448
|
+
// path; the host owns its own headers on the hook path.
|
|
1449
|
+
async sessionRequiredPage(req, res) {
|
|
1430
1450
|
const auth = this.requireAuth();
|
|
1431
1451
|
if (auth.modes.includes("login")) throw new import_common7.NotFoundException();
|
|
1432
|
-
|
|
1452
|
+
const hook = auth.unauthenticatedPage;
|
|
1453
|
+
if (hook) {
|
|
1454
|
+
try {
|
|
1455
|
+
await hook({
|
|
1456
|
+
request: req,
|
|
1457
|
+
response: res,
|
|
1458
|
+
basePath: this.basePath
|
|
1459
|
+
});
|
|
1460
|
+
if (responseAlreadyWritten(res)) return;
|
|
1461
|
+
this.warnHookOnce("unauthenticatedPage", "dashboardAuth.unauthenticatedPage returned without writing a response; falling back to the built-in page. The hook must write AND end the response it is given.");
|
|
1462
|
+
} catch (error) {
|
|
1463
|
+
this.warnHookOnce("unauthenticatedPage", `dashboardAuth.unauthenticatedPage threw; falling back to the built-in page. ${String(error)}`);
|
|
1464
|
+
if (responseAlreadyWritten(res)) return;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
sendHtml(res, 200, renderSessionRequiredPage());
|
|
1433
1468
|
}
|
|
1434
1469
|
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
1435
1470
|
redirectToLoginError(res, returnTo) {
|
|
@@ -1454,13 +1489,19 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1454
1489
|
try {
|
|
1455
1490
|
return await run() ?? null;
|
|
1456
1491
|
} catch (error) {
|
|
1457
|
-
|
|
1458
|
-
this.warnedHooks.add(kind);
|
|
1459
|
-
this.logger.warn(`AgentDashboardModule dashboardAuth ${kind} hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
|
|
1460
|
-
}
|
|
1492
|
+
this.warnHookOnce(kind, `AgentDashboardModule dashboardAuth ${kind} hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
|
|
1461
1493
|
return null;
|
|
1462
1494
|
}
|
|
1463
1495
|
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Warn once per hook kind for the life of the process, not once per request: a broken hook fires
|
|
1498
|
+
* on every denied navigation and would otherwise flood the logs.
|
|
1499
|
+
*/
|
|
1500
|
+
warnHookOnce(kind, message) {
|
|
1501
|
+
if (this.warnedHooks.has(kind)) return;
|
|
1502
|
+
this.warnedHooks.add(kind);
|
|
1503
|
+
this.logger.warn(message);
|
|
1504
|
+
}
|
|
1464
1505
|
requireAuth() {
|
|
1465
1506
|
if (!this.auth) throw new import_common7.NotFoundException();
|
|
1466
1507
|
return this.auth;
|
|
@@ -1529,11 +1570,14 @@ _ts_decorate4([
|
|
|
1529
1570
|
], AgentDashboardAuthController.prototype, "session", null);
|
|
1530
1571
|
_ts_decorate4([
|
|
1531
1572
|
(0, import_common7.Get)("session-required"),
|
|
1532
|
-
(0, import_common7.
|
|
1533
|
-
(0, import_common7.
|
|
1573
|
+
_ts_param4(0, (0, import_common7.Req)()),
|
|
1574
|
+
_ts_param4(1, (0, import_common7.Res)()),
|
|
1534
1575
|
_ts_metadata4("design:type", Function),
|
|
1535
|
-
_ts_metadata4("design:paramtypes", [
|
|
1536
|
-
|
|
1576
|
+
_ts_metadata4("design:paramtypes", [
|
|
1577
|
+
typeof AuthPageRequest === "undefined" ? Object : AuthPageRequest,
|
|
1578
|
+
Object
|
|
1579
|
+
]),
|
|
1580
|
+
_ts_metadata4("design:returntype", Promise)
|
|
1537
1581
|
], AgentDashboardAuthController.prototype, "sessionRequiredPage", null);
|
|
1538
1582
|
AgentDashboardAuthController = _ts_decorate4([
|
|
1539
1583
|
(0, import_common7.Controller)("auth"),
|
|
@@ -1863,6 +1907,9 @@ function resolveDashboardAuth(options) {
|
|
|
1863
1907
|
if (options.revalidate !== void 0 && typeof options.revalidate !== "function") {
|
|
1864
1908
|
throw new Error("AgentDashboardModule dashboardAuth: `revalidate` must be a function.");
|
|
1865
1909
|
}
|
|
1910
|
+
if (options.unauthenticatedPage !== void 0 && typeof options.unauthenticatedPage !== "function") {
|
|
1911
|
+
throw new Error("AgentDashboardModule dashboardAuth: `unauthenticatedPage` must be a function.");
|
|
1912
|
+
}
|
|
1866
1913
|
if (modes.length === 0) {
|
|
1867
1914
|
throw new Error("AgentDashboardModule dashboardAuth: at least one of `session` (the host mints the session from its own auth) or `login` (the built-in login screen) is required \u2014 otherwise the cookie can never be minted. Failing closed.");
|
|
1868
1915
|
}
|
|
@@ -1878,6 +1925,9 @@ function resolveDashboardAuth(options) {
|
|
|
1878
1925
|
} : {},
|
|
1879
1926
|
...options.revalidate !== void 0 ? {
|
|
1880
1927
|
revalidate: options.revalidate
|
|
1928
|
+
} : {},
|
|
1929
|
+
...options.unauthenticatedPage !== void 0 ? {
|
|
1930
|
+
unauthenticatedPage: options.unauthenticatedPage
|
|
1881
1931
|
} : {}
|
|
1882
1932
|
};
|
|
1883
1933
|
}
|