@dudousxd/nestjs-agent-dashboard 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,469 @@ 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 !== "";
1299
+ }
1300
+ __name(isNonEmptyString, "isNonEmptyString");
1301
+ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1302
+ static {
1303
+ __name(this, "AgentDashboardAuthController");
1304
+ }
1305
+ auth;
1306
+ basePath;
1307
+ logger = new import_common7.Logger(_AgentDashboardAuthController.name);
1308
+ /** Warn once (not per request) so a broken hook can't be used to flood the logs. */
1309
+ warnedLoginHookThrow = false;
1310
+ constructor(auth, basePath) {
1311
+ this.auth = auth;
1312
+ this.basePath = basePath;
1313
+ }
1314
+ loginPage(req, res, returnToQuery, error) {
1315
+ this.requireAuth();
1316
+ const returnTo = sanitizeReturnTo(this.basePath, returnToQuery);
1317
+ if (this.currentSession(req)) {
1318
+ res.status(302);
1319
+ res.setHeader("Location", returnTo);
1320
+ return "";
1321
+ }
1322
+ return renderLoginPage({
1323
+ actionUrl: `${this.basePath}/auth/login`,
1324
+ returnTo,
1325
+ error: error !== void 0
1326
+ });
1327
+ }
1328
+ async login(body, req, res) {
1329
+ const auth = this.requireAuth();
1330
+ const returnTo = sanitizeReturnTo(this.basePath, body?.returnTo);
1331
+ const username = body?.username;
1332
+ const password = body?.password;
1333
+ if (!isNonEmptyString(username) || !isNonEmptyString(password)) {
1334
+ this.redirectToLoginError(res, returnTo);
1335
+ return "";
1336
+ }
1337
+ const user = await this.runLoginHook(auth, username, password);
1338
+ if (!user) {
1339
+ this.redirectToLoginError(res, returnTo);
1340
+ return "";
1341
+ }
1342
+ issueSessionCookie(user, {
1343
+ auth,
1344
+ request: req,
1345
+ response: res
1346
+ });
1347
+ res.status(302);
1348
+ res.setHeader("Location", returnTo);
1349
+ return "";
1350
+ }
1351
+ logout(req, res) {
1352
+ clearSessionCookie({
1353
+ request: req,
1354
+ response: res
1355
+ });
1356
+ res.status(302);
1357
+ res.setHeader("Location", `${this.basePath}/auth/login`);
1358
+ return "";
1359
+ }
1360
+ /** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
1361
+ redirectToLoginError(res, returnTo) {
1362
+ res.status(303);
1363
+ res.setHeader("Location", `${this.basePath}/auth/login?error=1&returnTo=${encodeURIComponent(returnTo)}`);
1364
+ }
1365
+ currentSession(req) {
1366
+ const auth = this.auth;
1367
+ if (!auth) return false;
1368
+ const cookieValue = parseCookieHeader(readCookieHeader(req))[SESSION_COOKIE_NAME];
1369
+ if (cookieValue === void 0) return false;
1370
+ return verifySessionCookie(cookieValue, {
1371
+ secret: auth.secret
1372
+ }) !== null;
1373
+ }
1374
+ /**
1375
+ * Run the host's `login` hook defensively: a throw (sync or async) is treated as a denial
1376
+ * (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the endpoint into a
1377
+ * stack-trace leak nor floods the logs.
1378
+ */
1379
+ async runLoginHook(auth, username, password) {
1380
+ try {
1381
+ return await auth.login(username, password) ?? null;
1382
+ } catch (error) {
1383
+ if (!this.warnedLoginHookThrow) {
1384
+ this.warnedLoginHookThrow = true;
1385
+ this.logger.warn(`AgentDashboardModule dashboardAuth login hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
1386
+ }
1387
+ return null;
1388
+ }
1389
+ }
1390
+ requireAuth() {
1391
+ if (!this.auth) throw new import_common7.NotFoundException();
1392
+ return this.auth;
1393
+ }
1394
+ };
1395
+ _ts_decorate4([
1396
+ (0, import_common7.Get)("login"),
1397
+ (0, import_common7.Header)("Content-Type", "text/html; charset=utf-8"),
1398
+ (0, import_common7.Header)("Cache-Control", "no-store"),
1399
+ _ts_param4(0, (0, import_common7.Req)()),
1400
+ _ts_param4(1, (0, import_common7.Res)({
1401
+ passthrough: true
1402
+ })),
1403
+ _ts_param4(2, (0, import_common7.Query)("returnTo")),
1404
+ _ts_param4(3, (0, import_common7.Query)("error")),
1405
+ _ts_metadata4("design:type", Function),
1406
+ _ts_metadata4("design:paramtypes", [
1407
+ typeof AuthPageRequest === "undefined" ? Object : AuthPageRequest,
1408
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse,
1409
+ String,
1410
+ String
1411
+ ]),
1412
+ _ts_metadata4("design:returntype", String)
1413
+ ], AgentDashboardAuthController.prototype, "loginPage", null);
1414
+ _ts_decorate4([
1415
+ (0, import_common7.Post)("login"),
1416
+ _ts_param4(0, (0, import_common7.Body)()),
1417
+ _ts_param4(1, (0, import_common7.Req)()),
1418
+ _ts_param4(2, (0, import_common7.Res)({
1419
+ passthrough: true
1420
+ })),
1421
+ _ts_metadata4("design:type", Function),
1422
+ _ts_metadata4("design:paramtypes", [
1423
+ typeof LoginFormBody === "undefined" ? Object : LoginFormBody,
1424
+ Object,
1425
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse
1426
+ ]),
1427
+ _ts_metadata4("design:returntype", Promise)
1428
+ ], AgentDashboardAuthController.prototype, "login", null);
1429
+ _ts_decorate4([
1430
+ (0, import_common7.Post)("logout"),
1431
+ _ts_param4(0, (0, import_common7.Req)()),
1432
+ _ts_param4(1, (0, import_common7.Res)({
1433
+ passthrough: true
1434
+ })),
1435
+ _ts_metadata4("design:type", Function),
1436
+ _ts_metadata4("design:paramtypes", [
1437
+ Object,
1438
+ typeof AuthPageResponse === "undefined" ? Object : AuthPageResponse
1439
+ ]),
1440
+ _ts_metadata4("design:returntype", String)
1441
+ ], AgentDashboardAuthController.prototype, "logout", null);
1442
+ AgentDashboardAuthController = _ts_decorate4([
1443
+ (0, import_common7.Controller)("auth"),
1444
+ _ts_param4(0, (0, import_common7.Optional)()),
1445
+ _ts_param4(0, (0, import_common7.Inject)(DASHBOARD_AUTH)),
1446
+ _ts_param4(1, (0, import_common7.Inject)(DASHBOARD_BASE_PATH)),
1447
+ _ts_metadata4("design:type", Function),
1448
+ _ts_metadata4("design:paramtypes", [
1449
+ Object,
1450
+ String
1451
+ ])
1452
+ ], AgentDashboardAuthController);
1453
+
831
1454
  // src/server/normalize-path.ts
832
1455
  function normalizeDashboardPath(path) {
833
1456
  return `/${path.replace(/^\/+|\/+$/g, "")}`;
@@ -854,32 +1477,155 @@ function agentDashboardMountPaths(options) {
854
1477
  __name(agentDashboardMountPaths, "agentDashboardMountPaths");
855
1478
 
856
1479
  // src/server/agent-dashboard.module.ts
857
- var import_reflect_metadata = require("reflect-metadata");
858
- var import_common7 = require("@nestjs/common");
1480
+ var import_reflect_metadata2 = require("reflect-metadata");
1481
+ var import_common11 = require("@nestjs/common");
859
1482
  var import_core = require("@nestjs/core");
860
1483
 
861
1484
  // src/server/agent-ui.controller.ts
862
1485
  var import_node_fs = require("fs");
863
1486
  var import_node_path = require("path");
864
1487
  var import_node_url = require("url");
865
- var import_common6 = require("@nestjs/common");
866
- function _ts_decorate3(decorators, target, key, desc) {
1488
+ var import_common10 = require("@nestjs/common");
1489
+
1490
+ // src/server/auth/dashboard-auth-page.guard.ts
1491
+ var import_common9 = require("@nestjs/common");
1492
+
1493
+ // src/server/auth/dashboard-auth-redirect.ts
1494
+ var import_common8 = require("@nestjs/common");
1495
+ function _ts_decorate5(decorators, target, key, desc) {
867
1496
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
868
1497
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
869
1498
  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
1499
  return c > 3 && r && Object.defineProperty(target, key, r), r;
871
1500
  }
872
- __name(_ts_decorate3, "_ts_decorate");
873
- function _ts_metadata3(k, v) {
1501
+ __name(_ts_decorate5, "_ts_decorate");
1502
+ var DashboardAuthRedirect = class extends Error {
1503
+ static {
1504
+ __name(this, "DashboardAuthRedirect");
1505
+ }
1506
+ redirectTo;
1507
+ constructor(redirectTo) {
1508
+ super(`Redirect to ${redirectTo}`), this.redirectTo = redirectTo;
1509
+ this.name = "DashboardAuthRedirect";
1510
+ }
1511
+ };
1512
+ var DashboardAuthRedirectFilter = class {
1513
+ static {
1514
+ __name(this, "DashboardAuthRedirectFilter");
1515
+ }
1516
+ catch(exception, host) {
1517
+ const response = host.switchToHttp().getResponse();
1518
+ sendRedirect(response, 302, exception.redirectTo);
1519
+ }
1520
+ };
1521
+ DashboardAuthRedirectFilter = _ts_decorate5([
1522
+ (0, import_common8.Injectable)(),
1523
+ (0, import_common8.Catch)(DashboardAuthRedirect)
1524
+ ], DashboardAuthRedirectFilter);
1525
+
1526
+ // src/server/auth/dashboard-auth-page.guard.ts
1527
+ function _ts_decorate6(decorators, target, key, desc) {
1528
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1529
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1530
+ 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;
1531
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1532
+ }
1533
+ __name(_ts_decorate6, "_ts_decorate");
1534
+ function _ts_metadata5(k, v) {
874
1535
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
875
1536
  }
876
- __name(_ts_metadata3, "_ts_metadata");
877
- function _ts_param3(paramIndex, decorator) {
1537
+ __name(_ts_metadata5, "_ts_metadata");
1538
+ function _ts_param5(paramIndex, decorator) {
878
1539
  return function(target, key) {
879
1540
  decorator(target, key, paramIndex);
880
1541
  };
881
1542
  }
882
- __name(_ts_param3, "_ts_param");
1543
+ __name(_ts_param5, "_ts_param");
1544
+ var DashboardAuthPageGuard = class {
1545
+ static {
1546
+ __name(this, "DashboardAuthPageGuard");
1547
+ }
1548
+ auth;
1549
+ basePath;
1550
+ constructor(auth, basePath) {
1551
+ this.auth = auth;
1552
+ this.basePath = basePath;
1553
+ }
1554
+ canActivate(context) {
1555
+ if (!this.auth) return true;
1556
+ const http = context.switchToHttp();
1557
+ const request = http.getRequest();
1558
+ const session = this.verifyRequestSession(request);
1559
+ if (!session) {
1560
+ const returnTo = readOriginalUrl(request);
1561
+ throw new DashboardAuthRedirect(`${this.basePath}/auth/login?returnTo=${encodeURIComponent(returnTo)}`);
1562
+ }
1563
+ attachSession(request, session);
1564
+ this.maybeRenew(http.getResponse(), request, session);
1565
+ return true;
1566
+ }
1567
+ verifyRequestSession(request) {
1568
+ const auth = this.auth;
1569
+ if (!auth) return null;
1570
+ const cookieValue = parseCookieHeader(readCookieHeader(request))[SESSION_COOKIE_NAME];
1571
+ if (cookieValue === void 0) return null;
1572
+ return verifySessionCookie(cookieValue, {
1573
+ secret: auth.secret
1574
+ });
1575
+ }
1576
+ /**
1577
+ * Sliding renewal: a valid cookie past 50% of its TTL is transparently re-issued on the
1578
+ * response, so an active user never gets logged out mid-session.
1579
+ */
1580
+ maybeRenew(response, request, session) {
1581
+ const auth = this.auth;
1582
+ if (!auth) return;
1583
+ const now = Date.now();
1584
+ if (now - session.iat <= auth.ttlMs / 2) return;
1585
+ issueSessionCookie({
1586
+ id: session.sub,
1587
+ ...session.name !== void 0 ? {
1588
+ name: session.name
1589
+ } : {},
1590
+ roles: session.roles
1591
+ }, {
1592
+ auth,
1593
+ request,
1594
+ response,
1595
+ now
1596
+ });
1597
+ }
1598
+ };
1599
+ DashboardAuthPageGuard = _ts_decorate6([
1600
+ (0, import_common9.Injectable)(),
1601
+ _ts_param5(0, (0, import_common9.Optional)()),
1602
+ _ts_param5(0, (0, import_common9.Inject)(DASHBOARD_AUTH)),
1603
+ _ts_param5(1, (0, import_common9.Inject)(DASHBOARD_BASE_PATH)),
1604
+ _ts_metadata5("design:type", Function),
1605
+ _ts_metadata5("design:paramtypes", [
1606
+ Object,
1607
+ String
1608
+ ])
1609
+ ], DashboardAuthPageGuard);
1610
+
1611
+ // src/server/agent-ui.controller.ts
1612
+ function _ts_decorate7(decorators, target, key, desc) {
1613
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1614
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1615
+ 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;
1616
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1617
+ }
1618
+ __name(_ts_decorate7, "_ts_decorate");
1619
+ function _ts_metadata6(k, v) {
1620
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1621
+ }
1622
+ __name(_ts_metadata6, "_ts_metadata");
1623
+ function _ts_param6(paramIndex, decorator) {
1624
+ return function(target, key) {
1625
+ decorator(target, key, paramIndex);
1626
+ };
1627
+ }
1628
+ __name(_ts_param6, "_ts_param");
883
1629
  var BUILD_BASE = "/ai-gateway";
884
1630
  function spaDir() {
885
1631
  return (0, import_node_url.fileURLToPath)(new URL("../spa", __importMetaUrl));
@@ -915,7 +1661,7 @@ var AgentUiController = class {
915
1661
  }
916
1662
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
917
1663
  if (!(0, import_node_fs.existsSync)(indexPath)) {
918
- throw new import_common6.NotFoundException("Dashboard is not built. Run the package build.");
1664
+ throw new import_common10.NotFoundException("Dashboard is not built. Run the package build.");
919
1665
  }
920
1666
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
921
1667
  const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;
@@ -923,78 +1669,147 @@ var AgentUiController = class {
923
1669
  }
924
1670
  asset(file) {
925
1671
  const safe = (0, import_node_path.basename)(file);
926
- if (safe !== file) throw new import_common6.NotFoundException();
1672
+ if (safe !== file) throw new import_common10.NotFoundException();
927
1673
  const root = (0, import_node_path.resolve)(this.dir, "assets");
928
1674
  const assetPath = (0, import_node_path.resolve)(root, safe);
929
1675
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
930
- throw new import_common6.NotFoundException();
1676
+ throw new import_common10.NotFoundException();
931
1677
  }
932
1678
  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), {
1679
+ return new import_common10.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
934
1680
  type
935
1681
  });
936
1682
  }
937
1683
  };
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)({
1684
+ _ts_decorate7([
1685
+ (0, import_common10.Get)(),
1686
+ (0, import_common10.Header)("Content-Type", "text/html; charset=utf-8"),
1687
+ (0, import_common10.Header)("Cache-Control", "no-store, must-revalidate"),
1688
+ _ts_param6(0, (0, import_common10.Req)()),
1689
+ _ts_param6(1, (0, import_common10.Res)({
944
1690
  passthrough: true
945
1691
  })),
946
- _ts_metadata3("design:type", Function),
947
- _ts_metadata3("design:paramtypes", [
1692
+ _ts_metadata6("design:type", Function),
1693
+ _ts_metadata6("design:paramtypes", [
948
1694
  typeof UiPageRequest === "undefined" ? Object : UiPageRequest,
949
1695
  typeof UiPageResponse === "undefined" ? Object : UiPageResponse
950
1696
  ]),
951
- _ts_metadata3("design:returntype", String)
1697
+ _ts_metadata6("design:returntype", String)
952
1698
  ], 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", [
1699
+ _ts_decorate7([
1700
+ (0, import_common10.Get)("assets/:file"),
1701
+ (0, import_common10.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1702
+ _ts_param6(0, (0, import_common10.Param)("file")),
1703
+ _ts_metadata6("design:type", Function),
1704
+ _ts_metadata6("design:paramtypes", [
959
1705
  String
960
1706
  ]),
961
- _ts_metadata3("design:returntype", typeof import_common6.StreamableFile === "undefined" ? Object : import_common6.StreamableFile)
1707
+ _ts_metadata6("design:returntype", typeof import_common10.StreamableFile === "undefined" ? Object : import_common10.StreamableFile)
962
1708
  ], 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", [
1709
+ AgentUiController = _ts_decorate7([
1710
+ (0, import_common10.Controller)(),
1711
+ (0, import_common10.UseGuards)(DashboardAuthPageGuard),
1712
+ (0, import_common10.UseFilters)(new DashboardAuthRedirectFilter()),
1713
+ _ts_param6(0, (0, import_common10.Inject)(DASHBOARD_BASE_PATH)),
1714
+ _ts_param6(1, (0, import_common10.Inject)(DASHBOARD_API_PATH)),
1715
+ _ts_metadata6("design:type", Function),
1716
+ _ts_metadata6("design:paramtypes", [
969
1717
  String,
970
1718
  String
971
1719
  ])
972
1720
  ], AgentUiController);
973
1721
 
1722
+ // src/server/auth/dashboard-auth-config.ts
1723
+ var DEFAULT_TTL = "8h";
1724
+ function unitToMs(unit) {
1725
+ switch (unit) {
1726
+ case "ms":
1727
+ return 1;
1728
+ case "s":
1729
+ return 1e3;
1730
+ case "m":
1731
+ return 6e4;
1732
+ case "h":
1733
+ return 36e5;
1734
+ case "d":
1735
+ return 864e5;
1736
+ default:
1737
+ return void 0;
1738
+ }
1739
+ }
1740
+ __name(unitToMs, "unitToMs");
1741
+ function durationToMs(duration) {
1742
+ const match = /^(\d+)(ms|s|m|h|d)$/.exec(duration.trim());
1743
+ const amount = match?.[1];
1744
+ const unit = match?.[2] !== void 0 ? unitToMs(match[2]) : void 0;
1745
+ if (amount === void 0 || unit === void 0) {
1746
+ throw new Error(`AgentDashboardModule dashboardAuth: invalid \`ttl\` duration: ${duration}`);
1747
+ }
1748
+ return Number(amount) * unit;
1749
+ }
1750
+ __name(durationToMs, "durationToMs");
1751
+ function resolveDashboardAuth(options) {
1752
+ if (options === void 0) return null;
1753
+ if (typeof options.secret !== "string" || options.secret === "") {
1754
+ throw new Error("AgentDashboardModule dashboardAuth: `secret` is required and must be a non-empty string (HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.");
1755
+ }
1756
+ if (typeof options.login !== "function") {
1757
+ throw new Error("AgentDashboardModule dashboardAuth: `login` is required (validates submitted credentials for the built-in login screen). Failing closed.");
1758
+ }
1759
+ return {
1760
+ secret: options.secret,
1761
+ ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
1762
+ login: options.login
1763
+ };
1764
+ }
1765
+ __name(resolveDashboardAuth, "resolveDashboardAuth");
1766
+
1767
+ // src/server/guards.ts
1768
+ var import_reflect_metadata = require("reflect-metadata");
1769
+ var GUARDS_METADATA = "__guards__";
1770
+ function isGuardClass(guard) {
1771
+ return typeof guard === "function";
1772
+ }
1773
+ __name(isGuardClass, "isGuardClass");
1774
+ function baseGuards(controller) {
1775
+ return Reflect.getOwnMetadata(GUARDS_METADATA, controller) ?? [];
1776
+ }
1777
+ __name(baseGuards, "baseGuards");
1778
+ function stampGuards(guards, entries) {
1779
+ for (const [controller, base] of entries) {
1780
+ Reflect.defineMetadata(GUARDS_METADATA, [
1781
+ ...base,
1782
+ ...guards ?? []
1783
+ ], controller);
1784
+ }
1785
+ }
1786
+ __name(stampGuards, "stampGuards");
1787
+
974
1788
  // src/server/agent-dashboard.module.ts
975
- function _ts_decorate4(decorators, target, key, desc) {
1789
+ function _ts_decorate8(decorators, target, key, desc) {
976
1790
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
977
1791
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
978
1792
  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
1793
  return c > 3 && r && Object.defineProperty(target, key, r), r;
980
1794
  }
981
- __name(_ts_decorate4, "_ts_decorate");
982
- var GUARDS_METADATA = "__guards__";
1795
+ __name(_ts_decorate8, "_ts_decorate");
1796
+ var API_BASE_GUARDS = baseGuards(AgentApiController);
1797
+ var UI_BASE_GUARDS = baseGuards(AgentUiController);
983
1798
  function normalize(path) {
984
1799
  return normalizeDashboardPath(path);
985
1800
  }
986
1801
  __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
1802
  var AgentApiModule = class _AgentApiModule {
994
1803
  static {
995
1804
  __name(this, "AgentApiModule");
996
1805
  }
997
1806
  static register(options) {
1807
+ stampGuards(options.guards, [
1808
+ [
1809
+ AgentApiController,
1810
+ API_BASE_GUARDS
1811
+ ]
1812
+ ]);
998
1813
  return {
999
1814
  module: _AgentApiModule,
1000
1815
  imports: [
@@ -1005,7 +1820,9 @@ var AgentApiModule = class _AgentApiModule {
1005
1820
  ],
1006
1821
  providers: [
1007
1822
  DashboardService,
1008
- ...options.guards ?? [],
1823
+ DashboardAuthGuard,
1824
+ options.dashboardAuth,
1825
+ ...(options.guards ?? []).filter(isGuardClass),
1009
1826
  // `useValue` even when `options.approvalActorRef` is `undefined` — AgentApiController
1010
1827
  // injects this WITHOUT `@Optional()` (same pattern as `AGENT_QUOTA_STORE`'s factory).
1011
1828
  {
@@ -1013,14 +1830,18 @@ var AgentApiModule = class _AgentApiModule {
1013
1830
  useValue: options.approvalActorRef
1014
1831
  }
1015
1832
  ],
1833
+ // DASHBOARD_AUTH re-exported so AgentUiController/AgentDashboardAuthController (hosted
1834
+ // directly by AgentDashboardModule, which imports this module) resolve the SAME instance
1835
+ // instead of re-running a host's async factory a second time.
1016
1836
  exports: [
1017
- DashboardService
1837
+ DashboardService,
1838
+ DASHBOARD_AUTH
1018
1839
  ]
1019
1840
  };
1020
1841
  }
1021
1842
  };
1022
- AgentApiModule = _ts_decorate4([
1023
- (0, import_common7.Module)({})
1843
+ AgentApiModule = _ts_decorate8([
1844
+ (0, import_common11.Module)({})
1024
1845
  ], AgentApiModule);
1025
1846
  var AgentDashboardModule = class _AgentDashboardModule {
1026
1847
  static {
@@ -1029,7 +1850,16 @@ var AgentDashboardModule = class _AgentDashboardModule {
1029
1850
  static forRoot(options = {}) {
1030
1851
  const basePath = normalize(options.basePath ?? "/ai-gateway");
1031
1852
  const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
1032
- stampGuards(options.guards, AgentApiController, AgentUiController);
1853
+ stampGuards(options.guards, [
1854
+ [
1855
+ AgentUiController,
1856
+ UI_BASE_GUARDS
1857
+ ]
1858
+ ]);
1859
+ const dashboardAuthProvider = {
1860
+ provide: DASHBOARD_AUTH,
1861
+ useValue: resolveDashboardAuth(options.dashboardAuth)
1862
+ };
1033
1863
  return {
1034
1864
  module: _AgentDashboardModule,
1035
1865
  imports: [
@@ -1046,7 +1876,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
1046
1876
  } : {},
1047
1877
  ...options.approvalActorRef ? {
1048
1878
  approvalActorRef: options.approvalActorRef
1049
- } : {}
1879
+ } : {},
1880
+ dashboardAuth: dashboardAuthProvider
1050
1881
  }),
1051
1882
  import_core.RouterModule.register([
1052
1883
  {
@@ -1060,7 +1891,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
1060
1891
  ])
1061
1892
  ],
1062
1893
  controllers: [
1063
- AgentUiController
1894
+ AgentUiController,
1895
+ AgentDashboardAuthController
1064
1896
  ],
1065
1897
  providers: [
1066
1898
  {
@@ -1071,8 +1903,9 @@ var AgentDashboardModule = class _AgentDashboardModule {
1071
1903
  provide: DASHBOARD_API_PATH,
1072
1904
  useValue: apiBasePath
1073
1905
  },
1906
+ DashboardAuthPageGuard,
1074
1907
  // AgentUiController is hosted HERE, so its guards DI-instantiate from this module.
1075
- ...options.guards ?? []
1908
+ ...(options.guards ?? []).filter(isGuardClass)
1076
1909
  ],
1077
1910
  // Re-export the API module so its DashboardService reaches importers (e.g. the host's own controllers).
1078
1911
  exports: [
@@ -1080,9 +1913,71 @@ var AgentDashboardModule = class _AgentDashboardModule {
1080
1913
  ]
1081
1914
  };
1082
1915
  }
1916
+ static forRootAsync(options) {
1917
+ const basePath = normalize(options.basePath ?? "/ai-gateway");
1918
+ const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
1919
+ stampGuards(options.guards, [
1920
+ [
1921
+ AgentUiController,
1922
+ UI_BASE_GUARDS
1923
+ ]
1924
+ ]);
1925
+ const dashboardAuthProvider = {
1926
+ provide: DASHBOARD_AUTH,
1927
+ inject: options.inject ?? [],
1928
+ useFactory: /* @__PURE__ */ __name(async (...deps) => resolveDashboardAuth(await options.useDashboardAuth(...deps)), "useFactory")
1929
+ };
1930
+ return {
1931
+ module: _AgentDashboardModule,
1932
+ imports: [
1933
+ ...options.imports ?? [],
1934
+ AgentApiModule.register({
1935
+ ...options.imports ? {
1936
+ imports: options.imports
1937
+ } : {},
1938
+ ...options.guards ? {
1939
+ guards: options.guards
1940
+ } : {},
1941
+ ...options.approvalActorRef ? {
1942
+ approvalActorRef: options.approvalActorRef
1943
+ } : {},
1944
+ dashboardAuth: dashboardAuthProvider
1945
+ }),
1946
+ import_core.RouterModule.register([
1947
+ {
1948
+ path: basePath,
1949
+ module: _AgentDashboardModule
1950
+ },
1951
+ {
1952
+ path: apiBasePath,
1953
+ module: AgentApiModule
1954
+ }
1955
+ ])
1956
+ ],
1957
+ controllers: [
1958
+ AgentUiController,
1959
+ AgentDashboardAuthController
1960
+ ],
1961
+ providers: [
1962
+ {
1963
+ provide: DASHBOARD_BASE_PATH,
1964
+ useValue: basePath
1965
+ },
1966
+ {
1967
+ provide: DASHBOARD_API_PATH,
1968
+ useValue: apiBasePath
1969
+ },
1970
+ DashboardAuthPageGuard,
1971
+ ...(options.guards ?? []).filter(isGuardClass)
1972
+ ],
1973
+ exports: [
1974
+ AgentApiModule
1975
+ ]
1976
+ };
1977
+ }
1083
1978
  };
1084
- AgentDashboardModule = _ts_decorate4([
1085
- (0, import_common7.Module)({})
1979
+ AgentDashboardModule = _ts_decorate8([
1980
+ (0, import_common11.Module)({})
1086
1981
  ], AgentDashboardModule);
1087
1982
  // Annotate the CommonJS export names for ESM import in node:
1088
1983
  0 && (module.exports = {
@@ -1093,13 +1988,16 @@ AgentDashboardModule = _ts_decorate4([
1093
1988
  AGENT_PRICING_STORE,
1094
1989
  AgentApiController,
1095
1990
  AgentApiModule,
1991
+ AgentDashboardAuthController,
1096
1992
  AgentDashboardModule,
1097
1993
  AgentUiController,
1098
1994
  DASHBOARD_API_PATH,
1099
1995
  DASHBOARD_APPROVAL_ACTOR_REF,
1996
+ DASHBOARD_AUTH,
1100
1997
  DASHBOARD_BASE_PATH,
1101
1998
  DashboardService,
1102
1999
  agentDashboardMountPaths,
1103
- parsePriceInput
2000
+ parsePriceInput,
2001
+ resolveDashboardAuth
1104
2002
  });
1105
2003
  //# sourceMappingURL=index.cjs.map