@dudousxd/nestjs-agent-dashboard 0.7.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_common4 = 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 = [
@@ -209,6 +538,14 @@ var DashboardService = class {
209
538
  recentToolCalls(limit) {
210
539
  return this.queries.recentToolCalls(limit);
211
540
  }
541
+ /** Paged, filterable tool calls for the Runs & tools activity table. */
542
+ toolCallsPage(query) {
543
+ return this.queries.toolCallsPage(query);
544
+ }
545
+ /** Paged, filterable runs for the Reliability recent-runs table. */
546
+ runsPage(query) {
547
+ return this.queries.runsPage(query);
548
+ }
212
549
  /** Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox. */
213
550
  pendingApprovals(limit) {
214
551
  return this.queries.pendingApprovals(limit);
@@ -227,7 +564,7 @@ var DashboardService = class {
227
564
  */
228
565
  async decideApproval(toolCallId, body, executedByRef) {
229
566
  if (this.approvalPort === void 0) {
230
- throw new import_common3.NotImplementedException(APPROVAL_PORT_UNBOUND_MESSAGE);
567
+ throw new import_common4.NotImplementedException(APPROVAL_PORT_UNBOUND_MESSAGE);
231
568
  }
232
569
  const decision = parseApprovalDecision(body);
233
570
  const opts = executedByRef !== void 0 ? {
@@ -250,6 +587,18 @@ var DashboardService = class {
250
587
  return this.withActorLabels(rows);
251
588
  }
252
589
  /**
590
+ * Paged, filterable threads for the Runs & tools threads table — actor-labeled the same way
591
+ * {@link recentThreads} is.
592
+ */
593
+ async threadsPage(query) {
594
+ const page = await this.queries.threadsPage(query);
595
+ const rows = await this.withActorLabels(page.rows);
596
+ return {
597
+ ...page,
598
+ rows
599
+ };
600
+ }
601
+ /**
253
602
  * Decorate actor-scoped rows with `actorLabel`, batching the distinct `actorRef`s into ONE
254
603
  * {@link ActorDirectory.resolveDisplay} call per response. `null` for every row when no directory
255
604
  * is bound, or for a ref the directory didn't resolve.
@@ -276,7 +625,7 @@ var DashboardService = class {
276
625
  /** Current price row per model, for the pricing tab. 501s when no `AGENT_PRICING_STORE` is bound. */
277
626
  async listPrices() {
278
627
  if (this.pricingStore === void 0) {
279
- throw new import_common3.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
628
+ throw new import_common4.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
280
629
  }
281
630
  return this.pricingStore.listCurrentPrices();
282
631
  }
@@ -287,7 +636,7 @@ var DashboardService = class {
287
636
  */
288
637
  async upsertPrice(body) {
289
638
  if (this.pricingStore === void 0) {
290
- throw new import_common3.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
639
+ throw new import_common4.NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
291
640
  }
292
641
  await this.pricingStore.upsertModelPrice(parsePriceInput(body));
293
642
  }
@@ -322,17 +671,17 @@ var DashboardService = class {
322
671
  });
323
672
  }
324
673
  };
325
- DashboardService = _ts_decorate([
326
- (0, import_common3.Injectable)(),
327
- _ts_param(0, (0, import_common3.Inject)(AGENT_GOVERNANCE_QUERIES)),
328
- _ts_param(1, (0, import_common3.Optional)()),
329
- _ts_param(1, (0, import_common3.Inject)(AGENT_ACTOR_DIRECTORY)),
330
- _ts_param(2, (0, import_common3.Optional)()),
331
- _ts_param(2, (0, import_common3.Inject)(AGENT_PRICING_STORE)),
332
- _ts_param(3, (0, import_common3.Optional)()),
333
- _ts_param(3, (0, import_common3.Inject)(AGENT_APPROVAL_PORT)),
334
- _ts_metadata("design:type", Function),
335
- _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", [
336
685
  typeof AgentGovernanceQueries === "undefined" ? Object : AgentGovernanceQueries,
337
686
  typeof ActorDirectory === "undefined" ? Object : ActorDirectory,
338
687
  typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
@@ -340,32 +689,153 @@ DashboardService = _ts_decorate([
340
689
  ])
341
690
  ], DashboardService);
342
691
 
692
+ // src/server/parse-page-query.ts
693
+ var import_common5 = require("@nestjs/common");
694
+ var ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
695
+ function parsePageNumber(value) {
696
+ const parsed = value === void 0 ? Number.NaN : Number.parseInt(value, 10);
697
+ if (!Number.isFinite(parsed) || parsed < 1) return 1;
698
+ return parsed;
699
+ }
700
+ __name(parsePageNumber, "parsePageNumber");
701
+ function assertKnownFields(raw, allowed) {
702
+ for (const field of Object.keys(raw)) {
703
+ if (!allowed.includes(field)) {
704
+ throw new import_common5.BadRequestException(`Unknown where field "${field}".`);
705
+ }
706
+ }
707
+ }
708
+ __name(assertKnownFields, "assertKnownFields");
709
+ function assertDayFields(raw, dayFields) {
710
+ for (const field of dayFields) {
711
+ const value = raw[field];
712
+ if (value !== void 0 && !ISO_DAY.test(value)) {
713
+ throw new import_common5.BadRequestException(`"where[${field}]" must be YYYY-MM-DD.`);
714
+ }
715
+ }
716
+ }
717
+ __name(assertDayFields, "assertDayFields");
718
+ var DAY_FIELDS = [
719
+ "fromDay",
720
+ "toDay"
721
+ ];
722
+ var TOOL_CALL_WHERE_FIELDS = [
723
+ "toolName",
724
+ "toolType",
725
+ "status",
726
+ "threadId",
727
+ "fromDay",
728
+ "toDay"
729
+ ];
730
+ function parseToolCallWhere(raw) {
731
+ if (raw === void 0 || Object.keys(raw).length === 0) return void 0;
732
+ assertKnownFields(raw, TOOL_CALL_WHERE_FIELDS);
733
+ assertDayFields(raw, DAY_FIELDS);
734
+ return {
735
+ ...raw.toolName !== void 0 ? {
736
+ toolName: raw.toolName
737
+ } : {},
738
+ ...raw.toolType !== void 0 ? {
739
+ toolType: raw.toolType
740
+ } : {},
741
+ ...raw.status !== void 0 ? {
742
+ status: raw.status
743
+ } : {},
744
+ ...raw.threadId !== void 0 ? {
745
+ threadId: raw.threadId
746
+ } : {},
747
+ ...raw.fromDay !== void 0 ? {
748
+ fromDay: raw.fromDay
749
+ } : {},
750
+ ...raw.toDay !== void 0 ? {
751
+ toDay: raw.toDay
752
+ } : {}
753
+ };
754
+ }
755
+ __name(parseToolCallWhere, "parseToolCallWhere");
756
+ var THREAD_WHERE_FIELDS = [
757
+ "actorRef",
758
+ "title",
759
+ "fromDay",
760
+ "toDay"
761
+ ];
762
+ function parseThreadWhere(raw) {
763
+ if (raw === void 0 || Object.keys(raw).length === 0) return void 0;
764
+ assertKnownFields(raw, THREAD_WHERE_FIELDS);
765
+ assertDayFields(raw, DAY_FIELDS);
766
+ return {
767
+ ...raw.actorRef !== void 0 ? {
768
+ actorRef: raw.actorRef
769
+ } : {},
770
+ ...raw.title !== void 0 ? {
771
+ title: raw.title
772
+ } : {},
773
+ ...raw.fromDay !== void 0 ? {
774
+ fromDay: raw.fromDay
775
+ } : {},
776
+ ...raw.toDay !== void 0 ? {
777
+ toDay: raw.toDay
778
+ } : {}
779
+ };
780
+ }
781
+ __name(parseThreadWhere, "parseThreadWhere");
782
+ var RUN_WHERE_FIELDS = [
783
+ "agentName",
784
+ "status",
785
+ "errorCode",
786
+ "fromDay",
787
+ "toDay"
788
+ ];
789
+ function parseRunWhere(raw) {
790
+ if (raw === void 0 || Object.keys(raw).length === 0) return void 0;
791
+ assertKnownFields(raw, RUN_WHERE_FIELDS);
792
+ assertDayFields(raw, DAY_FIELDS);
793
+ return {
794
+ ...raw.agentName !== void 0 ? {
795
+ agentName: raw.agentName
796
+ } : {},
797
+ ...raw.status !== void 0 ? {
798
+ status: raw.status
799
+ } : {},
800
+ ...raw.errorCode !== void 0 ? {
801
+ errorCode: raw.errorCode
802
+ } : {},
803
+ ...raw.fromDay !== void 0 ? {
804
+ fromDay: raw.fromDay
805
+ } : {},
806
+ ...raw.toDay !== void 0 ? {
807
+ toDay: raw.toDay
808
+ } : {}
809
+ };
810
+ }
811
+ __name(parseRunWhere, "parseRunWhere");
812
+
343
813
  // src/server/agent-api.controller.ts
344
- function _ts_decorate2(decorators, target, key, desc) {
814
+ function _ts_decorate3(decorators, target, key, desc) {
345
815
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
346
816
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
347
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;
348
818
  return c > 3 && r && Object.defineProperty(target, key, r), r;
349
819
  }
350
- __name(_ts_decorate2, "_ts_decorate");
351
- function _ts_metadata2(k, v) {
820
+ __name(_ts_decorate3, "_ts_decorate");
821
+ function _ts_metadata3(k, v) {
352
822
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
353
823
  }
354
- __name(_ts_metadata2, "_ts_metadata");
355
- function _ts_param2(paramIndex, decorator) {
824
+ __name(_ts_metadata3, "_ts_metadata");
825
+ function _ts_param3(paramIndex, decorator) {
356
826
  return function(target, key) {
357
827
  decorator(target, key, paramIndex);
358
828
  };
359
829
  }
360
- __name(_ts_param2, "_ts_param");
830
+ __name(_ts_param3, "_ts_param");
361
831
  var DAY_MS = 864e5;
362
- var ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
832
+ var ISO_DAY2 = /^\d{4}-\d{2}-\d{2}$/;
363
833
  function utcDay(daysAgo) {
364
834
  return new Date(Date.now() - daysAgo * DAY_MS).toISOString().slice(0, 10);
365
835
  }
366
836
  __name(utcDay, "utcDay");
367
837
  function dayOr(value, fallback) {
368
- return value !== void 0 && ISO_DAY.test(value) ? value : fallback;
838
+ return value !== void 0 && ISO_DAY2.test(value) ? value : fallback;
369
839
  }
370
840
  __name(dayOr, "dayOr");
371
841
  function resolveRange(from, to) {
@@ -409,10 +879,40 @@ var AgentApiController = class {
409
879
  runs(limit) {
410
880
  return this.dashboard.recentRuns(parseLimit(limit, 50));
411
881
  }
882
+ /**
883
+ * Paged, filterable runs for the Reliability recent-runs table. `page` (default 1), `limit`
884
+ * (default 25, max 200), and `where[agentName]`/`where[status]`/`where[errorCode]`/
885
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
886
+ */
887
+ runsPage(page, limit, where) {
888
+ const parsedWhere = parseRunWhere(where);
889
+ return this.dashboard.runsPage({
890
+ page: parsePageNumber(page),
891
+ pageSize: parseLimit(limit, 25),
892
+ ...parsedWhere !== void 0 ? {
893
+ where: parsedWhere
894
+ } : {}
895
+ });
896
+ }
412
897
  /** Most recent tool calls (default 50, max 200) for the activity feed. */
413
898
  toolCalls(limit) {
414
899
  return this.dashboard.recentToolCalls(parseLimit(limit, 50));
415
900
  }
901
+ /**
902
+ * Paged, filterable tool calls for the Runs & tools activity table. `page` (default 1), `limit`
903
+ * (default 25, max 200), and `where[toolName]`/`where[toolType]`/`where[status]`/`where[threadId]`/
904
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
905
+ */
906
+ toolCallsPage(page, limit, where) {
907
+ const parsedWhere = parseToolCallWhere(where);
908
+ return this.dashboard.toolCallsPage({
909
+ page: parsePageNumber(page),
910
+ pageSize: parseLimit(limit, 25),
911
+ ...parsedWhere !== void 0 ? {
912
+ where: parsedWhere
913
+ } : {}
914
+ });
915
+ }
416
916
  /** Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox. */
417
917
  approvals(limit) {
418
918
  return this.dashboard.pendingApprovals(parseLimit(limit, 50));
@@ -454,6 +954,21 @@ var AgentApiController = class {
454
954
  return this.dashboard.recentThreads(parseLimit(limit, 50));
455
955
  }
456
956
  /**
957
+ * Paged, filterable threads for the Runs & tools threads table. `page` (default 1), `limit`
958
+ * (default 25, max 200), and `where[actorRef]`/`where[title]` (case-insensitive substring)/
959
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
960
+ */
961
+ threadsPage(page, limit, where) {
962
+ const parsedWhere = parseThreadWhere(where);
963
+ return this.dashboard.threadsPage({
964
+ page: parsePageNumber(page),
965
+ pageSize: parseLimit(limit, 25),
966
+ ...parsedWhere !== void 0 ? {
967
+ where: parsedWhere
968
+ } : {}
969
+ });
970
+ }
971
+ /**
457
972
  * Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when
458
973
  * no `AGENT_PRICING_STORE` is bound.
459
974
  */
@@ -473,136 +988,469 @@ var AgentApiController = class {
473
988
  return this.dashboard.streamEvents();
474
989
  }
475
990
  };
476
- _ts_decorate2([
477
- (0, import_common4.Get)("spend"),
478
- _ts_param2(0, (0, import_common4.Query)("from")),
479
- _ts_param2(1, (0, import_common4.Query)("to")),
480
- _ts_metadata2("design:type", Function),
481
- _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", [
482
997
  String,
483
998
  String
484
999
  ]),
485
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1000
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
486
1001
  ], AgentApiController.prototype, "spend", null);
487
- _ts_decorate2([
488
- (0, import_common4.Get)("top-threads"),
489
- _ts_param2(0, (0, import_common4.Query)("from")),
490
- _ts_param2(1, (0, import_common4.Query)("to")),
491
- _ts_param2(2, (0, import_common4.Query)("limit")),
492
- _ts_metadata2("design:type", Function),
493
- _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", [
494
1009
  String,
495
1010
  String,
496
1011
  String
497
1012
  ]),
498
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1013
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
499
1014
  ], AgentApiController.prototype, "topThreads", null);
500
- _ts_decorate2([
501
- (0, import_common4.Get)("reliability"),
502
- _ts_param2(0, (0, import_common4.Query)("from")),
503
- _ts_param2(1, (0, import_common4.Query)("to")),
504
- _ts_metadata2("design:type", Function),
505
- _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", [
506
1021
  String,
507
1022
  String
508
1023
  ]),
509
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1024
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
510
1025
  ], AgentApiController.prototype, "reliability", null);
511
- _ts_decorate2([
512
- (0, import_common4.Get)("runs"),
513
- _ts_param2(0, (0, import_common4.Query)("limit")),
514
- _ts_metadata2("design:type", Function),
515
- _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", [
516
1031
  String
517
1032
  ]),
518
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1033
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
519
1034
  ], AgentApiController.prototype, "runs", null);
520
- _ts_decorate2([
521
- (0, import_common4.Get)("tool-calls"),
522
- _ts_param2(0, (0, import_common4.Query)("limit")),
523
- _ts_metadata2("design:type", Function),
524
- _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", [
1042
+ String,
1043
+ String,
1044
+ typeof Record === "undefined" ? Object : Record
1045
+ ]),
1046
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1047
+ ], AgentApiController.prototype, "runsPage", null);
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", [
525
1053
  String
526
1054
  ]),
527
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1055
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
528
1056
  ], AgentApiController.prototype, "toolCalls", null);
529
- _ts_decorate2([
530
- (0, import_common4.Get)("approvals"),
531
- _ts_param2(0, (0, import_common4.Query)("limit")),
532
- _ts_metadata2("design:type", Function),
533
- _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", [
1064
+ String,
1065
+ String,
1066
+ typeof Record === "undefined" ? Object : Record
1067
+ ]),
1068
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1069
+ ], AgentApiController.prototype, "toolCallsPage", null);
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", [
534
1075
  String
535
1076
  ]),
536
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1077
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
537
1078
  ], AgentApiController.prototype, "approvals", null);
538
- _ts_decorate2([
539
- (0, import_common4.Post)("approvals/:toolCallId"),
540
- (0, import_common4.HttpCode)(204),
541
- _ts_param2(0, (0, import_common4.Param)("toolCallId")),
542
- _ts_param2(1, (0, import_common4.Body)()),
543
- _ts_param2(2, (0, import_common4.Req)()),
544
- _ts_metadata2("design:type", Function),
545
- _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", [
546
1087
  String,
547
1088
  Object,
548
1089
  Object
549
1090
  ]),
550
- _ts_metadata2("design:returntype", Promise)
1091
+ _ts_metadata3("design:returntype", Promise)
551
1092
  ], AgentApiController.prototype, "decideApproval", null);
552
- _ts_decorate2([
553
- (0, import_common4.Get)("tools"),
554
- _ts_param2(0, (0, import_common4.Query)("from")),
555
- _ts_param2(1, (0, import_common4.Query)("to")),
556
- _ts_metadata2("design:type", Function),
557
- _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", [
558
1099
  String,
559
1100
  String
560
1101
  ]),
561
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1102
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
562
1103
  ], AgentApiController.prototype, "tools", null);
563
- _ts_decorate2([
564
- (0, import_common4.Get)("threads"),
565
- _ts_param2(0, (0, import_common4.Query)("limit")),
566
- _ts_metadata2("design:type", Function),
567
- _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", [
568
1109
  String
569
1110
  ]),
570
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1111
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
571
1112
  ], AgentApiController.prototype, "threads", null);
572
- _ts_decorate2([
573
- (0, import_common4.Get)("pricing"),
574
- _ts_metadata2("design:type", Function),
575
- _ts_metadata2("design:paramtypes", []),
576
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
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", [
1120
+ String,
1121
+ String,
1122
+ typeof Record === "undefined" ? Object : Record
1123
+ ]),
1124
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1125
+ ], AgentApiController.prototype, "threadsPage", null);
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)
577
1131
  ], AgentApiController.prototype, "listPrices", null);
578
- _ts_decorate2([
579
- (0, import_common4.Post)("pricing"),
580
- _ts_param2(0, (0, import_common4.Body)()),
581
- _ts_metadata2("design:type", Function),
582
- _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", [
583
1137
  Object
584
1138
  ]),
585
- _ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1139
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
586
1140
  ], AgentApiController.prototype, "upsertPrice", null);
587
- _ts_decorate2([
588
- (0, import_common4.Sse)("stream"),
589
- _ts_metadata2("design:type", Function),
590
- _ts_metadata2("design:paramtypes", []),
591
- _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)
592
1146
  ], AgentApiController.prototype, "stream", null);
593
- AgentApiController = _ts_decorate2([
594
- (0, import_common4.Controller)(),
595
- _ts_param2(1, (0, import_common4.Inject)(DASHBOARD_APPROVAL_ACTOR_REF)),
596
- _ts_param2(2, (0, import_common4.Optional)()),
597
- _ts_param2(2, (0, import_common4.Inject)(AGENT_ACTOR_RESOLVER)),
598
- _ts_metadata2("design:type", Function),
599
- _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", [
600
1155
  typeof DashboardService === "undefined" ? Object : DashboardService,
601
1156
  Object,
602
1157
  typeof ActorResolver === "undefined" ? Object : ActorResolver
603
1158
  ])
604
1159
  ], AgentApiController);
605
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
+
606
1454
  // src/server/normalize-path.ts
607
1455
  function normalizeDashboardPath(path) {
608
1456
  return `/${path.replace(/^\/+|\/+$/g, "")}`;
@@ -629,32 +1477,155 @@ function agentDashboardMountPaths(options) {
629
1477
  __name(agentDashboardMountPaths, "agentDashboardMountPaths");
630
1478
 
631
1479
  // src/server/agent-dashboard.module.ts
632
- var import_reflect_metadata = require("reflect-metadata");
633
- var import_common6 = require("@nestjs/common");
1480
+ var import_reflect_metadata2 = require("reflect-metadata");
1481
+ var import_common11 = require("@nestjs/common");
634
1482
  var import_core = require("@nestjs/core");
635
1483
 
636
1484
  // src/server/agent-ui.controller.ts
637
1485
  var import_node_fs = require("fs");
638
1486
  var import_node_path = require("path");
639
1487
  var import_node_url = require("url");
640
- var import_common5 = require("@nestjs/common");
641
- 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) {
642
1496
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
643
1497
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
644
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;
645
1499
  return c > 3 && r && Object.defineProperty(target, key, r), r;
646
1500
  }
647
- __name(_ts_decorate3, "_ts_decorate");
648
- 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) {
649
1535
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
650
1536
  }
651
- __name(_ts_metadata3, "_ts_metadata");
652
- function _ts_param3(paramIndex, decorator) {
1537
+ __name(_ts_metadata5, "_ts_metadata");
1538
+ function _ts_param5(paramIndex, decorator) {
653
1539
  return function(target, key) {
654
1540
  decorator(target, key, paramIndex);
655
1541
  };
656
1542
  }
657
- __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");
658
1629
  var BUILD_BASE = "/ai-gateway";
659
1630
  function spaDir() {
660
1631
  return (0, import_node_url.fileURLToPath)(new URL("../spa", __importMetaUrl));
@@ -690,7 +1661,7 @@ var AgentUiController = class {
690
1661
  }
691
1662
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
692
1663
  if (!(0, import_node_fs.existsSync)(indexPath)) {
693
- throw new import_common5.NotFoundException("Dashboard is not built. Run the package build.");
1664
+ throw new import_common10.NotFoundException("Dashboard is not built. Run the package build.");
694
1665
  }
695
1666
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
696
1667
  const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;
@@ -698,78 +1669,147 @@ var AgentUiController = class {
698
1669
  }
699
1670
  asset(file) {
700
1671
  const safe = (0, import_node_path.basename)(file);
701
- if (safe !== file) throw new import_common5.NotFoundException();
1672
+ if (safe !== file) throw new import_common10.NotFoundException();
702
1673
  const root = (0, import_node_path.resolve)(this.dir, "assets");
703
1674
  const assetPath = (0, import_node_path.resolve)(root, safe);
704
1675
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
705
- throw new import_common5.NotFoundException();
1676
+ throw new import_common10.NotFoundException();
706
1677
  }
707
1678
  const type = CONTENT_TYPES[(0, import_node_path.extname)(safe)] ?? "application/octet-stream";
708
- return new import_common5.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1679
+ return new import_common10.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
709
1680
  type
710
1681
  });
711
1682
  }
712
1683
  };
713
- _ts_decorate3([
714
- (0, import_common5.Get)(),
715
- (0, import_common5.Header)("Content-Type", "text/html; charset=utf-8"),
716
- (0, import_common5.Header)("Cache-Control", "no-store, must-revalidate"),
717
- _ts_param3(0, (0, import_common5.Req)()),
718
- _ts_param3(1, (0, import_common5.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)({
719
1690
  passthrough: true
720
1691
  })),
721
- _ts_metadata3("design:type", Function),
722
- _ts_metadata3("design:paramtypes", [
1692
+ _ts_metadata6("design:type", Function),
1693
+ _ts_metadata6("design:paramtypes", [
723
1694
  typeof UiPageRequest === "undefined" ? Object : UiPageRequest,
724
1695
  typeof UiPageResponse === "undefined" ? Object : UiPageResponse
725
1696
  ]),
726
- _ts_metadata3("design:returntype", String)
1697
+ _ts_metadata6("design:returntype", String)
727
1698
  ], AgentUiController.prototype, "index", null);
728
- _ts_decorate3([
729
- (0, import_common5.Get)("assets/:file"),
730
- (0, import_common5.Header)("Cache-Control", "public, max-age=31536000, immutable"),
731
- _ts_param3(0, (0, import_common5.Param)("file")),
732
- _ts_metadata3("design:type", Function),
733
- _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", [
734
1705
  String
735
1706
  ]),
736
- _ts_metadata3("design:returntype", typeof import_common5.StreamableFile === "undefined" ? Object : import_common5.StreamableFile)
1707
+ _ts_metadata6("design:returntype", typeof import_common10.StreamableFile === "undefined" ? Object : import_common10.StreamableFile)
737
1708
  ], AgentUiController.prototype, "asset", null);
738
- AgentUiController = _ts_decorate3([
739
- (0, import_common5.Controller)(),
740
- _ts_param3(0, (0, import_common5.Inject)(DASHBOARD_BASE_PATH)),
741
- _ts_param3(1, (0, import_common5.Inject)(DASHBOARD_API_PATH)),
742
- _ts_metadata3("design:type", Function),
743
- _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", [
744
1717
  String,
745
1718
  String
746
1719
  ])
747
1720
  ], AgentUiController);
748
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
+
749
1788
  // src/server/agent-dashboard.module.ts
750
- function _ts_decorate4(decorators, target, key, desc) {
1789
+ function _ts_decorate8(decorators, target, key, desc) {
751
1790
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
752
1791
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
753
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;
754
1793
  return c > 3 && r && Object.defineProperty(target, key, r), r;
755
1794
  }
756
- __name(_ts_decorate4, "_ts_decorate");
757
- var GUARDS_METADATA = "__guards__";
1795
+ __name(_ts_decorate8, "_ts_decorate");
1796
+ var API_BASE_GUARDS = baseGuards(AgentApiController);
1797
+ var UI_BASE_GUARDS = baseGuards(AgentUiController);
758
1798
  function normalize(path) {
759
1799
  return normalizeDashboardPath(path);
760
1800
  }
761
1801
  __name(normalize, "normalize");
762
- function stampGuards(guards, ...controllers) {
763
- for (const controller of controllers) {
764
- Reflect.defineMetadata(GUARDS_METADATA, guards ?? [], controller);
765
- }
766
- }
767
- __name(stampGuards, "stampGuards");
768
1802
  var AgentApiModule = class _AgentApiModule {
769
1803
  static {
770
1804
  __name(this, "AgentApiModule");
771
1805
  }
772
1806
  static register(options) {
1807
+ stampGuards(options.guards, [
1808
+ [
1809
+ AgentApiController,
1810
+ API_BASE_GUARDS
1811
+ ]
1812
+ ]);
773
1813
  return {
774
1814
  module: _AgentApiModule,
775
1815
  imports: [
@@ -780,7 +1820,9 @@ var AgentApiModule = class _AgentApiModule {
780
1820
  ],
781
1821
  providers: [
782
1822
  DashboardService,
783
- ...options.guards ?? [],
1823
+ DashboardAuthGuard,
1824
+ options.dashboardAuth,
1825
+ ...(options.guards ?? []).filter(isGuardClass),
784
1826
  // `useValue` even when `options.approvalActorRef` is `undefined` — AgentApiController
785
1827
  // injects this WITHOUT `@Optional()` (same pattern as `AGENT_QUOTA_STORE`'s factory).
786
1828
  {
@@ -788,14 +1830,18 @@ var AgentApiModule = class _AgentApiModule {
788
1830
  useValue: options.approvalActorRef
789
1831
  }
790
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.
791
1836
  exports: [
792
- DashboardService
1837
+ DashboardService,
1838
+ DASHBOARD_AUTH
793
1839
  ]
794
1840
  };
795
1841
  }
796
1842
  };
797
- AgentApiModule = _ts_decorate4([
798
- (0, import_common6.Module)({})
1843
+ AgentApiModule = _ts_decorate8([
1844
+ (0, import_common11.Module)({})
799
1845
  ], AgentApiModule);
800
1846
  var AgentDashboardModule = class _AgentDashboardModule {
801
1847
  static {
@@ -804,7 +1850,16 @@ var AgentDashboardModule = class _AgentDashboardModule {
804
1850
  static forRoot(options = {}) {
805
1851
  const basePath = normalize(options.basePath ?? "/ai-gateway");
806
1852
  const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
807
- 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
+ };
808
1863
  return {
809
1864
  module: _AgentDashboardModule,
810
1865
  imports: [
@@ -821,7 +1876,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
821
1876
  } : {},
822
1877
  ...options.approvalActorRef ? {
823
1878
  approvalActorRef: options.approvalActorRef
824
- } : {}
1879
+ } : {},
1880
+ dashboardAuth: dashboardAuthProvider
825
1881
  }),
826
1882
  import_core.RouterModule.register([
827
1883
  {
@@ -835,7 +1891,8 @@ var AgentDashboardModule = class _AgentDashboardModule {
835
1891
  ])
836
1892
  ],
837
1893
  controllers: [
838
- AgentUiController
1894
+ AgentUiController,
1895
+ AgentDashboardAuthController
839
1896
  ],
840
1897
  providers: [
841
1898
  {
@@ -846,8 +1903,9 @@ var AgentDashboardModule = class _AgentDashboardModule {
846
1903
  provide: DASHBOARD_API_PATH,
847
1904
  useValue: apiBasePath
848
1905
  },
1906
+ DashboardAuthPageGuard,
849
1907
  // AgentUiController is hosted HERE, so its guards DI-instantiate from this module.
850
- ...options.guards ?? []
1908
+ ...(options.guards ?? []).filter(isGuardClass)
851
1909
  ],
852
1910
  // Re-export the API module so its DashboardService reaches importers (e.g. the host's own controllers).
853
1911
  exports: [
@@ -855,9 +1913,71 @@ var AgentDashboardModule = class _AgentDashboardModule {
855
1913
  ]
856
1914
  };
857
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
+ }
858
1978
  };
859
- AgentDashboardModule = _ts_decorate4([
860
- (0, import_common6.Module)({})
1979
+ AgentDashboardModule = _ts_decorate8([
1980
+ (0, import_common11.Module)({})
861
1981
  ], AgentDashboardModule);
862
1982
  // Annotate the CommonJS export names for ESM import in node:
863
1983
  0 && (module.exports = {
@@ -868,13 +1988,16 @@ AgentDashboardModule = _ts_decorate4([
868
1988
  AGENT_PRICING_STORE,
869
1989
  AgentApiController,
870
1990
  AgentApiModule,
1991
+ AgentDashboardAuthController,
871
1992
  AgentDashboardModule,
872
1993
  AgentUiController,
873
1994
  DASHBOARD_API_PATH,
874
1995
  DASHBOARD_APPROVAL_ACTOR_REF,
1996
+ DASHBOARD_AUTH,
875
1997
  DASHBOARD_BASE_PATH,
876
1998
  DashboardService,
877
1999
  agentDashboardMountPaths,
878
- parsePriceInput
2000
+ parsePriceInput,
2001
+ resolveDashboardAuth
879
2002
  });
880
2003
  //# sourceMappingURL=index.cjs.map