@dudousxd/nestjs-agent-dashboard 0.8.0 → 0.9.1

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.
@@ -29,38 +29,377 @@ __export(index_exports, {
29
29
  AGENT_PRICING_STORE: () => AGENT_PRICING_STORE,
30
30
  AgentApiController: () => AgentApiController,
31
31
  AgentApiModule: () => AgentApiModule,
32
+ AgentDashboardAuthController: () => AgentDashboardAuthController,
32
33
  AgentDashboardModule: () => AgentDashboardModule,
33
34
  AgentUiController: () => AgentUiController,
34
35
  DASHBOARD_API_PATH: () => DASHBOARD_API_PATH,
35
36
  DASHBOARD_APPROVAL_ACTOR_REF: () => DASHBOARD_APPROVAL_ACTOR_REF,
37
+ DASHBOARD_AUTH: () => DASHBOARD_AUTH,
36
38
  DASHBOARD_BASE_PATH: () => DASHBOARD_BASE_PATH,
37
39
  DashboardService: () => DashboardService,
38
40
  agentDashboardMountPaths: () => agentDashboardMountPaths,
39
- parsePriceInput: () => parsePriceInput
41
+ parsePriceInput: () => parsePriceInput,
42
+ resolveDashboardAuth: () => resolveDashboardAuth
40
43
  });
41
44
  module.exports = __toCommonJS(index_exports);
42
45
 
43
46
  // src/server/agent-api.controller.ts
44
- var import_common5 = require("@nestjs/common");
47
+ var import_common6 = require("@nestjs/common");
48
+
49
+ // src/server/auth/dashboard-auth.guard.ts
50
+ var import_common = require("@nestjs/common");
51
+
52
+ // src/server/tokens.ts
53
+ var AGENT_GOVERNANCE_QUERIES = Symbol.for("@dudousxd/nestjs-agent:governance-queries");
54
+ var AGENT_ACTOR_DIRECTORY = Symbol.for("@dudousxd/nestjs-agent:actor-directory");
55
+ var AGENT_PRICING_STORE = Symbol.for("@dudousxd/nestjs-agent:pricing-store");
56
+ var AGENT_APPROVAL_PORT = Symbol.for("@dudousxd/nestjs-agent:approval-port");
57
+ var AGENT_ACTOR_RESOLVER = Symbol.for("@dudousxd/nestjs-agent:actor-resolver");
58
+ var DASHBOARD_BASE_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:base-path");
59
+ var DASHBOARD_API_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:api-path");
60
+ var DASHBOARD_APPROVAL_ACTOR_REF = Symbol.for("@dudousxd/nestjs-agent-dashboard:approval-actor-ref");
61
+ var DASHBOARD_AUTH = Symbol.for("@dudousxd/nestjs-agent-dashboard:dashboard-auth");
62
+
63
+ // src/server/auth/cookie-header.ts
64
+ function parseCookieHeader(header) {
65
+ const cookies = {};
66
+ if (typeof header !== "string" || header === "") return cookies;
67
+ for (const segment of header.split(";")) {
68
+ const eq = segment.indexOf("=");
69
+ if (eq <= 0) continue;
70
+ const name = segment.slice(0, eq).trim();
71
+ if (name === "") continue;
72
+ let rawValue = segment.slice(eq + 1).trim();
73
+ if (rawValue.length >= 2 && rawValue.startsWith('"') && rawValue.endsWith('"')) {
74
+ rawValue = rawValue.slice(1, -1);
75
+ }
76
+ if (name in cookies) continue;
77
+ try {
78
+ cookies[name] = decodeURIComponent(rawValue);
79
+ } catch {
80
+ cookies[name] = rawValue;
81
+ }
82
+ }
83
+ return cookies;
84
+ }
85
+ __name(parseCookieHeader, "parseCookieHeader");
86
+ function serializeSetCookie(name, value, options) {
87
+ const parts = [
88
+ `${name}=${options.clear ? "" : encodeURIComponent(value)}`
89
+ ];
90
+ parts.push(`Path=${options.path}`);
91
+ parts.push("HttpOnly");
92
+ parts.push("SameSite=Lax");
93
+ if (options.secure) parts.push("Secure");
94
+ if (options.clear) {
95
+ parts.push("Max-Age=0");
96
+ parts.push("Expires=Thu, 01 Jan 1970 00:00:00 GMT");
97
+ } else {
98
+ parts.push(`Max-Age=${options.maxAgeSeconds}`);
99
+ }
100
+ return parts.join("; ");
101
+ }
102
+ __name(serializeSetCookie, "serializeSetCookie");
103
+
104
+ // src/server/auth/http-request.ts
105
+ function isRecord(value) {
106
+ return typeof value === "object" && value !== null;
107
+ }
108
+ __name(isRecord, "isRecord");
109
+ function readHeaders(request) {
110
+ if (!isRecord(request)) return {};
111
+ const headers = request.headers;
112
+ return isRecord(headers) ? headers : {};
113
+ }
114
+ __name(readHeaders, "readHeaders");
115
+ function headerToString(value) {
116
+ if (typeof value === "string") return value;
117
+ if (Array.isArray(value) && value.every((part) => typeof part === "string")) {
118
+ return value.join(",");
119
+ }
120
+ return void 0;
121
+ }
122
+ __name(headerToString, "headerToString");
123
+ function readCookieHeader(request) {
124
+ return headerToString(readHeaders(request).cookie);
125
+ }
126
+ __name(readCookieHeader, "readCookieHeader");
127
+ function isHttpsRequest(request) {
128
+ if (isRecord(request) && request.protocol === "https") return true;
129
+ const forwarded = headerToString(readHeaders(request)["x-forwarded-proto"]);
130
+ if (forwarded === void 0) return false;
131
+ return forwarded.split(",").map((proto) => proto.trim().toLowerCase()).includes("https");
132
+ }
133
+ __name(isHttpsRequest, "isHttpsRequest");
134
+ function readOriginalUrl(request) {
135
+ if (!isRecord(request)) return "/";
136
+ const originalUrl = request.originalUrl;
137
+ if (typeof originalUrl === "string" && originalUrl !== "") return originalUrl;
138
+ const url = request.url;
139
+ return typeof url === "string" && url !== "" ? url : "/";
140
+ }
141
+ __name(readOriginalUrl, "readOriginalUrl");
142
+ function attachSession(request, session) {
143
+ if (!isRecord(request)) return;
144
+ const target = request;
145
+ target.dashboardSession = session;
146
+ }
147
+ __name(attachSession, "attachSession");
148
+
149
+ // src/server/auth/response.ts
150
+ function isRecord2(value) {
151
+ return typeof value === "object" && value !== null;
152
+ }
153
+ __name(isRecord2, "isRecord");
154
+ function isHeaderCapableResponse(value) {
155
+ return isRecord2(value) && typeof value.getHeader === "function" && typeof value.setHeader === "function";
156
+ }
157
+ __name(isHeaderCapableResponse, "isHeaderCapableResponse");
158
+ function resolveHeaderCapableResponse(response) {
159
+ if (isHeaderCapableResponse(response)) return response;
160
+ if (isRecord2(response) && isHeaderCapableResponse(response.raw)) return response.raw;
161
+ return null;
162
+ }
163
+ __name(resolveHeaderCapableResponse, "resolveHeaderCapableResponse");
164
+ function existingSetCookies(response) {
165
+ const current = response.getHeader("set-cookie");
166
+ if (Array.isArray(current)) return current;
167
+ if (typeof current === "string") return [
168
+ current
169
+ ];
170
+ return [];
171
+ }
172
+ __name(existingSetCookies, "existingSetCookies");
173
+ function appendSetCookie(response, cookie) {
174
+ const raw = resolveHeaderCapableResponse(response);
175
+ if (!raw) return;
176
+ raw.setHeader("set-cookie", [
177
+ ...existingSetCookies(raw),
178
+ cookie
179
+ ]);
180
+ }
181
+ __name(appendSetCookie, "appendSetCookie");
182
+ function isRawNodeResponse(value) {
183
+ return isRecord2(value) && typeof value.getHeader === "function" && typeof value.setHeader === "function" && typeof value.end === "function";
184
+ }
185
+ __name(isRawNodeResponse, "isRawNodeResponse");
186
+ function resolveRawResponse(response) {
187
+ if (isRawNodeResponse(response)) return response;
188
+ if (isRecord2(response) && isRawNodeResponse(response.raw)) return response.raw;
189
+ return null;
190
+ }
191
+ __name(resolveRawResponse, "resolveRawResponse");
192
+ function sendRedirect(response, status, location) {
193
+ const raw = resolveRawResponse(response);
194
+ if (!raw) return;
195
+ raw.statusCode = status;
196
+ raw.setHeader("location", location);
197
+ raw.end();
198
+ }
199
+ __name(sendRedirect, "sendRedirect");
200
+
201
+ // src/server/auth/session-cookie.ts
202
+ var import_node_crypto = require("crypto");
203
+ var EXP_GRACE_MS = 3e4;
204
+ function base64urlEncode(value) {
205
+ return Buffer.from(value, "utf8").toString("base64url");
206
+ }
207
+ __name(base64urlEncode, "base64urlEncode");
208
+ function base64urlDecode(value) {
209
+ return Buffer.from(value, "base64url").toString("utf8");
210
+ }
211
+ __name(base64urlDecode, "base64urlDecode");
212
+ function hmac(secret, payload) {
213
+ return (0, import_node_crypto.createHmac)("sha256", secret).update(payload).digest("base64url");
214
+ }
215
+ __name(hmac, "hmac");
216
+ function signSessionCookie(user, options) {
217
+ const issuedAt = options.now ?? Date.now();
218
+ const session = {
219
+ sub: user.id,
220
+ ...user.name !== void 0 ? {
221
+ name: user.name
222
+ } : {},
223
+ roles: user.roles ?? [],
224
+ iat: issuedAt,
225
+ exp: issuedAt + options.ttlMs
226
+ };
227
+ const encodedPayload = base64urlEncode(JSON.stringify(session));
228
+ const signature = hmac(options.secret, encodedPayload);
229
+ return `${encodedPayload}.${signature}`;
230
+ }
231
+ __name(signSessionCookie, "signSessionCookie");
232
+ function isSessionPayload(value) {
233
+ if (typeof value !== "object" || value === null) return false;
234
+ const record = {
235
+ ...value
236
+ };
237
+ if (typeof record.sub !== "string") return false;
238
+ if (record.name !== void 0 && typeof record.name !== "string") return false;
239
+ if (!Array.isArray(record.roles)) return false;
240
+ if (!record.roles.every((role) => typeof role === "string")) return false;
241
+ if (typeof record.iat !== "number" || !Number.isFinite(record.iat)) return false;
242
+ if (typeof record.exp !== "number" || !Number.isFinite(record.exp)) return false;
243
+ return true;
244
+ }
245
+ __name(isSessionPayload, "isSessionPayload");
246
+ function verifySessionCookie(value, options) {
247
+ try {
248
+ const dot = value.indexOf(".");
249
+ if (dot <= 0 || dot === value.length - 1) return null;
250
+ const encodedPayload = value.slice(0, dot);
251
+ const providedSignature = value.slice(dot + 1);
252
+ const expectedSignature = hmac(options.secret, encodedPayload);
253
+ const provided = Buffer.from(providedSignature, "base64url");
254
+ const expected = Buffer.from(expectedSignature, "base64url");
255
+ if (provided.length !== expected.length) return null;
256
+ if (!(0, import_node_crypto.timingSafeEqual)(provided, expected)) return null;
257
+ const decoded = JSON.parse(base64urlDecode(encodedPayload));
258
+ if (!isSessionPayload(decoded)) return null;
259
+ const now = options.now ?? Date.now();
260
+ if (now > decoded.exp + EXP_GRACE_MS) return null;
261
+ const session = {
262
+ sub: decoded.sub,
263
+ ...decoded.name !== void 0 ? {
264
+ name: decoded.name
265
+ } : {},
266
+ roles: decoded.roles,
267
+ iat: decoded.iat,
268
+ exp: decoded.exp
269
+ };
270
+ return session;
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+ __name(verifySessionCookie, "verifySessionCookie");
276
+
277
+ // src/server/auth/session-cookie-io.ts
278
+ var SESSION_COOKIE_NAME = "agent_dashboard_session";
279
+ var COOKIE_PATH = "/";
280
+ function issueSessionCookie(user, context) {
281
+ const value = signSessionCookie(user, {
282
+ secret: context.auth.secret,
283
+ ttlMs: context.auth.ttlMs,
284
+ ...context.now !== void 0 ? {
285
+ now: context.now
286
+ } : {}
287
+ });
288
+ const cookie = serializeSetCookie(SESSION_COOKIE_NAME, value, {
289
+ path: COOKIE_PATH,
290
+ maxAgeSeconds: Math.floor(context.auth.ttlMs / 1e3),
291
+ secure: isHttpsRequest(context.request)
292
+ });
293
+ appendSetCookie(context.response, cookie);
294
+ }
295
+ __name(issueSessionCookie, "issueSessionCookie");
296
+ function clearSessionCookie(context) {
297
+ const cookie = serializeSetCookie(SESSION_COOKIE_NAME, "", {
298
+ path: COOKIE_PATH,
299
+ maxAgeSeconds: 0,
300
+ secure: isHttpsRequest(context.request),
301
+ clear: true
302
+ });
303
+ appendSetCookie(context.response, cookie);
304
+ }
305
+ __name(clearSessionCookie, "clearSessionCookie");
306
+
307
+ // src/server/auth/dashboard-auth.guard.ts
308
+ function _ts_decorate(decorators, target, key, desc) {
309
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
310
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
311
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
312
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
313
+ }
314
+ __name(_ts_decorate, "_ts_decorate");
315
+ function _ts_metadata(k, v) {
316
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
317
+ }
318
+ __name(_ts_metadata, "_ts_metadata");
319
+ function _ts_param(paramIndex, decorator) {
320
+ return function(target, key) {
321
+ decorator(target, key, paramIndex);
322
+ };
323
+ }
324
+ __name(_ts_param, "_ts_param");
325
+ var DashboardAuthGuard = class {
326
+ static {
327
+ __name(this, "DashboardAuthGuard");
328
+ }
329
+ auth;
330
+ constructor(auth) {
331
+ this.auth = auth;
332
+ }
333
+ canActivate(context) {
334
+ if (!this.auth) return true;
335
+ const http = context.switchToHttp();
336
+ const request = http.getRequest();
337
+ const session = this.verifyRequestSession(request);
338
+ if (!session) throw new import_common.UnauthorizedException();
339
+ attachSession(request, session);
340
+ this.maybeRenew(http.getResponse(), request, session);
341
+ return true;
342
+ }
343
+ verifyRequestSession(request) {
344
+ const auth = this.auth;
345
+ if (!auth) return null;
346
+ const cookieValue = parseCookieHeader(readCookieHeader(request))[SESSION_COOKIE_NAME];
347
+ if (cookieValue === void 0) return null;
348
+ return verifySessionCookie(cookieValue, {
349
+ secret: auth.secret
350
+ });
351
+ }
352
+ /**
353
+ * Sliding renewal: a valid cookie past 50% of its TTL is transparently re-issued on the
354
+ * response, so an active user never gets logged out mid-session.
355
+ */
356
+ maybeRenew(response, request, session) {
357
+ const auth = this.auth;
358
+ if (!auth) return;
359
+ const now = Date.now();
360
+ if (now - session.iat <= auth.ttlMs / 2) return;
361
+ issueSessionCookie({
362
+ id: session.sub,
363
+ ...session.name !== void 0 ? {
364
+ name: session.name
365
+ } : {},
366
+ roles: session.roles
367
+ }, {
368
+ auth,
369
+ request,
370
+ response,
371
+ now
372
+ });
373
+ }
374
+ };
375
+ DashboardAuthGuard = _ts_decorate([
376
+ (0, import_common.Injectable)(),
377
+ _ts_param(0, (0, import_common.Optional)()),
378
+ _ts_param(0, (0, import_common.Inject)(DASHBOARD_AUTH)),
379
+ _ts_metadata("design:type", Function),
380
+ _ts_metadata("design:paramtypes", [
381
+ Object
382
+ ])
383
+ ], DashboardAuthGuard);
45
384
 
46
385
  // src/server/dashboard.service.ts
47
386
  var import_node_diagnostics_channel = require("diagnostics_channel");
48
387
  var import_nestjs_diagnostics = require("@dudousxd/nestjs-diagnostics");
49
- var import_common3 = require("@nestjs/common");
388
+ var import_common4 = require("@nestjs/common");
50
389
  var import_rxjs = require("rxjs");
51
390
 
52
391
  // src/server/parse-approval-decision.ts
53
- var import_common = require("@nestjs/common");
392
+ var import_common2 = require("@nestjs/common");
54
393
  function parseApprovalDecision(body) {
55
394
  if (typeof body !== "object" || body === null) {
56
- throw new import_common.BadRequestException("Expected a JSON object body.");
395
+ throw new import_common2.BadRequestException("Expected a JSON object body.");
57
396
  }
58
397
  const { approved, reason } = body;
59
398
  if (typeof approved !== "boolean") {
60
- throw new import_common.BadRequestException('"approved" must be a boolean.');
399
+ throw new import_common2.BadRequestException('"approved" must be a boolean.');
61
400
  }
62
401
  if (reason !== void 0 && typeof reason !== "string") {
63
- throw new import_common.BadRequestException('"reason" must be a string when present.');
402
+ throw new import_common2.BadRequestException('"reason" must be a string when present.');
64
403
  }
65
404
  return {
66
405
  approved,
@@ -72,26 +411,26 @@ function parseApprovalDecision(body) {
72
411
  __name(parseApprovalDecision, "parseApprovalDecision");
73
412
 
74
413
  // src/server/parse-price-input.ts
75
- var import_common2 = require("@nestjs/common");
414
+ var import_common3 = require("@nestjs/common");
76
415
  function parsePriceInput(body) {
77
416
  if (typeof body !== "object" || body === null) {
78
- throw new import_common2.BadRequestException("Expected a JSON object body.");
417
+ throw new import_common3.BadRequestException("Expected a JSON object body.");
79
418
  }
80
419
  const { modelId, inputPricePer1m, outputPricePer1m, cacheWritePricePer1m, cacheReadPricePer1m } = body;
81
420
  if (typeof modelId !== "string" || modelId.trim().length === 0) {
82
- throw new import_common2.BadRequestException('"modelId" must be a non-empty string.');
421
+ throw new import_common3.BadRequestException('"modelId" must be a non-empty string.');
83
422
  }
84
423
  if (!isFiniteNonNegative(inputPricePer1m)) {
85
- throw new import_common2.BadRequestException('"inputPricePer1m" must be a non-negative number.');
424
+ throw new import_common3.BadRequestException('"inputPricePer1m" must be a non-negative number.');
86
425
  }
87
426
  if (!isFiniteNonNegative(outputPricePer1m)) {
88
- throw new import_common2.BadRequestException('"outputPricePer1m" must be a non-negative number.');
427
+ throw new import_common3.BadRequestException('"outputPricePer1m" must be a non-negative number.');
89
428
  }
90
429
  if (cacheWritePricePer1m !== void 0 && !isFiniteNonNegative(cacheWritePricePer1m)) {
91
- throw new import_common2.BadRequestException('"cacheWritePricePer1m" must be a non-negative number when present.');
430
+ throw new import_common3.BadRequestException('"cacheWritePricePer1m" must be a non-negative number when present.');
92
431
  }
93
432
  if (cacheReadPricePer1m !== void 0 && !isFiniteNonNegative(cacheReadPricePer1m)) {
94
- throw new import_common2.BadRequestException('"cacheReadPricePer1m" must be a non-negative number when present.');
433
+ throw new import_common3.BadRequestException('"cacheReadPricePer1m" must be a non-negative number when present.');
95
434
  }
96
435
  return {
97
436
  modelId,
@@ -111,34 +450,24 @@ function isFiniteNonNegative(value) {
111
450
  }
112
451
  __name(isFiniteNonNegative, "isFiniteNonNegative");
113
452
 
114
- // src/server/tokens.ts
115
- var AGENT_GOVERNANCE_QUERIES = Symbol.for("@dudousxd/nestjs-agent:governance-queries");
116
- var AGENT_ACTOR_DIRECTORY = Symbol.for("@dudousxd/nestjs-agent:actor-directory");
117
- var AGENT_PRICING_STORE = Symbol.for("@dudousxd/nestjs-agent:pricing-store");
118
- var AGENT_APPROVAL_PORT = Symbol.for("@dudousxd/nestjs-agent:approval-port");
119
- var AGENT_ACTOR_RESOLVER = Symbol.for("@dudousxd/nestjs-agent:actor-resolver");
120
- var DASHBOARD_BASE_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:base-path");
121
- var DASHBOARD_API_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:api-path");
122
- var DASHBOARD_APPROVAL_ACTOR_REF = Symbol.for("@dudousxd/nestjs-agent-dashboard:approval-actor-ref");
123
-
124
453
  // src/server/dashboard.service.ts
125
- function _ts_decorate(decorators, target, key, desc) {
454
+ function _ts_decorate2(decorators, target, key, desc) {
126
455
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
127
456
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
128
457
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
129
458
  return c > 3 && r && Object.defineProperty(target, key, r), r;
130
459
  }
131
- __name(_ts_decorate, "_ts_decorate");
132
- function _ts_metadata(k, v) {
460
+ __name(_ts_decorate2, "_ts_decorate");
461
+ function _ts_metadata2(k, v) {
133
462
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
134
463
  }
135
- __name(_ts_metadata, "_ts_metadata");
136
- function _ts_param(paramIndex, decorator) {
464
+ __name(_ts_metadata2, "_ts_metadata");
465
+ function _ts_param2(paramIndex, decorator) {
137
466
  return function(target, key) {
138
467
  decorator(target, key, paramIndex);
139
468
  };
140
469
  }
141
- __name(_ts_param, "_ts_param");
470
+ __name(_ts_param2, "_ts_param");
142
471
  var PRICING_STORE_UNBOUND_MESSAGE = "Pricing CRUD is unavailable: no AGENT_PRICING_STORE is bound. Bind a pricing store (e.g. MikroOrmPricingStore from @dudousxd/nestjs-agent-store-mikro-orm) to enable it.";
143
472
  var APPROVAL_PORT_UNBOUND_MESSAGE = "Approve/reject is unavailable: no AGENT_APPROVAL_PORT is bound. Import AgentModule from @dudousxd/nestjs-agent alongside this dashboard to enable it \u2014 the approvals inbox stays read-only until then.";
144
473
  var AGENT_EVENTS = [
@@ -235,7 +564,7 @@ var DashboardService = class {
235
564
  */
236
565
  async decideApproval(toolCallId, body, executedByRef) {
237
566
  if (this.approvalPort === void 0) {
238
- throw new import_common3.NotImplementedException(APPROVAL_PORT_UNBOUND_MESSAGE);
567
+ throw new import_common4.NotImplementedException(APPROVAL_PORT_UNBOUND_MESSAGE);
239
568
  }
240
569
  const decision = parseApprovalDecision(body);
241
570
  const opts = executedByRef !== void 0 ? {
@@ -296,7 +625,7 @@ var DashboardService = class {
296
625
  /** Current price row per model, for the pricing tab. 501s when no `AGENT_PRICING_STORE` is bound. */
297
626
  async listPrices() {
298
627
  if (this.pricingStore === void 0) {
299
- throw new import_common3.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
628
+ throw new import_common4.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
300
629
  }
301
630
  return this.pricingStore.listCurrentPrices();
302
631
  }
@@ -307,7 +636,7 @@ var DashboardService = class {
307
636
  */
308
637
  async upsertPrice(body) {
309
638
  if (this.pricingStore === void 0) {
310
- throw new import_common3.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
639
+ throw new import_common4.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
311
640
  }
312
641
  await this.pricingStore.upsertModelPrice(parsePriceInput(body));
313
642
  }
@@ -342,17 +671,17 @@ var DashboardService = class {
342
671
  });
343
672
  }
344
673
  };
345
- DashboardService = _ts_decorate([
346
- (0, import_common3.Injectable)(),
347
- _ts_param(0, (0, import_common3.Inject)(AGENT_GOVERNANCE_QUERIES)),
348
- _ts_param(1, (0, import_common3.Optional)()),
349
- _ts_param(1, (0, import_common3.Inject)(AGENT_ACTOR_DIRECTORY)),
350
- _ts_param(2, (0, import_common3.Optional)()),
351
- _ts_param(2, (0, import_common3.Inject)(AGENT_PRICING_STORE)),
352
- _ts_param(3, (0, import_common3.Optional)()),
353
- _ts_param(3, (0, import_common3.Inject)(AGENT_APPROVAL_PORT)),
354
- _ts_metadata("design:type", Function),
355
- _ts_metadata("design:paramtypes", [
674
+ DashboardService = _ts_decorate2([
675
+ (0, import_common4.Injectable)(),
676
+ _ts_param2(0, (0, import_common4.Inject)(AGENT_GOVERNANCE_QUERIES)),
677
+ _ts_param2(1, (0, import_common4.Optional)()),
678
+ _ts_param2(1, (0, import_common4.Inject)(AGENT_ACTOR_DIRECTORY)),
679
+ _ts_param2(2, (0, import_common4.Optional)()),
680
+ _ts_param2(2, (0, import_common4.Inject)(AGENT_PRICING_STORE)),
681
+ _ts_param2(3, (0, import_common4.Optional)()),
682
+ _ts_param2(3, (0, import_common4.Inject)(AGENT_APPROVAL_PORT)),
683
+ _ts_metadata2("design:type", Function),
684
+ _ts_metadata2("design:paramtypes", [
356
685
  typeof AgentGovernanceQueries === "undefined" ? Object : AgentGovernanceQueries,
357
686
  typeof ActorDirectory === "undefined" ? Object : ActorDirectory,
358
687
  typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
@@ -361,7 +690,7 @@ DashboardService = _ts_decorate([
361
690
  ], DashboardService);
362
691
 
363
692
  // src/server/parse-page-query.ts
364
- var import_common4 = require("@nestjs/common");
693
+ var import_common5 = require("@nestjs/common");
365
694
  var ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
366
695
  function parsePageNumber(value) {
367
696
  const parsed = value === void 0 ? Number.NaN : Number.parseInt(value, 10);
@@ -372,7 +701,7 @@ __name(parsePageNumber, "parsePageNumber");
372
701
  function assertKnownFields(raw, allowed) {
373
702
  for (const field of Object.keys(raw)) {
374
703
  if (!allowed.includes(field)) {
375
- throw new import_common4.BadRequestException(`Unknown where field "${field}".`);
704
+ throw new import_common5.BadRequestException(`Unknown where field "${field}".`);
376
705
  }
377
706
  }
378
707
  }
@@ -381,7 +710,7 @@ function assertDayFields(raw, dayFields) {
381
710
  for (const field of dayFields) {
382
711
  const value = raw[field];
383
712
  if (value !== void 0 && !ISO_DAY.test(value)) {
384
- throw new import_common4.BadRequestException(`"where[${field}]" must be YYYY-MM-DD.`);
713
+ throw new import_common5.BadRequestException(`"where[${field}]" must be YYYY-MM-DD.`);
385
714
  }
386
715
  }
387
716
  }
@@ -482,23 +811,23 @@ function parseRunWhere(raw) {
482
811
  __name(parseRunWhere, "parseRunWhere");
483
812
 
484
813
  // src/server/agent-api.controller.ts
485
- function _ts_decorate2(decorators, target, key, desc) {
814
+ function _ts_decorate3(decorators, target, key, desc) {
486
815
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
487
816
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
488
817
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
489
818
  return c > 3 && r && Object.defineProperty(target, key, r), r;
490
819
  }
491
- __name(_ts_decorate2, "_ts_decorate");
492
- function _ts_metadata2(k, v) {
820
+ __name(_ts_decorate3, "_ts_decorate");
821
+ function _ts_metadata3(k, v) {
493
822
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
494
823
  }
495
- __name(_ts_metadata2, "_ts_metadata");
496
- function _ts_param2(paramIndex, decorator) {
824
+ __name(_ts_metadata3, "_ts_metadata");
825
+ function _ts_param3(paramIndex, decorator) {
497
826
  return function(target, key) {
498
827
  decorator(target, key, paramIndex);
499
828
  };
500
829
  }
501
- __name(_ts_param2, "_ts_param");
830
+ __name(_ts_param3, "_ts_param");
502
831
  var DAY_MS = 864e5;
503
832
  var ISO_DAY2 = /^\d{4}-\d{2}-\d{2}$/;
504
833
  function utcDay(daysAgo) {
@@ -659,175 +988,473 @@ var AgentApiController = class {
659
988
  return this.dashboard.streamEvents();
660
989
  }
661
990
  };
662
- _ts_decorate2([
663
- (0, import_common5.Get)("spend"),
664
- _ts_param2(0, (0, import_common5.Query)("from")),
665
- _ts_param2(1, (0, import_common5.Query)("to")),
666
- _ts_metadata2("design:type", Function),
667
- _ts_metadata2("design:paramtypes", [
991
+ _ts_decorate3([
992
+ (0, import_common6.Get)("spend"),
993
+ _ts_param3(0, (0, import_common6.Query)("from")),
994
+ _ts_param3(1, (0, import_common6.Query)("to")),
995
+ _ts_metadata3("design:type", Function),
996
+ _ts_metadata3("design:paramtypes", [
668
997
  String,
669
998
  String
670
999
  ]),
671
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1000
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
672
1001
  ], AgentApiController.prototype, "spend", null);
673
- _ts_decorate2([
674
- (0, import_common5.Get)("top-threads"),
675
- _ts_param2(0, (0, import_common5.Query)("from")),
676
- _ts_param2(1, (0, import_common5.Query)("to")),
677
- _ts_param2(2, (0, import_common5.Query)("limit")),
678
- _ts_metadata2("design:type", Function),
679
- _ts_metadata2("design:paramtypes", [
1002
+ _ts_decorate3([
1003
+ (0, import_common6.Get)("top-threads"),
1004
+ _ts_param3(0, (0, import_common6.Query)("from")),
1005
+ _ts_param3(1, (0, import_common6.Query)("to")),
1006
+ _ts_param3(2, (0, import_common6.Query)("limit")),
1007
+ _ts_metadata3("design:type", Function),
1008
+ _ts_metadata3("design:paramtypes", [
680
1009
  String,
681
1010
  String,
682
1011
  String
683
1012
  ]),
684
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1013
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
685
1014
  ], AgentApiController.prototype, "topThreads", null);
686
- _ts_decorate2([
687
- (0, import_common5.Get)("reliability"),
688
- _ts_param2(0, (0, import_common5.Query)("from")),
689
- _ts_param2(1, (0, import_common5.Query)("to")),
690
- _ts_metadata2("design:type", Function),
691
- _ts_metadata2("design:paramtypes", [
1015
+ _ts_decorate3([
1016
+ (0, import_common6.Get)("reliability"),
1017
+ _ts_param3(0, (0, import_common6.Query)("from")),
1018
+ _ts_param3(1, (0, import_common6.Query)("to")),
1019
+ _ts_metadata3("design:type", Function),
1020
+ _ts_metadata3("design:paramtypes", [
692
1021
  String,
693
1022
  String
694
1023
  ]),
695
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1024
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
696
1025
  ], AgentApiController.prototype, "reliability", null);
697
- _ts_decorate2([
698
- (0, import_common5.Get)("runs"),
699
- _ts_param2(0, (0, import_common5.Query)("limit")),
700
- _ts_metadata2("design:type", Function),
701
- _ts_metadata2("design:paramtypes", [
1026
+ _ts_decorate3([
1027
+ (0, import_common6.Get)("runs"),
1028
+ _ts_param3(0, (0, import_common6.Query)("limit")),
1029
+ _ts_metadata3("design:type", Function),
1030
+ _ts_metadata3("design:paramtypes", [
702
1031
  String
703
1032
  ]),
704
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1033
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
705
1034
  ], AgentApiController.prototype, "runs", null);
706
- _ts_decorate2([
707
- (0, import_common5.Get)("runs-page"),
708
- _ts_param2(0, (0, import_common5.Query)("page")),
709
- _ts_param2(1, (0, import_common5.Query)("limit")),
710
- _ts_param2(2, (0, import_common5.Query)("where")),
711
- _ts_metadata2("design:type", Function),
712
- _ts_metadata2("design:paramtypes", [
1035
+ _ts_decorate3([
1036
+ (0, import_common6.Get)("runs-page"),
1037
+ _ts_param3(0, (0, import_common6.Query)("page")),
1038
+ _ts_param3(1, (0, import_common6.Query)("limit")),
1039
+ _ts_param3(2, (0, import_common6.Query)("where")),
1040
+ _ts_metadata3("design:type", Function),
1041
+ _ts_metadata3("design:paramtypes", [
713
1042
  String,
714
1043
  String,
715
1044
  typeof Record === "undefined" ? Object : Record
716
1045
  ]),
717
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1046
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
718
1047
  ], AgentApiController.prototype, "runsPage", null);
719
- _ts_decorate2([
720
- (0, import_common5.Get)("tool-calls"),
721
- _ts_param2(0, (0, import_common5.Query)("limit")),
722
- _ts_metadata2("design:type", Function),
723
- _ts_metadata2("design:paramtypes", [
1048
+ _ts_decorate3([
1049
+ (0, import_common6.Get)("tool-calls"),
1050
+ _ts_param3(0, (0, import_common6.Query)("limit")),
1051
+ _ts_metadata3("design:type", Function),
1052
+ _ts_metadata3("design:paramtypes", [
724
1053
  String
725
1054
  ]),
726
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1055
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
727
1056
  ], AgentApiController.prototype, "toolCalls", null);
728
- _ts_decorate2([
729
- (0, import_common5.Get)("tool-calls-page"),
730
- _ts_param2(0, (0, import_common5.Query)("page")),
731
- _ts_param2(1, (0, import_common5.Query)("limit")),
732
- _ts_param2(2, (0, import_common5.Query)("where")),
733
- _ts_metadata2("design:type", Function),
734
- _ts_metadata2("design:paramtypes", [
1057
+ _ts_decorate3([
1058
+ (0, import_common6.Get)("tool-calls-page"),
1059
+ _ts_param3(0, (0, import_common6.Query)("page")),
1060
+ _ts_param3(1, (0, import_common6.Query)("limit")),
1061
+ _ts_param3(2, (0, import_common6.Query)("where")),
1062
+ _ts_metadata3("design:type", Function),
1063
+ _ts_metadata3("design:paramtypes", [
735
1064
  String,
736
1065
  String,
737
1066
  typeof Record === "undefined" ? Object : Record
738
1067
  ]),
739
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1068
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
740
1069
  ], AgentApiController.prototype, "toolCallsPage", null);
741
- _ts_decorate2([
742
- (0, import_common5.Get)("approvals"),
743
- _ts_param2(0, (0, import_common5.Query)("limit")),
744
- _ts_metadata2("design:type", Function),
745
- _ts_metadata2("design:paramtypes", [
1070
+ _ts_decorate3([
1071
+ (0, import_common6.Get)("approvals"),
1072
+ _ts_param3(0, (0, import_common6.Query)("limit")),
1073
+ _ts_metadata3("design:type", Function),
1074
+ _ts_metadata3("design:paramtypes", [
746
1075
  String
747
1076
  ]),
748
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1077
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
749
1078
  ], AgentApiController.prototype, "approvals", null);
750
- _ts_decorate2([
751
- (0, import_common5.Post)("approvals/:toolCallId"),
752
- (0, import_common5.HttpCode)(204),
753
- _ts_param2(0, (0, import_common5.Param)("toolCallId")),
754
- _ts_param2(1, (0, import_common5.Body)()),
755
- _ts_param2(2, (0, import_common5.Req)()),
756
- _ts_metadata2("design:type", Function),
757
- _ts_metadata2("design:paramtypes", [
1079
+ _ts_decorate3([
1080
+ (0, import_common6.Post)("approvals/:toolCallId"),
1081
+ (0, import_common6.HttpCode)(204),
1082
+ _ts_param3(0, (0, import_common6.Param)("toolCallId")),
1083
+ _ts_param3(1, (0, import_common6.Body)()),
1084
+ _ts_param3(2, (0, import_common6.Req)()),
1085
+ _ts_metadata3("design:type", Function),
1086
+ _ts_metadata3("design:paramtypes", [
758
1087
  String,
759
1088
  Object,
760
1089
  Object
761
1090
  ]),
762
- _ts_metadata2("design:returntype", Promise)
1091
+ _ts_metadata3("design:returntype", Promise)
763
1092
  ], AgentApiController.prototype, "decideApproval", null);
764
- _ts_decorate2([
765
- (0, import_common5.Get)("tools"),
766
- _ts_param2(0, (0, import_common5.Query)("from")),
767
- _ts_param2(1, (0, import_common5.Query)("to")),
768
- _ts_metadata2("design:type", Function),
769
- _ts_metadata2("design:paramtypes", [
1093
+ _ts_decorate3([
1094
+ (0, import_common6.Get)("tools"),
1095
+ _ts_param3(0, (0, import_common6.Query)("from")),
1096
+ _ts_param3(1, (0, import_common6.Query)("to")),
1097
+ _ts_metadata3("design:type", Function),
1098
+ _ts_metadata3("design:paramtypes", [
770
1099
  String,
771
1100
  String
772
1101
  ]),
773
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1102
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
774
1103
  ], AgentApiController.prototype, "tools", null);
775
- _ts_decorate2([
776
- (0, import_common5.Get)("threads"),
777
- _ts_param2(0, (0, import_common5.Query)("limit")),
778
- _ts_metadata2("design:type", Function),
779
- _ts_metadata2("design:paramtypes", [
1104
+ _ts_decorate3([
1105
+ (0, import_common6.Get)("threads"),
1106
+ _ts_param3(0, (0, import_common6.Query)("limit")),
1107
+ _ts_metadata3("design:type", Function),
1108
+ _ts_metadata3("design:paramtypes", [
780
1109
  String
781
1110
  ]),
782
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1111
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
783
1112
  ], AgentApiController.prototype, "threads", null);
784
- _ts_decorate2([
785
- (0, import_common5.Get)("threads-page"),
786
- _ts_param2(0, (0, import_common5.Query)("page")),
787
- _ts_param2(1, (0, import_common5.Query)("limit")),
788
- _ts_param2(2, (0, import_common5.Query)("where")),
789
- _ts_metadata2("design:type", Function),
790
- _ts_metadata2("design:paramtypes", [
1113
+ _ts_decorate3([
1114
+ (0, import_common6.Get)("threads-page"),
1115
+ _ts_param3(0, (0, import_common6.Query)("page")),
1116
+ _ts_param3(1, (0, import_common6.Query)("limit")),
1117
+ _ts_param3(2, (0, import_common6.Query)("where")),
1118
+ _ts_metadata3("design:type", Function),
1119
+ _ts_metadata3("design:paramtypes", [
791
1120
  String,
792
1121
  String,
793
1122
  typeof Record === "undefined" ? Object : Record
794
1123
  ]),
795
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1124
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
796
1125
  ], AgentApiController.prototype, "threadsPage", null);
797
- _ts_decorate2([
798
- (0, import_common5.Get)("pricing"),
799
- _ts_metadata2("design:type", Function),
800
- _ts_metadata2("design:paramtypes", []),
801
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1126
+ _ts_decorate3([
1127
+ (0, import_common6.Get)("pricing"),
1128
+ _ts_metadata3("design:type", Function),
1129
+ _ts_metadata3("design:paramtypes", []),
1130
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
802
1131
  ], AgentApiController.prototype, "listPrices", null);
803
- _ts_decorate2([
804
- (0, import_common5.Post)("pricing"),
805
- _ts_param2(0, (0, import_common5.Body)()),
806
- _ts_metadata2("design:type", Function),
807
- _ts_metadata2("design:paramtypes", [
1132
+ _ts_decorate3([
1133
+ (0, import_common6.Post)("pricing"),
1134
+ _ts_param3(0, (0, import_common6.Body)()),
1135
+ _ts_metadata3("design:type", Function),
1136
+ _ts_metadata3("design:paramtypes", [
808
1137
  Object
809
1138
  ]),
810
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1139
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
811
1140
  ], AgentApiController.prototype, "upsertPrice", null);
812
- _ts_decorate2([
813
- (0, import_common5.Sse)("stream"),
814
- _ts_metadata2("design:type", Function),
815
- _ts_metadata2("design:paramtypes", []),
816
- _ts_metadata2("design:returntype", typeof Observable === "undefined" ? Object : Observable)
1141
+ _ts_decorate3([
1142
+ (0, import_common6.Sse)("stream"),
1143
+ _ts_metadata3("design:type", Function),
1144
+ _ts_metadata3("design:paramtypes", []),
1145
+ _ts_metadata3("design:returntype", typeof Observable === "undefined" ? Object : Observable)
817
1146
  ], AgentApiController.prototype, "stream", null);
818
- AgentApiController = _ts_decorate2([
819
- (0, import_common5.Controller)(),
820
- _ts_param2(1, (0, import_common5.Inject)(DASHBOARD_APPROVAL_ACTOR_REF)),
821
- _ts_param2(2, (0, import_common5.Optional)()),
822
- _ts_param2(2, (0, import_common5.Inject)(AGENT_ACTOR_RESOLVER)),
823
- _ts_metadata2("design:type", Function),
824
- _ts_metadata2("design:paramtypes", [
1147
+ AgentApiController = _ts_decorate3([
1148
+ (0, import_common6.Controller)(),
1149
+ (0, import_common6.UseGuards)(DashboardAuthGuard),
1150
+ _ts_param3(1, (0, import_common6.Inject)(DASHBOARD_APPROVAL_ACTOR_REF)),
1151
+ _ts_param3(2, (0, import_common6.Optional)()),
1152
+ _ts_param3(2, (0, import_common6.Inject)(AGENT_ACTOR_RESOLVER)),
1153
+ _ts_metadata3("design:type", Function),
1154
+ _ts_metadata3("design:paramtypes", [
825
1155
  typeof DashboardService === "undefined" ? Object : DashboardService,
826
1156
  Object,
827
1157
  typeof ActorResolver === "undefined" ? Object : ActorResolver
828
1158
  ])
829
1159
  ], AgentApiController);
830
1160
 
1161
+ // src/server/agent-dashboard-auth.controller.ts
1162
+ var import_common7 = require("@nestjs/common");
1163
+
1164
+ // src/server/auth/login-page.ts
1165
+ function escapeHtml(value) {
1166
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1167
+ }
1168
+ __name(escapeHtml, "escapeHtml");
1169
+ function renderLoginPage(options) {
1170
+ const action = escapeHtml(options.actionUrl);
1171
+ const returnTo = escapeHtml(options.returnTo);
1172
+ const errorBanner = options.error === true ? '<p role="alert" class="error">Invalid username or password.</p>' : "";
1173
+ return `<!doctype html>
1174
+ <html lang="en">
1175
+ <head>
1176
+ <meta charset="utf-8" />
1177
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1178
+ <meta name="robots" content="noindex, nofollow" />
1179
+ <title>Sign in \u2014 AI Gateway</title>
1180
+ <style>
1181
+ :root { color-scheme: dark; }
1182
+ * { box-sizing: border-box; }
1183
+ body {
1184
+ margin: 0;
1185
+ min-height: 100vh;
1186
+ display: flex;
1187
+ align-items: center;
1188
+ justify-content: center;
1189
+ background: #09090b;
1190
+ color: #e4e4e7;
1191
+ font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1192
+ padding: 16px;
1193
+ }
1194
+ .card {
1195
+ width: 100%;
1196
+ max-width: 384px;
1197
+ border: 1px solid #27272a;
1198
+ background: #18181b;
1199
+ border-radius: 8px;
1200
+ padding: 32px;
1201
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5);
1202
+ }
1203
+ .brand {
1204
+ margin: 0 0 24px;
1205
+ text-align: center;
1206
+ font-size: 18px;
1207
+ font-weight: 600;
1208
+ color: #34d399;
1209
+ }
1210
+ form { display: flex; flex-direction: column; gap: 16px; }
1211
+ label { display: flex; flex-direction: column; gap: 6px; }
1212
+ .field-label {
1213
+ font-size: 11px;
1214
+ text-transform: uppercase;
1215
+ letter-spacing: 0.05em;
1216
+ color: #71717a;
1217
+ }
1218
+ input {
1219
+ border-radius: 4px;
1220
+ border: 1px solid #3f3f46;
1221
+ background: #09090b;
1222
+ color: #f4f4f5;
1223
+ padding: 8px 12px;
1224
+ font: inherit;
1225
+ outline: none;
1226
+ }
1227
+ input:focus { border-color: rgb(52 211 153 / 0.6); }
1228
+ .error { margin: 0; font-size: 12px; color: #fb7185; }
1229
+ button {
1230
+ margin-top: 8px;
1231
+ border-radius: 4px;
1232
+ border: 1px solid rgb(52 211 153 / 0.4);
1233
+ background: rgb(52 211 153 / 0.1);
1234
+ color: #6ee7b7;
1235
+ padding: 8px 12px;
1236
+ font: inherit;
1237
+ font-size: 12px;
1238
+ font-weight: 500;
1239
+ text-transform: uppercase;
1240
+ letter-spacing: 0.05em;
1241
+ cursor: pointer;
1242
+ }
1243
+ button:hover { background: rgb(52 211 153 / 0.2); }
1244
+ </style>
1245
+ </head>
1246
+ <body>
1247
+ <div class="card">
1248
+ <p class="brand">AI Gateway</p>
1249
+ <form method="post" action="${action}">
1250
+ <input type="hidden" name="returnTo" value="${returnTo}" />
1251
+ <label>
1252
+ <span class="field-label">Username</span>
1253
+ <input type="text" name="username" autocomplete="username" autofocus />
1254
+ </label>
1255
+ <label>
1256
+ <span class="field-label">Password</span>
1257
+ <input type="password" name="password" autocomplete="current-password" />
1258
+ </label>
1259
+ ${errorBanner}
1260
+ <button type="submit">Sign in</button>
1261
+ </form>
1262
+ </div>
1263
+ </body>
1264
+ </html>`;
1265
+ }
1266
+ __name(renderLoginPage, "renderLoginPage");
1267
+
1268
+ // src/server/auth/sanitize-return-to.ts
1269
+ function sanitizeReturnTo(basePath, returnTo) {
1270
+ if (typeof returnTo !== "string" || returnTo === "") return basePath;
1271
+ if (!returnTo.startsWith("/") || returnTo.startsWith("//")) return basePath;
1272
+ if (returnTo !== basePath && !returnTo.startsWith(`${basePath}/`) && !returnTo.startsWith(`${basePath}?`)) {
1273
+ return basePath;
1274
+ }
1275
+ return returnTo;
1276
+ }
1277
+ __name(sanitizeReturnTo, "sanitizeReturnTo");
1278
+
1279
+ // src/server/agent-dashboard-auth.controller.ts
1280
+ function _ts_decorate4(decorators, target, key, desc) {
1281
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1282
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1283
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1284
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1285
+ }
1286
+ __name(_ts_decorate4, "_ts_decorate");
1287
+ function _ts_metadata4(k, v) {
1288
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1289
+ }
1290
+ __name(_ts_metadata4, "_ts_metadata");
1291
+ function _ts_param4(paramIndex, decorator) {
1292
+ return function(target, key) {
1293
+ decorator(target, key, paramIndex);
1294
+ };
1295
+ }
1296
+ __name(_ts_param4, "_ts_param");
1297
+ function isNonEmptyString(value) {
1298
+ return typeof value === "string" && value.trim() !== "";
1299
+ }
1300
+ __name(isNonEmptyString, "isNonEmptyString");
1301
+ function isString(value) {
1302
+ return typeof value === "string";
1303
+ }
1304
+ __name(isString, "isString");
1305
+ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1306
+ static {
1307
+ __name(this, "AgentDashboardAuthController");
1308
+ }
1309
+ auth;
1310
+ basePath;
1311
+ logger = new import_common7.Logger(_AgentDashboardAuthController.name);
1312
+ /** Warn once (not per request) so a broken hook can't be used to flood the logs. */
1313
+ warnedLoginHookThrow = false;
1314
+ constructor(auth, basePath) {
1315
+ this.auth = auth;
1316
+ this.basePath = basePath;
1317
+ }
1318
+ loginPage(req, res, returnToQuery, error) {
1319
+ this.requireAuth();
1320
+ const returnTo = sanitizeReturnTo(this.basePath, returnToQuery);
1321
+ if (this.currentSession(req)) {
1322
+ res.status(302);
1323
+ res.setHeader("Location", returnTo);
1324
+ return "";
1325
+ }
1326
+ return renderLoginPage({
1327
+ actionUrl: `${this.basePath}/auth/login`,
1328
+ returnTo,
1329
+ error: error !== void 0
1330
+ });
1331
+ }
1332
+ async login(body, req, res) {
1333
+ const auth = this.requireAuth();
1334
+ const returnTo = sanitizeReturnTo(this.basePath, body?.returnTo);
1335
+ const username = body?.username;
1336
+ const password = body?.password;
1337
+ if (!isNonEmptyString(username) || password !== void 0 && !isString(password)) {
1338
+ this.redirectToLoginError(res, returnTo);
1339
+ return "";
1340
+ }
1341
+ const user = await this.runLoginHook(auth, username.trim(), isString(password) ? password : "");
1342
+ if (!user) {
1343
+ this.redirectToLoginError(res, returnTo);
1344
+ return "";
1345
+ }
1346
+ issueSessionCookie(user, {
1347
+ auth,
1348
+ request: req,
1349
+ response: res
1350
+ });
1351
+ res.status(302);
1352
+ res.setHeader("Location", returnTo);
1353
+ return "";
1354
+ }
1355
+ logout(req, res) {
1356
+ clearSessionCookie({
1357
+ request: req,
1358
+ response: res
1359
+ });
1360
+ res.status(302);
1361
+ res.setHeader("Location", `${this.basePath}/auth/login`);
1362
+ return "";
1363
+ }
1364
+ /** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
1365
+ redirectToLoginError(res, returnTo) {
1366
+ res.status(303);
1367
+ res.setHeader("Location", `${this.basePath}/auth/login?error=1&returnTo=${encodeURIComponent(returnTo)}`);
1368
+ }
1369
+ currentSession(req) {
1370
+ const auth = this.auth;
1371
+ if (!auth) return false;
1372
+ const cookieValue = parseCookieHeader(readCookieHeader(req))[SESSION_COOKIE_NAME];
1373
+ if (cookieValue === void 0) return false;
1374
+ return verifySessionCookie(cookieValue, {
1375
+ secret: auth.secret
1376
+ }) !== null;
1377
+ }
1378
+ /**
1379
+ * Run the host's `login` hook defensively: a throw (sync or async) is treated as a denial
1380
+ * (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the endpoint into a
1381
+ * stack-trace leak nor floods the logs.
1382
+ */
1383
+ async runLoginHook(auth, username, password) {
1384
+ try {
1385
+ return await auth.login(username, password) ?? null;
1386
+ } catch (error) {
1387
+ if (!this.warnedLoginHookThrow) {
1388
+ this.warnedLoginHookThrow = true;
1389
+ this.logger.warn(`AgentDashboardModule dashboardAuth login hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
1390
+ }
1391
+ return null;
1392
+ }
1393
+ }
1394
+ requireAuth() {
1395
+ if (!this.auth) throw new import_common7.NotFoundException();
1396
+ return this.auth;
1397
+ }
1398
+ };
1399
+ _ts_decorate4([
1400
+ (0, import_common7.Get)("login"),
1401
+ (0, import_common7.Header)("Content-Type", "text/html; charset=utf-8"),
1402
+ (0, import_common7.Header)("Cache-Control", "no-store"),
1403
+ _ts_param4(0, (0, import_common7.Req)()),
1404
+ _ts_param4(1, (0, import_common7.Res)({
1405
+ passthrough: true
1406
+ })),
1407
+ _ts_param4(2, (0, import_common7.Query)("returnTo")),
1408
+ _ts_param4(3, (0, import_common7.Query)("error")),
1409
+ _ts_metadata4("design:type", Function),
1410
+ _ts_metadata4("design:paramtypes", [
1411
+ typeof AuthPageRequest === "undefined" ? Object : AuthPageRequest,
1412
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse,
1413
+ String,
1414
+ String
1415
+ ]),
1416
+ _ts_metadata4("design:returntype", String)
1417
+ ], AgentDashboardAuthController.prototype, "loginPage", null);
1418
+ _ts_decorate4([
1419
+ (0, import_common7.Post)("login"),
1420
+ _ts_param4(0, (0, import_common7.Body)()),
1421
+ _ts_param4(1, (0, import_common7.Req)()),
1422
+ _ts_param4(2, (0, import_common7.Res)({
1423
+ passthrough: true
1424
+ })),
1425
+ _ts_metadata4("design:type", Function),
1426
+ _ts_metadata4("design:paramtypes", [
1427
+ typeof LoginFormBody === "undefined" ? Object : LoginFormBody,
1428
+ Object,
1429
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse
1430
+ ]),
1431
+ _ts_metadata4("design:returntype", Promise)
1432
+ ], AgentDashboardAuthController.prototype, "login", null);
1433
+ _ts_decorate4([
1434
+ (0, import_common7.Post)("logout"),
1435
+ _ts_param4(0, (0, import_common7.Req)()),
1436
+ _ts_param4(1, (0, import_common7.Res)({
1437
+ passthrough: true
1438
+ })),
1439
+ _ts_metadata4("design:type", Function),
1440
+ _ts_metadata4("design:paramtypes", [
1441
+ Object,
1442
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse
1443
+ ]),
1444
+ _ts_metadata4("design:returntype", String)
1445
+ ], AgentDashboardAuthController.prototype, "logout", null);
1446
+ AgentDashboardAuthController = _ts_decorate4([
1447
+ (0, import_common7.Controller)("auth"),
1448
+ _ts_param4(0, (0, import_common7.Optional)()),
1449
+ _ts_param4(0, (0, import_common7.Inject)(DASHBOARD_AUTH)),
1450
+ _ts_param4(1, (0, import_common7.Inject)(DASHBOARD_BASE_PATH)),
1451
+ _ts_metadata4("design:type", Function),
1452
+ _ts_metadata4("design:paramtypes", [
1453
+ Object,
1454
+ String
1455
+ ])
1456
+ ], AgentDashboardAuthController);
1457
+
831
1458
  // src/server/normalize-path.ts
832
1459
  function normalizeDashboardPath(path) {
833
1460
  return `/${path.replace(/^\/+|\/+$/g, "")}`;
@@ -854,32 +1481,155 @@ function agentDashboardMountPaths(options) {
854
1481
  __name(agentDashboardMountPaths, "agentDashboardMountPaths");
855
1482
 
856
1483
  // src/server/agent-dashboard.module.ts
857
- var import_reflect_metadata = require("reflect-metadata");
858
- var import_common7 = require("@nestjs/common");
1484
+ var import_reflect_metadata2 = require("reflect-metadata");
1485
+ var import_common11 = require("@nestjs/common");
859
1486
  var import_core = require("@nestjs/core");
860
1487
 
861
1488
  // src/server/agent-ui.controller.ts
862
1489
  var import_node_fs = require("fs");
863
1490
  var import_node_path = require("path");
864
1491
  var import_node_url = require("url");
865
- var import_common6 = require("@nestjs/common");
866
- function _ts_decorate3(decorators, target, key, desc) {
1492
+ var import_common10 = require("@nestjs/common");
1493
+
1494
+ // src/server/auth/dashboard-auth-page.guard.ts
1495
+ var import_common9 = require("@nestjs/common");
1496
+
1497
+ // src/server/auth/dashboard-auth-redirect.ts
1498
+ var import_common8 = require("@nestjs/common");
1499
+ function _ts_decorate5(decorators, target, key, desc) {
867
1500
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
868
1501
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
869
1502
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
870
1503
  return c > 3 && r && Object.defineProperty(target, key, r), r;
871
1504
  }
872
- __name(_ts_decorate3, "_ts_decorate");
873
- function _ts_metadata3(k, v) {
1505
+ __name(_ts_decorate5, "_ts_decorate");
1506
+ var DashboardAuthRedirect = class extends Error {
1507
+ static {
1508
+ __name(this, "DashboardAuthRedirect");
1509
+ }
1510
+ redirectTo;
1511
+ constructor(redirectTo) {
1512
+ super(`Redirect to ${redirectTo}`), this.redirectTo = redirectTo;
1513
+ this.name = "DashboardAuthRedirect";
1514
+ }
1515
+ };
1516
+ var DashboardAuthRedirectFilter = class {
1517
+ static {
1518
+ __name(this, "DashboardAuthRedirectFilter");
1519
+ }
1520
+ catch(exception, host) {
1521
+ const response = host.switchToHttp().getResponse();
1522
+ sendRedirect(response, 302, exception.redirectTo);
1523
+ }
1524
+ };
1525
+ DashboardAuthRedirectFilter = _ts_decorate5([
1526
+ (0, import_common8.Injectable)(),
1527
+ (0, import_common8.Catch)(DashboardAuthRedirect)
1528
+ ], DashboardAuthRedirectFilter);
1529
+
1530
+ // src/server/auth/dashboard-auth-page.guard.ts
1531
+ function _ts_decorate6(decorators, target, key, desc) {
1532
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1533
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1534
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1535
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1536
+ }
1537
+ __name(_ts_decorate6, "_ts_decorate");
1538
+ function _ts_metadata5(k, v) {
874
1539
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
875
1540
  }
876
- __name(_ts_metadata3, "_ts_metadata");
877
- function _ts_param3(paramIndex, decorator) {
1541
+ __name(_ts_metadata5, "_ts_metadata");
1542
+ function _ts_param5(paramIndex, decorator) {
878
1543
  return function(target, key) {
879
1544
  decorator(target, key, paramIndex);
880
1545
  };
881
1546
  }
882
- __name(_ts_param3, "_ts_param");
1547
+ __name(_ts_param5, "_ts_param");
1548
+ var DashboardAuthPageGuard = class {
1549
+ static {
1550
+ __name(this, "DashboardAuthPageGuard");
1551
+ }
1552
+ auth;
1553
+ basePath;
1554
+ constructor(auth, basePath) {
1555
+ this.auth = auth;
1556
+ this.basePath = basePath;
1557
+ }
1558
+ canActivate(context) {
1559
+ if (!this.auth) return true;
1560
+ const http = context.switchToHttp();
1561
+ const request = http.getRequest();
1562
+ const session = this.verifyRequestSession(request);
1563
+ if (!session) {
1564
+ const returnTo = readOriginalUrl(request);
1565
+ throw new DashboardAuthRedirect(`${this.basePath}/auth/login?returnTo=${encodeURIComponent(returnTo)}`);
1566
+ }
1567
+ attachSession(request, session);
1568
+ this.maybeRenew(http.getResponse(), request, session);
1569
+ return true;
1570
+ }
1571
+ verifyRequestSession(request) {
1572
+ const auth = this.auth;
1573
+ if (!auth) return null;
1574
+ const cookieValue = parseCookieHeader(readCookieHeader(request))[SESSION_COOKIE_NAME];
1575
+ if (cookieValue === void 0) return null;
1576
+ return verifySessionCookie(cookieValue, {
1577
+ secret: auth.secret
1578
+ });
1579
+ }
1580
+ /**
1581
+ * Sliding renewal: a valid cookie past 50% of its TTL is transparently re-issued on the
1582
+ * response, so an active user never gets logged out mid-session.
1583
+ */
1584
+ maybeRenew(response, request, session) {
1585
+ const auth = this.auth;
1586
+ if (!auth) return;
1587
+ const now = Date.now();
1588
+ if (now - session.iat <= auth.ttlMs / 2) return;
1589
+ issueSessionCookie({
1590
+ id: session.sub,
1591
+ ...session.name !== void 0 ? {
1592
+ name: session.name
1593
+ } : {},
1594
+ roles: session.roles
1595
+ }, {
1596
+ auth,
1597
+ request,
1598
+ response,
1599
+ now
1600
+ });
1601
+ }
1602
+ };
1603
+ DashboardAuthPageGuard = _ts_decorate6([
1604
+ (0, import_common9.Injectable)(),
1605
+ _ts_param5(0, (0, import_common9.Optional)()),
1606
+ _ts_param5(0, (0, import_common9.Inject)(DASHBOARD_AUTH)),
1607
+ _ts_param5(1, (0, import_common9.Inject)(DASHBOARD_BASE_PATH)),
1608
+ _ts_metadata5("design:type", Function),
1609
+ _ts_metadata5("design:paramtypes", [
1610
+ Object,
1611
+ String
1612
+ ])
1613
+ ], DashboardAuthPageGuard);
1614
+
1615
+ // src/server/agent-ui.controller.ts
1616
+ function _ts_decorate7(decorators, target, key, desc) {
1617
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1618
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1619
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1620
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1621
+ }
1622
+ __name(_ts_decorate7, "_ts_decorate");
1623
+ function _ts_metadata6(k, v) {
1624
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1625
+ }
1626
+ __name(_ts_metadata6, "_ts_metadata");
1627
+ function _ts_param6(paramIndex, decorator) {
1628
+ return function(target, key) {
1629
+ decorator(target, key, paramIndex);
1630
+ };
1631
+ }
1632
+ __name(_ts_param6, "_ts_param");
883
1633
  var BUILD_BASE = "/ai-gateway";
884
1634
  function spaDir() {
885
1635
  return (0, import_node_url.fileURLToPath)(new URL("../spa", __importMetaUrl));
@@ -915,7 +1665,7 @@ var AgentUiController = class {
915
1665
  }
916
1666
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
917
1667
  if (!(0, import_node_fs.existsSync)(indexPath)) {
918
- throw new import_common6.NotFoundException("Dashboard is not built. Run the package build.");
1668
+ throw new import_common10.NotFoundException("Dashboard is not built. Run the package build.");
919
1669
  }
920
1670
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
921
1671
  const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;
@@ -923,78 +1673,147 @@ var AgentUiController = class {
923
1673
  }
924
1674
  asset(file) {
925
1675
  const safe = (0, import_node_path.basename)(file);
926
- if (safe !== file) throw new import_common6.NotFoundException();
1676
+ if (safe !== file) throw new import_common10.NotFoundException();
927
1677
  const root = (0, import_node_path.resolve)(this.dir, "assets");
928
1678
  const assetPath = (0, import_node_path.resolve)(root, safe);
929
1679
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
930
- throw new import_common6.NotFoundException();
1680
+ throw new import_common10.NotFoundException();
931
1681
  }
932
1682
  const type = CONTENT_TYPES[(0, import_node_path.extname)(safe)] ?? "application/octet-stream";
933
- return new import_common6.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1683
+ return new import_common10.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
934
1684
  type
935
1685
  });
936
1686
  }
937
1687
  };
938
- _ts_decorate3([
939
- (0, import_common6.Get)(),
940
- (0, import_common6.Header)("Content-Type", "text/html; charset=utf-8"),
941
- (0, import_common6.Header)("Cache-Control", "no-store, must-revalidate"),
942
- _ts_param3(0, (0, import_common6.Req)()),
943
- _ts_param3(1, (0, import_common6.Res)({
1688
+ _ts_decorate7([
1689
+ (0, import_common10.Get)(),
1690
+ (0, import_common10.Header)("Content-Type", "text/html; charset=utf-8"),
1691
+ (0, import_common10.Header)("Cache-Control", "no-store, must-revalidate"),
1692
+ _ts_param6(0, (0, import_common10.Req)()),
1693
+ _ts_param6(1, (0, import_common10.Res)({
944
1694
  passthrough: true
945
1695
  })),
946
- _ts_metadata3("design:type", Function),
947
- _ts_metadata3("design:paramtypes", [
1696
+ _ts_metadata6("design:type", Function),
1697
+ _ts_metadata6("design:paramtypes", [
948
1698
  typeof UiPageRequest === "undefined" ? Object : UiPageRequest,
949
1699
  typeof UiPageResponse === "undefined" ? Object : UiPageResponse
950
1700
  ]),
951
- _ts_metadata3("design:returntype", String)
1701
+ _ts_metadata6("design:returntype", String)
952
1702
  ], AgentUiController.prototype, "index", null);
953
- _ts_decorate3([
954
- (0, import_common6.Get)("assets/:file"),
955
- (0, import_common6.Header)("Cache-Control", "public, max-age=31536000, immutable"),
956
- _ts_param3(0, (0, import_common6.Param)("file")),
957
- _ts_metadata3("design:type", Function),
958
- _ts_metadata3("design:paramtypes", [
1703
+ _ts_decorate7([
1704
+ (0, import_common10.Get)("assets/:file"),
1705
+ (0, import_common10.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1706
+ _ts_param6(0, (0, import_common10.Param)("file")),
1707
+ _ts_metadata6("design:type", Function),
1708
+ _ts_metadata6("design:paramtypes", [
959
1709
  String
960
1710
  ]),
961
- _ts_metadata3("design:returntype", typeof import_common6.StreamableFile === "undefined" ? Object : import_common6.StreamableFile)
1711
+ _ts_metadata6("design:returntype", typeof import_common10.StreamableFile === "undefined" ? Object : import_common10.StreamableFile)
962
1712
  ], AgentUiController.prototype, "asset", null);
963
- AgentUiController = _ts_decorate3([
964
- (0, import_common6.Controller)(),
965
- _ts_param3(0, (0, import_common6.Inject)(DASHBOARD_BASE_PATH)),
966
- _ts_param3(1, (0, import_common6.Inject)(DASHBOARD_API_PATH)),
967
- _ts_metadata3("design:type", Function),
968
- _ts_metadata3("design:paramtypes", [
1713
+ AgentUiController = _ts_decorate7([
1714
+ (0, import_common10.Controller)(),
1715
+ (0, import_common10.UseGuards)(DashboardAuthPageGuard),
1716
+ (0, import_common10.UseFilters)(new DashboardAuthRedirectFilter()),
1717
+ _ts_param6(0, (0, import_common10.Inject)(DASHBOARD_BASE_PATH)),
1718
+ _ts_param6(1, (0, import_common10.Inject)(DASHBOARD_API_PATH)),
1719
+ _ts_metadata6("design:type", Function),
1720
+ _ts_metadata6("design:paramtypes", [
969
1721
  String,
970
1722
  String
971
1723
  ])
972
1724
  ], AgentUiController);
973
1725
 
1726
+ // src/server/auth/dashboard-auth-config.ts
1727
+ var DEFAULT_TTL = "8h";
1728
+ function unitToMs(unit) {
1729
+ switch (unit) {
1730
+ case "ms":
1731
+ return 1;
1732
+ case "s":
1733
+ return 1e3;
1734
+ case "m":
1735
+ return 6e4;
1736
+ case "h":
1737
+ return 36e5;
1738
+ case "d":
1739
+ return 864e5;
1740
+ default:
1741
+ return void 0;
1742
+ }
1743
+ }
1744
+ __name(unitToMs, "unitToMs");
1745
+ function durationToMs(duration) {
1746
+ const match = /^(\d+)(ms|s|m|h|d)$/.exec(duration.trim());
1747
+ const amount = match?.[1];
1748
+ const unit = match?.[2] !== void 0 ? unitToMs(match[2]) : void 0;
1749
+ if (amount === void 0 || unit === void 0) {
1750
+ throw new Error(`AgentDashboardModule dashboardAuth: invalid \`ttl\` duration: ${duration}`);
1751
+ }
1752
+ return Number(amount) * unit;
1753
+ }
1754
+ __name(durationToMs, "durationToMs");
1755
+ function resolveDashboardAuth(options) {
1756
+ if (options === void 0) return null;
1757
+ if (typeof options.secret !== "string" || options.secret === "") {
1758
+ throw new Error("AgentDashboardModule dashboardAuth: `secret` is required and must be a non-empty string (HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.");
1759
+ }
1760
+ if (typeof options.login !== "function") {
1761
+ throw new Error("AgentDashboardModule dashboardAuth: `login` is required (validates submitted credentials for the built-in login screen). Failing closed.");
1762
+ }
1763
+ return {
1764
+ secret: options.secret,
1765
+ ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
1766
+ login: options.login
1767
+ };
1768
+ }
1769
+ __name(resolveDashboardAuth, "resolveDashboardAuth");
1770
+
1771
+ // src/server/guards.ts
1772
+ var import_reflect_metadata = require("reflect-metadata");
1773
+ var GUARDS_METADATA = "__guards__";
1774
+ function isGuardClass(guard) {
1775
+ return typeof guard === "function";
1776
+ }
1777
+ __name(isGuardClass, "isGuardClass");
1778
+ function baseGuards(controller) {
1779
+ return Reflect.getOwnMetadata(GUARDS_METADATA, controller) ?? [];
1780
+ }
1781
+ __name(baseGuards, "baseGuards");
1782
+ function stampGuards(guards, entries) {
1783
+ for (const [controller, base] of entries) {
1784
+ Reflect.defineMetadata(GUARDS_METADATA, [
1785
+ ...base,
1786
+ ...guards ?? []
1787
+ ], controller);
1788
+ }
1789
+ }
1790
+ __name(stampGuards, "stampGuards");
1791
+
974
1792
  // src/server/agent-dashboard.module.ts
975
- function _ts_decorate4(decorators, target, key, desc) {
1793
+ function _ts_decorate8(decorators, target, key, desc) {
976
1794
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
977
1795
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
978
1796
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
979
1797
  return c > 3 && r && Object.defineProperty(target, key, r), r;
980
1798
  }
981
- __name(_ts_decorate4, "_ts_decorate");
982
- var GUARDS_METADATA = "__guards__";
1799
+ __name(_ts_decorate8, "_ts_decorate");
1800
+ var API_BASE_GUARDS = baseGuards(AgentApiController);
1801
+ var UI_BASE_GUARDS = baseGuards(AgentUiController);
983
1802
  function normalize(path) {
984
1803
  return normalizeDashboardPath(path);
985
1804
  }
986
1805
  __name(normalize, "normalize");
987
- function stampGuards(guards, ...controllers) {
988
- for (const controller of controllers) {
989
- Reflect.defineMetadata(GUARDS_METADATA, guards ?? [], controller);
990
- }
991
- }
992
- __name(stampGuards, "stampGuards");
993
1806
  var AgentApiModule = class _AgentApiModule {
994
1807
  static {
995
1808
  __name(this, "AgentApiModule");
996
1809
  }
997
1810
  static register(options) {
1811
+ stampGuards(options.guards, [
1812
+ [
1813
+ AgentApiController,
1814
+ API_BASE_GUARDS
1815
+ ]
1816
+ ]);
998
1817
  return {
999
1818
  module: _AgentApiModule,
1000
1819
  imports: [
@@ -1005,7 +1824,9 @@ var AgentApiModule = class _AgentApiModule {
1005
1824
  ],
1006
1825
  providers: [
1007
1826
  DashboardService,
1008
- ...options.guards ?? [],
1827
+ DashboardAuthGuard,
1828
+ options.dashboardAuth,
1829
+ ...(options.guards ?? []).filter(isGuardClass),
1009
1830
  // `useValue` even when `options.approvalActorRef` is `undefined` — AgentApiController
1010
1831
  // injects this WITHOUT `@Optional()` (same pattern as `AGENT_QUOTA_STORE`'s factory).
1011
1832
  {
@@ -1013,14 +1834,18 @@ var AgentApiModule = class _AgentApiModule {
1013
1834
  useValue: options.approvalActorRef
1014
1835
  }
1015
1836
  ],
1837
+ // DASHBOARD_AUTH re-exported so AgentUiController/AgentDashboardAuthController (hosted
1838
+ // directly by AgentDashboardModule, which imports this module) resolve the SAME instance
1839
+ // instead of re-running a host's async factory a second time.
1016
1840
  exports: [
1017
- DashboardService
1841
+ DashboardService,
1842
+ DASHBOARD_AUTH
1018
1843
  ]
1019
1844
  };
1020
1845
  }
1021
1846
  };
1022
- AgentApiModule = _ts_decorate4([
1023
- (0, import_common7.Module)({})
1847
+ AgentApiModule = _ts_decorate8([
1848
+ (0, import_common11.Module)({})
1024
1849
  ], AgentApiModule);
1025
1850
  var AgentDashboardModule = class _AgentDashboardModule {
1026
1851
  static {
@@ -1029,7 +1854,16 @@ var AgentDashboardModule = class _AgentDashboardModule {
1029
1854
  static forRoot(options = {}) {
1030
1855
  const basePath = normalize(options.basePath ?? "/ai-gateway");
1031
1856
  const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
1032
- stampGuards(options.guards, AgentApiController, AgentUiController);
1857
+ stampGuards(options.guards, [
1858
+ [
1859
+ AgentUiController,
1860
+ UI_BASE_GUARDS
1861
+ ]
1862
+ ]);
1863
+ const dashboardAuthProvider = {
1864
+ provide: DASHBOARD_AUTH,
1865
+ useValue: resolveDashboardAuth(options.dashboardAuth)
1866
+ };
1033
1867
  return {
1034
1868
  module: _AgentDashboardModule,
1035
1869
  imports: [
@@ -1046,7 +1880,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
1046
1880
  } : {},
1047
1881
  ...options.approvalActorRef ? {
1048
1882
  approvalActorRef: options.approvalActorRef
1049
- } : {}
1883
+ } : {},
1884
+ dashboardAuth: dashboardAuthProvider
1050
1885
  }),
1051
1886
  import_core.RouterModule.register([
1052
1887
  {
@@ -1060,7 +1895,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
1060
1895
  ])
1061
1896
  ],
1062
1897
  controllers: [
1063
- AgentUiController
1898
+ AgentUiController,
1899
+ AgentDashboardAuthController
1064
1900
  ],
1065
1901
  providers: [
1066
1902
  {
@@ -1071,8 +1907,9 @@ var AgentDashboardModule = class _AgentDashboardModule {
1071
1907
  provide: DASHBOARD_API_PATH,
1072
1908
  useValue: apiBasePath
1073
1909
  },
1910
+ DashboardAuthPageGuard,
1074
1911
  // AgentUiController is hosted HERE, so its guards DI-instantiate from this module.
1075
- ...options.guards ?? []
1912
+ ...(options.guards ?? []).filter(isGuardClass)
1076
1913
  ],
1077
1914
  // Re-export the API module so its DashboardService reaches importers (e.g. the host's own controllers).
1078
1915
  exports: [
@@ -1080,9 +1917,71 @@ var AgentDashboardModule = class _AgentDashboardModule {
1080
1917
  ]
1081
1918
  };
1082
1919
  }
1920
+ static forRootAsync(options) {
1921
+ const basePath = normalize(options.basePath ?? "/ai-gateway");
1922
+ const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
1923
+ stampGuards(options.guards, [
1924
+ [
1925
+ AgentUiController,
1926
+ UI_BASE_GUARDS
1927
+ ]
1928
+ ]);
1929
+ const dashboardAuthProvider = {
1930
+ provide: DASHBOARD_AUTH,
1931
+ inject: options.inject ?? [],
1932
+ useFactory: /* @__PURE__ */ __name(async (...deps) => resolveDashboardAuth(await options.useDashboardAuth(...deps)), "useFactory")
1933
+ };
1934
+ return {
1935
+ module: _AgentDashboardModule,
1936
+ imports: [
1937
+ ...options.imports ?? [],
1938
+ AgentApiModule.register({
1939
+ ...options.imports ? {
1940
+ imports: options.imports
1941
+ } : {},
1942
+ ...options.guards ? {
1943
+ guards: options.guards
1944
+ } : {},
1945
+ ...options.approvalActorRef ? {
1946
+ approvalActorRef: options.approvalActorRef
1947
+ } : {},
1948
+ dashboardAuth: dashboardAuthProvider
1949
+ }),
1950
+ import_core.RouterModule.register([
1951
+ {
1952
+ path: basePath,
1953
+ module: _AgentDashboardModule
1954
+ },
1955
+ {
1956
+ path: apiBasePath,
1957
+ module: AgentApiModule
1958
+ }
1959
+ ])
1960
+ ],
1961
+ controllers: [
1962
+ AgentUiController,
1963
+ AgentDashboardAuthController
1964
+ ],
1965
+ providers: [
1966
+ {
1967
+ provide: DASHBOARD_BASE_PATH,
1968
+ useValue: basePath
1969
+ },
1970
+ {
1971
+ provide: DASHBOARD_API_PATH,
1972
+ useValue: apiBasePath
1973
+ },
1974
+ DashboardAuthPageGuard,
1975
+ ...(options.guards ?? []).filter(isGuardClass)
1976
+ ],
1977
+ exports: [
1978
+ AgentApiModule
1979
+ ]
1980
+ };
1981
+ }
1083
1982
  };
1084
- AgentDashboardModule = _ts_decorate4([
1085
- (0, import_common7.Module)({})
1983
+ AgentDashboardModule = _ts_decorate8([
1984
+ (0, import_common11.Module)({})
1086
1985
  ], AgentDashboardModule);
1087
1986
  // Annotate the CommonJS export names for ESM import in node:
1088
1987
  0 && (module.exports = {
@@ -1093,13 +1992,16 @@ AgentDashboardModule = _ts_decorate4([
1093
1992
  AGENT_PRICING_STORE,
1094
1993
  AgentApiController,
1095
1994
  AgentApiModule,
1995
+ AgentDashboardAuthController,
1096
1996
  AgentDashboardModule,
1097
1997
  AgentUiController,
1098
1998
  DASHBOARD_API_PATH,
1099
1999
  DASHBOARD_APPROVAL_ACTOR_REF,
2000
+ DASHBOARD_AUTH,
1100
2001
  DASHBOARD_BASE_PATH,
1101
2002
  DashboardService,
1102
2003
  agentDashboardMountPaths,
1103
- parsePriceInput
2004
+ parsePriceInput,
2005
+ resolveDashboardAuth
1104
2006
  });
1105
2007
  //# sourceMappingURL=index.cjs.map