@dudousxd/nestjs-agent-dashboard 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/agent-client.d.ts +38 -0
- package/dist/client/agent-client.d.ts.map +1 -1
- package/dist/client/agent-client.js +19 -0
- package/dist/client/agent-client.js.map +1 -1
- package/dist/client/budget-usage.d.ts +2 -0
- package/dist/client/budget-usage.d.ts.map +1 -1
- package/dist/client/budget-usage.js +1 -0
- package/dist/client/budget-usage.js.map +1 -1
- package/dist/client/format-model.d.ts +10 -0
- package/dist/client/format-model.d.ts.map +1 -0
- package/dist/client/format-model.js +18 -0
- package/dist/client/format-model.js.map +1 -0
- package/dist/server/index.cjs +231 -39
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +121 -8
- package/dist/server/index.d.ts +121 -8
- package/dist/server/index.js +197 -9
- package/dist/server/index.js.map +1 -1
- package/dist/spa/assets/index-BHFHKR8b.css +1 -0
- package/dist/spa/assets/index-DPCmjbDB.js +1 -0
- package/dist/spa/assets/index-DXmRzl_c.js +49 -0
- package/dist/spa/assets/preview-BQeQWTP5.js +1 -0
- package/dist/spa/index.html +3 -3
- package/dist/spa/preview.html +3 -3
- package/package.json +8 -2
- package/dist/spa/assets/index-CVpU-HIB.js +0 -49
- package/dist/spa/assets/index-DAwWrHBV.css +0 -1
- package/dist/spa/assets/index-IlHveh9s.js +0 -1
- package/dist/spa/assets/preview-BsbVArrR.js +0 -1
package/dist/server/index.js
CHANGED
|
@@ -2,16 +2,58 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/server/agent-api.controller.ts
|
|
5
|
-
import { Controller, Get, Query, Sse } from "@nestjs/common";
|
|
5
|
+
import { Body, Controller, Get, Post, Query, Sse } from "@nestjs/common";
|
|
6
6
|
|
|
7
7
|
// src/server/dashboard.service.ts
|
|
8
8
|
import { subscribe, unsubscribe } from "node:diagnostics_channel";
|
|
9
9
|
import { channelName } from "@dudousxd/nestjs-diagnostics";
|
|
10
|
-
import { Inject, Injectable } from "@nestjs/common";
|
|
10
|
+
import { Inject, Injectable, NotImplementedException, Optional } from "@nestjs/common";
|
|
11
11
|
import { Observable as Observable2 } from "rxjs";
|
|
12
12
|
|
|
13
|
+
// src/server/parse-price-input.ts
|
|
14
|
+
import { BadRequestException } from "@nestjs/common";
|
|
15
|
+
function parsePriceInput(body) {
|
|
16
|
+
if (typeof body !== "object" || body === null) {
|
|
17
|
+
throw new BadRequestException("Expected a JSON object body.");
|
|
18
|
+
}
|
|
19
|
+
const { modelId, inputPricePer1m, outputPricePer1m, cacheWritePricePer1m, cacheReadPricePer1m } = body;
|
|
20
|
+
if (typeof modelId !== "string" || modelId.trim().length === 0) {
|
|
21
|
+
throw new BadRequestException('"modelId" must be a non-empty string.');
|
|
22
|
+
}
|
|
23
|
+
if (!isFiniteNonNegative(inputPricePer1m)) {
|
|
24
|
+
throw new BadRequestException('"inputPricePer1m" must be a non-negative number.');
|
|
25
|
+
}
|
|
26
|
+
if (!isFiniteNonNegative(outputPricePer1m)) {
|
|
27
|
+
throw new BadRequestException('"outputPricePer1m" must be a non-negative number.');
|
|
28
|
+
}
|
|
29
|
+
if (cacheWritePricePer1m !== void 0 && !isFiniteNonNegative(cacheWritePricePer1m)) {
|
|
30
|
+
throw new BadRequestException('"cacheWritePricePer1m" must be a non-negative number when present.');
|
|
31
|
+
}
|
|
32
|
+
if (cacheReadPricePer1m !== void 0 && !isFiniteNonNegative(cacheReadPricePer1m)) {
|
|
33
|
+
throw new BadRequestException('"cacheReadPricePer1m" must be a non-negative number when present.');
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
modelId,
|
|
37
|
+
inputPricePer1m,
|
|
38
|
+
outputPricePer1m,
|
|
39
|
+
...cacheWritePricePer1m !== void 0 ? {
|
|
40
|
+
cacheWritePricePer1m
|
|
41
|
+
} : {},
|
|
42
|
+
...cacheReadPricePer1m !== void 0 ? {
|
|
43
|
+
cacheReadPricePer1m
|
|
44
|
+
} : {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
__name(parsePriceInput, "parsePriceInput");
|
|
48
|
+
function isFiniteNonNegative(value) {
|
|
49
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
50
|
+
}
|
|
51
|
+
__name(isFiniteNonNegative, "isFiniteNonNegative");
|
|
52
|
+
|
|
13
53
|
// src/server/tokens.ts
|
|
14
54
|
var AGENT_GOVERNANCE_QUERIES = Symbol.for("@dudousxd/nestjs-agent:governance-queries");
|
|
55
|
+
var AGENT_ACTOR_DIRECTORY = Symbol.for("@dudousxd/nestjs-agent:actor-directory");
|
|
56
|
+
var AGENT_PRICING_STORE = Symbol.for("@dudousxd/nestjs-agent:pricing-store");
|
|
15
57
|
var DASHBOARD_BASE_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:base-path");
|
|
16
58
|
var DASHBOARD_API_PATH = Symbol.for("@dudousxd/nestjs-agent-dashboard:api-path");
|
|
17
59
|
|
|
@@ -33,6 +75,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
33
75
|
};
|
|
34
76
|
}
|
|
35
77
|
__name(_ts_param, "_ts_param");
|
|
78
|
+
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.";
|
|
36
79
|
var AGENT_EVENTS = [
|
|
37
80
|
"run.started",
|
|
38
81
|
"message",
|
|
@@ -50,29 +93,82 @@ var DashboardService = class {
|
|
|
50
93
|
__name(this, "DashboardService");
|
|
51
94
|
}
|
|
52
95
|
queries;
|
|
53
|
-
|
|
96
|
+
actorDirectory;
|
|
97
|
+
pricingStore;
|
|
98
|
+
constructor(queries, actorDirectory, pricingStore) {
|
|
54
99
|
this.queries = queries;
|
|
100
|
+
this.actorDirectory = actorDirectory;
|
|
101
|
+
this.pricingStore = pricingStore;
|
|
55
102
|
}
|
|
56
103
|
/** Spend/usage overview for a day range: by-model + by-actor spend and the daily trend, in parallel. */
|
|
57
104
|
async spend(range) {
|
|
58
|
-
const [byModel,
|
|
105
|
+
const [byModel, byActorRaw, trend] = await Promise.all([
|
|
59
106
|
this.queries.spendByModel(range),
|
|
60
107
|
this.queries.spendByActor(range),
|
|
61
108
|
this.queries.usageTrend(range)
|
|
62
109
|
]);
|
|
110
|
+
const byActor = await this.withActorLabels(byActorRaw);
|
|
63
111
|
return {
|
|
64
112
|
byModel,
|
|
65
113
|
byActor,
|
|
66
114
|
trend
|
|
67
115
|
};
|
|
68
116
|
}
|
|
117
|
+
/** Top threads by cost for a day range (default 10, highest cost first). */
|
|
118
|
+
async topThreads(range, limit = 10) {
|
|
119
|
+
const rows = await this.queries.spendByThread(range, limit);
|
|
120
|
+
return this.withActorLabels(rows);
|
|
121
|
+
}
|
|
69
122
|
/** Most recent tool calls (status/type/thread) for the Runs & tools activity feed. */
|
|
70
123
|
recentToolCalls(limit) {
|
|
71
124
|
return this.queries.recentToolCalls(limit);
|
|
72
125
|
}
|
|
73
126
|
/** Most recent threads with rolled-up message/token counts. */
|
|
74
|
-
recentThreads(limit) {
|
|
75
|
-
|
|
127
|
+
async recentThreads(limit) {
|
|
128
|
+
const rows = await this.queries.recentThreads(limit);
|
|
129
|
+
return this.withActorLabels(rows);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Decorate actor-scoped rows with `actorLabel`, batching the distinct `actorRef`s into ONE
|
|
133
|
+
* {@link ActorDirectory.resolveDisplay} call per response. `null` for every row when no directory
|
|
134
|
+
* is bound, or for a ref the directory didn't resolve.
|
|
135
|
+
*/
|
|
136
|
+
async withActorLabels(rows) {
|
|
137
|
+
if (rows.length === 0) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
if (this.actorDirectory === void 0) {
|
|
141
|
+
return rows.map((row) => ({
|
|
142
|
+
...row,
|
|
143
|
+
actorLabel: null
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
const refs = [
|
|
147
|
+
...new Set(rows.map((row) => row.actorRef))
|
|
148
|
+
];
|
|
149
|
+
const resolved = await this.actorDirectory.resolveDisplay(refs);
|
|
150
|
+
return rows.map((row) => ({
|
|
151
|
+
...row,
|
|
152
|
+
actorLabel: resolved[row.actorRef] ?? null
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
/** Current price row per model, for the pricing tab. 501s when no `AGENT_PRICING_STORE` is bound. */
|
|
156
|
+
async listPrices() {
|
|
157
|
+
if (this.pricingStore === void 0) {
|
|
158
|
+
throw new NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
|
|
159
|
+
}
|
|
160
|
+
return this.pricingStore.listCurrentPrices();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Set a model's current price (`POST <api>/pricing` body). 501s when no `AGENT_PRICING_STORE` is
|
|
164
|
+
* bound (checked BEFORE body validation, so an unbound store always reports as unimplemented rather
|
|
165
|
+
* than as a validation error); otherwise the body is minimally validated via {@link parsePriceInput}.
|
|
166
|
+
*/
|
|
167
|
+
async upsertPrice(body) {
|
|
168
|
+
if (this.pricingStore === void 0) {
|
|
169
|
+
throw new NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);
|
|
170
|
+
}
|
|
171
|
+
await this.pricingStore.upsertModelPrice(parsePriceInput(body));
|
|
76
172
|
}
|
|
77
173
|
/**
|
|
78
174
|
* Live SSE stream of `aviary:agent:*` diagnostics events. One subscription per SSE client:
|
|
@@ -108,9 +204,15 @@ var DashboardService = class {
|
|
|
108
204
|
DashboardService = _ts_decorate([
|
|
109
205
|
Injectable(),
|
|
110
206
|
_ts_param(0, Inject(AGENT_GOVERNANCE_QUERIES)),
|
|
207
|
+
_ts_param(1, Optional()),
|
|
208
|
+
_ts_param(1, Inject(AGENT_ACTOR_DIRECTORY)),
|
|
209
|
+
_ts_param(2, Optional()),
|
|
210
|
+
_ts_param(2, Inject(AGENT_PRICING_STORE)),
|
|
111
211
|
_ts_metadata("design:type", Function),
|
|
112
212
|
_ts_metadata("design:paramtypes", [
|
|
113
|
-
typeof AgentGovernanceQueries === "undefined" ? Object : AgentGovernanceQueries
|
|
213
|
+
typeof AgentGovernanceQueries === "undefined" ? Object : AgentGovernanceQueries,
|
|
214
|
+
typeof ActorDirectory === "undefined" ? Object : ActorDirectory,
|
|
215
|
+
typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore
|
|
114
216
|
])
|
|
115
217
|
], DashboardService);
|
|
116
218
|
|
|
@@ -167,6 +269,10 @@ var AgentApiController = class {
|
|
|
167
269
|
spend(from, to) {
|
|
168
270
|
return this.dashboard.spend(resolveRange(from, to));
|
|
169
271
|
}
|
|
272
|
+
/** Top threads by cost (default 10, max 200) for a day range (defaults to the last 30 days). */
|
|
273
|
+
topThreads(from, to, limit) {
|
|
274
|
+
return this.dashboard.topThreads(resolveRange(from, to), parseLimit(limit, 10));
|
|
275
|
+
}
|
|
170
276
|
/** Most recent tool calls (default 50, max 200) for the activity feed. */
|
|
171
277
|
toolCalls(limit) {
|
|
172
278
|
return this.dashboard.recentToolCalls(parseLimit(limit, 50));
|
|
@@ -175,6 +281,21 @@ var AgentApiController = class {
|
|
|
175
281
|
threads(limit) {
|
|
176
282
|
return this.dashboard.recentThreads(parseLimit(limit, 50));
|
|
177
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when
|
|
286
|
+
* no `AGENT_PRICING_STORE` is bound.
|
|
287
|
+
*/
|
|
288
|
+
listPrices() {
|
|
289
|
+
return this.dashboard.listPrices();
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Set a model's current price. Body shape mirrors core's `ModelPriceInput`
|
|
293
|
+
* (`{ modelId, inputPricePer1m, outputPricePer1m, cacheWritePricePer1m?, cacheReadPricePer1m? }`).
|
|
294
|
+
* 501s when no `AGENT_PRICING_STORE` is bound; 400s on a malformed body.
|
|
295
|
+
*/
|
|
296
|
+
upsertPrice(body) {
|
|
297
|
+
return this.dashboard.upsertPrice(body);
|
|
298
|
+
}
|
|
178
299
|
/** Server-Sent Events stream of live `aviary:agent:*` events — the Live feed tails it. */
|
|
179
300
|
stream() {
|
|
180
301
|
return this.dashboard.streamEvents();
|
|
@@ -191,6 +312,19 @@ _ts_decorate2([
|
|
|
191
312
|
]),
|
|
192
313
|
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
193
314
|
], AgentApiController.prototype, "spend", null);
|
|
315
|
+
_ts_decorate2([
|
|
316
|
+
Get("top-threads"),
|
|
317
|
+
_ts_param2(0, Query("from")),
|
|
318
|
+
_ts_param2(1, Query("to")),
|
|
319
|
+
_ts_param2(2, Query("limit")),
|
|
320
|
+
_ts_metadata2("design:type", Function),
|
|
321
|
+
_ts_metadata2("design:paramtypes", [
|
|
322
|
+
String,
|
|
323
|
+
String,
|
|
324
|
+
String
|
|
325
|
+
]),
|
|
326
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
327
|
+
], AgentApiController.prototype, "topThreads", null);
|
|
194
328
|
_ts_decorate2([
|
|
195
329
|
Get("tool-calls"),
|
|
196
330
|
_ts_param2(0, Query("limit")),
|
|
@@ -209,6 +343,21 @@ _ts_decorate2([
|
|
|
209
343
|
]),
|
|
210
344
|
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
211
345
|
], AgentApiController.prototype, "threads", null);
|
|
346
|
+
_ts_decorate2([
|
|
347
|
+
Get("pricing"),
|
|
348
|
+
_ts_metadata2("design:type", Function),
|
|
349
|
+
_ts_metadata2("design:paramtypes", []),
|
|
350
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
351
|
+
], AgentApiController.prototype, "listPrices", null);
|
|
352
|
+
_ts_decorate2([
|
|
353
|
+
Post("pricing"),
|
|
354
|
+
_ts_param2(0, Body()),
|
|
355
|
+
_ts_metadata2("design:type", Function),
|
|
356
|
+
_ts_metadata2("design:paramtypes", [
|
|
357
|
+
Object
|
|
358
|
+
]),
|
|
359
|
+
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
360
|
+
], AgentApiController.prototype, "upsertPrice", null);
|
|
212
361
|
_ts_decorate2([
|
|
213
362
|
Sse("stream"),
|
|
214
363
|
_ts_metadata2("design:type", Function),
|
|
@@ -223,7 +372,33 @@ AgentApiController = _ts_decorate2([
|
|
|
223
372
|
])
|
|
224
373
|
], AgentApiController);
|
|
225
374
|
|
|
375
|
+
// src/server/normalize-path.ts
|
|
376
|
+
function normalizeDashboardPath(path) {
|
|
377
|
+
return `/${path.replace(/^\/+|\/+$/g, "")}`;
|
|
378
|
+
}
|
|
379
|
+
__name(normalizeDashboardPath, "normalizeDashboardPath");
|
|
380
|
+
|
|
381
|
+
// src/server/agent-dashboard-mount-paths.ts
|
|
382
|
+
function unprefixed(path) {
|
|
383
|
+
return path.replace(/^\/+/, "");
|
|
384
|
+
}
|
|
385
|
+
__name(unprefixed, "unprefixed");
|
|
386
|
+
function agentDashboardMountPaths(options) {
|
|
387
|
+
const basePath = normalizeDashboardPath(options?.basePath ?? "/ai-gateway");
|
|
388
|
+
const apiBasePath = normalizeDashboardPath(options?.apiBasePath ?? `${basePath}/api`);
|
|
389
|
+
const base = unprefixed(basePath);
|
|
390
|
+
const api = unprefixed(apiBasePath);
|
|
391
|
+
return [
|
|
392
|
+
base,
|
|
393
|
+
`${base}/{*splat}`,
|
|
394
|
+
api,
|
|
395
|
+
`${api}/{*splat}`
|
|
396
|
+
];
|
|
397
|
+
}
|
|
398
|
+
__name(agentDashboardMountPaths, "agentDashboardMountPaths");
|
|
399
|
+
|
|
226
400
|
// src/server/agent-dashboard.module.ts
|
|
401
|
+
import "reflect-metadata";
|
|
227
402
|
import { Module } from "@nestjs/common";
|
|
228
403
|
import { RouterModule } from "@nestjs/core";
|
|
229
404
|
|
|
@@ -336,10 +511,17 @@ function _ts_decorate4(decorators, target, key, desc) {
|
|
|
336
511
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
337
512
|
}
|
|
338
513
|
__name(_ts_decorate4, "_ts_decorate");
|
|
514
|
+
var GUARDS_METADATA = "__guards__";
|
|
339
515
|
function normalize(path) {
|
|
340
|
-
return
|
|
516
|
+
return normalizeDashboardPath(path);
|
|
341
517
|
}
|
|
342
518
|
__name(normalize, "normalize");
|
|
519
|
+
function stampGuards(guards, ...controllers) {
|
|
520
|
+
for (const controller of controllers) {
|
|
521
|
+
Reflect.defineMetadata(GUARDS_METADATA, guards ?? [], controller);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
__name(stampGuards, "stampGuards");
|
|
343
525
|
var AgentApiModule = class {
|
|
344
526
|
static {
|
|
345
527
|
__name(this, "AgentApiModule");
|
|
@@ -365,9 +547,11 @@ var AgentDashboardModule = class _AgentDashboardModule {
|
|
|
365
547
|
static forRoot(options = {}) {
|
|
366
548
|
const basePath = normalize(options.basePath ?? "/ai-gateway");
|
|
367
549
|
const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
|
|
550
|
+
stampGuards(options.guards, AgentApiController, AgentUiController);
|
|
368
551
|
return {
|
|
369
552
|
module: _AgentDashboardModule,
|
|
370
553
|
imports: [
|
|
554
|
+
...options.imports ?? [],
|
|
371
555
|
AgentApiModule,
|
|
372
556
|
RouterModule.register([
|
|
373
557
|
{
|
|
@@ -404,13 +588,17 @@ AgentDashboardModule = _ts_decorate4([
|
|
|
404
588
|
Module({})
|
|
405
589
|
], AgentDashboardModule);
|
|
406
590
|
export {
|
|
591
|
+
AGENT_ACTOR_DIRECTORY,
|
|
407
592
|
AGENT_GOVERNANCE_QUERIES,
|
|
593
|
+
AGENT_PRICING_STORE,
|
|
408
594
|
AgentApiController,
|
|
409
595
|
AgentApiModule,
|
|
410
596
|
AgentDashboardModule,
|
|
411
597
|
AgentUiController,
|
|
412
598
|
DASHBOARD_API_PATH,
|
|
413
599
|
DASHBOARD_BASE_PATH,
|
|
414
|
-
DashboardService
|
|
600
|
+
DashboardService,
|
|
601
|
+
agentDashboardMountPaths,
|
|
602
|
+
parsePriceInput
|
|
415
603
|
};
|
|
416
604
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/agent-api.controller.ts","../../src/server/dashboard.service.ts","../../src/server/tokens.ts","../../src/server/agent-dashboard.module.ts","../../src/server/agent-ui.controller.ts"],"sourcesContent":["import type { ThreadActivityRow, ToolCallActivityRow } from '@dudousxd/nestjs-agent-core';\nimport { Controller, Get, Query, Sse } from '@nestjs/common';\nimport type { Observable } from 'rxjs';\nimport { DashboardService, type LiveAgentEvent, type SpendOverview } from './dashboard.service.js';\n\nconst DAY_MS = 86_400_000;\nconst ISO_DAY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/** A `YYYY-MM-DD` UTC day string `daysAgo` days before now (0 = today). */\nfunction utcDay(daysAgo: number): string {\n return new Date(Date.now() - daysAgo * DAY_MS).toISOString().slice(0, 10);\n}\n\n/** Accept a client-supplied `YYYY-MM-DD`, or fall back to `fallback`; guards against junk input. */\nfunction dayOr(value: string | undefined, fallback: string): string {\n return value !== undefined && ISO_DAY.test(value) ? value : fallback;\n}\n\n/** Resolve the `from`/`to` query params into a validated range, defaulting to the last 30 days. */\nfunction resolveRange(\n from: string | undefined,\n to: string | undefined,\n): {\n fromDay: string;\n toDay: string;\n} {\n return { fromDay: dayOr(from, utcDay(29)), toDay: dayOr(to, utcDay(0)) };\n}\n\n/** Parse a `limit` query param, clamped to a sane window; falls back to `fallback` when absent/junk. */\nfunction parseLimit(value: string | undefined, fallback: number): number {\n const parsed = value === undefined ? Number.NaN : Number.parseInt(value, 10);\n if (!Number.isFinite(parsed)) return fallback;\n return Math.max(1, Math.min(200, parsed));\n}\n\n/**\n * JSON + SSE API consumed by the AI-gateway console SPA. Mounted at `apiBasePath` (set by\n * `RouterModule` in {@link AgentDashboardModule.forRoot}), so the controller routes are relative.\n */\n@Controller()\nexport class AgentApiController {\n constructor(private readonly dashboard: DashboardService) {}\n\n /** `{ byModel, byActor, trend }` for a day range (defaults to the last 30 days). */\n @Get('spend')\n spend(@Query('from') from?: string, @Query('to') to?: string): Promise<SpendOverview> {\n return this.dashboard.spend(resolveRange(from, to));\n }\n\n /** Most recent tool calls (default 50, max 200) for the activity feed. */\n @Get('tool-calls')\n toolCalls(@Query('limit') limit?: string): Promise<ToolCallActivityRow[]> {\n return this.dashboard.recentToolCalls(parseLimit(limit, 50));\n }\n\n /** Most recent threads (default 50, max 200) with rolled-up counts. */\n @Get('threads')\n threads(@Query('limit') limit?: string): Promise<ThreadActivityRow[]> {\n return this.dashboard.recentThreads(parseLimit(limit, 50));\n }\n\n /** Server-Sent Events stream of live `aviary:agent:*` events — the Live feed tails it. */\n @Sse('stream')\n stream(): Observable<{ data: LiveAgentEvent }> {\n return this.dashboard.streamEvents();\n }\n}\n","import { subscribe, unsubscribe } from 'node:diagnostics_channel';\nimport type {\n ActorSpendRow,\n AgentGovernanceQueries,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { channelName } from '@dudousxd/nestjs-diagnostics';\nimport { Inject, Injectable } from '@nestjs/common';\nimport { Observable } from 'rxjs';\nimport { AGENT_GOVERNANCE_QUERIES } from './tokens.js';\n\n/** The spend/usage overview the SPA renders on its headline section (`GET <api>/spend`). */\nexport interface SpendOverview {\n byModel: ModelSpendRow[];\n byActor: ActorSpendRow[];\n trend: UsageTrendPoint[];\n}\n\n/** One live agent event forwarded over SSE, flattened from the `aviary:agent:*` diagnostics envelope. */\nexport interface LiveAgentEvent {\n /** The event name, e.g. `run.started` / `tool-call` / `quota.exceeded`. */\n event: string;\n /** Epoch millis the event was emitted. */\n ts: number;\n /** The library-defined payload (see the `Agent*Event` shapes in core's diagnostics). */\n payload: Record<string, unknown>;\n}\n\n/** The `aviary:agent:*` events the Live feed tails. Mirrors the telescope watcher's subscription. */\nconst AGENT_EVENTS = [\n 'run.started',\n 'message',\n 'tool-call',\n 'quota.exceeded',\n 'run.finished',\n 'delegated',\n] as const;\n\n/** The `node:diagnostics_channel` envelope `emit()` publishes (see `@dudousxd/nestjs-diagnostics`). */\ninterface AgentDiagnosticEnvelope {\n event: string;\n ts?: number;\n payload?: Record<string, unknown>;\n}\n\n/** Narrow the untyped diagnostics-channel message to the envelope we forward. */\nfunction isAgentEnvelope(message: unknown): message is AgentDiagnosticEnvelope {\n return (\n typeof message === 'object' &&\n message !== null &&\n 'event' in message &&\n typeof (message as { event: unknown }).event === 'string'\n );\n}\n\n/**\n * Read-model + live bridge backing the AI-gateway console.\n *\n * - Historical, restart-surviving spend/usage/threads come from the injected\n * {@link AGENT_GOVERNANCE_QUERIES} read-model (backed by a store adapter). The host must provide\n * that token — bind it via your `@dudousxd/nestjs-agent` module (global) alongside this dashboard.\n * - Live activity comes off the `aviary:agent:*` diagnostics channel, subscribed per SSE client and\n * unsubscribed when the client disconnects.\n */\n@Injectable()\nexport class DashboardService {\n constructor(@Inject(AGENT_GOVERNANCE_QUERIES) private readonly queries: AgentGovernanceQueries) {}\n\n /** Spend/usage overview for a day range: by-model + by-actor spend and the daily trend, in parallel. */\n async spend(range: GovernanceRange): Promise<SpendOverview> {\n const [byModel, byActor, trend] = await Promise.all([\n this.queries.spendByModel(range),\n this.queries.spendByActor(range),\n this.queries.usageTrend(range),\n ]);\n return { byModel, byActor, trend };\n }\n\n /** Most recent tool calls (status/type/thread) for the Runs & tools activity feed. */\n recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n return this.queries.recentToolCalls(limit);\n }\n\n /** Most recent threads with rolled-up message/token counts. */\n recentThreads(limit: number): Promise<ThreadActivityRow[]> {\n return this.queries.recentThreads(limit);\n }\n\n /**\n * Live SSE stream of `aviary:agent:*` diagnostics events. One subscription per SSE client:\n * subscribing wires a handler onto each agent channel; the returned teardown removes them all when\n * the client disconnects (or the observable is otherwise unsubscribed).\n */\n streamEvents(): Observable<{ data: LiveAgentEvent }> {\n return new Observable<{ data: LiveAgentEvent }>((subscriber) => {\n const bindings = AGENT_EVENTS.map((event) => {\n const name = channelName('agent', event);\n const handler = (message: unknown): void => {\n if (!isAgentEnvelope(message)) return;\n subscriber.next({\n data: {\n event: message.event,\n ts: message.ts ?? Date.now(),\n payload: message.payload ?? {},\n },\n });\n };\n subscribe(name, handler);\n return { name, handler };\n });\n return () => {\n for (const binding of bindings) unsubscribe(binding.name, binding.handler);\n };\n });\n }\n}\n","/**\n * DI tokens for the standalone AI-gateway dashboard.\n *\n * All use `Symbol.for(...)` (the global symbol registry) on purpose: pnpm peer multiplexing + dual\n * ESM/CJS can load a package more than once, and a plain `Symbol()` would mint a distinct token per\n * copy and break DI across the ESM/CJS split. A registered symbol collapses every copy onto the same\n * token.\n */\n\n/**\n * The governance read-model, owned by `@dudousxd/nestjs-agent-core`. We re-declare it here BY VALUE\n * (not by import) so DI does not depend on a runtime value-import of core resolving — `Symbol.for`\n * with the identical key resolves to the SAME symbol instance as core's own\n * `packages/core/src/tokens.ts` export. The key MUST stay byte-identical with that export.\n */\nexport const AGENT_GOVERNANCE_QUERIES = Symbol.for('@dudousxd/nestjs-agent:governance-queries');\n\n/** DI token carrying the UI mount base (e.g. `/ai-gateway`). */\nexport const DASHBOARD_BASE_PATH = Symbol.for('@dudousxd/nestjs-agent-dashboard:base-path');\n\n/** DI token carrying the JSON API base the SPA fetches from (e.g. `/ai-gateway/api`). */\nexport const DASHBOARD_API_PATH = Symbol.for('@dudousxd/nestjs-agent-dashboard:api-path');\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { RouterModule } from '@nestjs/core';\nimport { AgentApiController } from './agent-api.controller.js';\nimport { AgentUiController } from './agent-ui.controller.js';\nimport { DashboardService } from './dashboard.service.js';\nimport { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH } from './tokens.js';\n\nexport interface AgentDashboardOptions {\n /**\n * Where the SPA (UI) is served. Default `/ai-gateway`. This is a page route — keep it out of an\n * `/api` prefix so it reads as a UI, not an endpoint.\n */\n basePath?: string;\n /**\n * Where the JSON API is mounted (what the SPA fetches). Default `<basePath>/api`. Set it under\n * your app's `/api` prefix — e.g. `/api/ai-gateway` — so the API inherits the app's auth/proxy\n * rules while the UI stays at `basePath`.\n */\n apiBasePath?: string;\n}\n\n/** Leading slash, no trailing slash. */\nfunction normalize(path: string): string {\n return `/${path.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\n/** Holds the JSON API + SSE controller and its read service, mounted on its own path by `forRoot`. */\n@Module({\n controllers: [AgentApiController],\n providers: [DashboardService],\n exports: [DashboardService],\n})\nexport class AgentApiModule {}\n\n/**\n * Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE\n * API at `apiBasePath` (default `<basePath>/api`).\n *\n * Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module\n * (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the\n * routes with your own guard — the controllers are path-relative and guard-frontable.\n */\n@Module({})\nexport class AgentDashboardModule {\n static forRoot(options: AgentDashboardOptions = {}): DynamicModule {\n const basePath = normalize(options.basePath ?? '/ai-gateway');\n const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);\n return {\n module: AgentDashboardModule,\n imports: [\n AgentApiModule,\n RouterModule.register([\n { path: basePath, module: AgentDashboardModule }, // the UI controller below\n { path: apiBasePath, module: AgentApiModule },\n ]),\n ],\n controllers: [AgentUiController],\n providers: [\n { provide: DASHBOARD_BASE_PATH, useValue: basePath },\n { provide: DASHBOARD_API_PATH, useValue: apiBasePath },\n ],\n // Re-export the API module so its DashboardService reaches importers (e.g. the host's own controllers).\n exports: [AgentApiModule],\n };\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { basename, extname, join, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n Controller,\n Get,\n Header,\n Inject,\n NotFoundException,\n Param,\n StreamableFile,\n} from '@nestjs/common';\nimport { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH } from './tokens.js';\n\n/** The base the SPA bundle was built with (Vite `base`); rewritten to the configured base at serve time. */\nconst BUILD_BASE = '/ai-gateway';\n\n/** dist/server/agent-ui.controller.js -> ../spa (the Vite build output). */\nfunction spaDir(): string {\n return fileURLToPath(new URL('../spa', import.meta.url));\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n '.js': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.map': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.json': 'application/json; charset=utf-8',\n '.woff2': 'font/woff2',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Serves the bundled AI-gateway console SPA at the configured base (+ hashed assets at\n * `<base>/assets`). The path comes from `RouterModule` (set by\n * {@link AgentDashboardModule.forRoot}({ basePath })), so the controller routes are relative.\n */\n@Controller()\nexport class AgentUiController {\n private readonly dir = spaDir();\n\n constructor(\n @Inject(DASHBOARD_BASE_PATH) private readonly basePath: string,\n @Inject(DASHBOARD_API_PATH) private readonly apiBasePath: string,\n ) {}\n\n // index.html references hash-named bundles, so it MUST NOT be cached (stale bundle = the classic\n // \"stuck loading after a deploy\"). The hashed assets below are immutable.\n @Get()\n @Header('Content-Type', 'text/html; charset=utf-8')\n @Header('Cache-Control', 'no-store, must-revalidate')\n index(): string {\n const indexPath = join(this.dir, 'index.html');\n if (!existsSync(indexPath)) {\n throw new NotFoundException('Dashboard is not built. Run the package build.');\n }\n // The bundle was built with Vite base `/ai-gateway/`; rewrite asset URLs to the configured base\n // so the SPA loads from `<base>/assets` wherever it's mounted, and tell the client its API base.\n const html = readFileSync(indexPath, 'utf8').replaceAll(\n `=\"${BUILD_BASE}/`,\n `=\"${this.basePath}/`,\n );\n // __AGENT_BASE__ = where assets load; __AGENT_API__ = where the SPA fetches the JSON API.\n const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;\n return html.includes('</head>') ? html.replace('</head>', `${inject}</head>`) : inject + html;\n }\n\n @Get('assets/:file')\n @Header('Cache-Control', 'public, max-age=31536000, immutable')\n asset(@Param('file') file: string): StreamableFile {\n const safe = basename(file);\n if (safe !== file) throw new NotFoundException();\n const root = resolve(this.dir, 'assets');\n const assetPath = resolve(root, safe);\n if (!assetPath.startsWith(root + sep) || !existsSync(assetPath)) {\n throw new NotFoundException();\n }\n const type = CONTENT_TYPES[extname(safe)] ?? 'application/octet-stream';\n return new StreamableFile(readFileSync(assetPath), { type });\n }\n}\n"],"mappings":"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","names":["Controller","Get","Query","Sse","subscribe","unsubscribe","channelName","Inject","Injectable","Observable","AGENT_GOVERNANCE_QUERIES","Symbol","for","DASHBOARD_BASE_PATH","DASHBOARD_API_PATH","AGENT_EVENTS","isAgentEnvelope","message","event","DashboardService","queries","spend","range","byModel","byActor","trend","Promise","all","spendByModel","spendByActor","usageTrend","recentToolCalls","limit","recentThreads","streamEvents","Observable","subscriber","bindings","map","name","channelName","handler","next","data","ts","Date","now","payload","subscribe","binding","unsubscribe","DAY_MS","ISO_DAY","utcDay","daysAgo","Date","now","toISOString","slice","dayOr","value","fallback","undefined","test","resolveRange","from","to","fromDay","toDay","parseLimit","parsed","Number","NaN","parseInt","isFinite","Math","max","min","AgentApiController","dashboard","spend","toolCalls","limit","recentToolCalls","threads","recentThreads","stream","streamEvents","Module","RouterModule","existsSync","readFileSync","basename","extname","join","resolve","sep","fileURLToPath","Controller","Get","Header","Inject","NotFoundException","Param","StreamableFile","BUILD_BASE","spaDir","fileURLToPath","URL","url","CONTENT_TYPES","AgentUiController","dir","basePath","apiBasePath","index","indexPath","join","existsSync","NotFoundException","html","readFileSync","replaceAll","inject","includes","replace","asset","file","safe","basename","root","resolve","assetPath","startsWith","sep","type","extname","StreamableFile","normalize","path","replace","AgentApiModule","controllers","AgentApiController","providers","DashboardService","exports","AgentDashboardModule","forRoot","options","basePath","apiBasePath","module","imports","RouterModule","register","AgentUiController","provide","DASHBOARD_BASE_PATH","useValue","DASHBOARD_API_PATH"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/agent-api.controller.ts","../../src/server/dashboard.service.ts","../../src/server/parse-price-input.ts","../../src/server/tokens.ts","../../src/server/normalize-path.ts","../../src/server/agent-dashboard-mount-paths.ts","../../src/server/agent-dashboard.module.ts","../../src/server/agent-ui.controller.ts"],"sourcesContent":["import type { CurrentModelPrice, ToolCallActivityRow } from '@dudousxd/nestjs-agent-core';\nimport { Body, Controller, Get, Post, Query, Sse } from '@nestjs/common';\nimport type { Observable } from 'rxjs';\nimport {\n DashboardService,\n type LiveAgentEvent,\n type SpendOverview,\n type ThreadActivityRowWithLabel,\n type ThreadSpendRowWithLabel,\n} from './dashboard.service.js';\n\nconst DAY_MS = 86_400_000;\nconst ISO_DAY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/** A `YYYY-MM-DD` UTC day string `daysAgo` days before now (0 = today). */\nfunction utcDay(daysAgo: number): string {\n return new Date(Date.now() - daysAgo * DAY_MS).toISOString().slice(0, 10);\n}\n\n/** Accept a client-supplied `YYYY-MM-DD`, or fall back to `fallback`; guards against junk input. */\nfunction dayOr(value: string | undefined, fallback: string): string {\n return value !== undefined && ISO_DAY.test(value) ? value : fallback;\n}\n\n/** Resolve the `from`/`to` query params into a validated range, defaulting to the last 30 days. */\nfunction resolveRange(\n from: string | undefined,\n to: string | undefined,\n): {\n fromDay: string;\n toDay: string;\n} {\n return { fromDay: dayOr(from, utcDay(29)), toDay: dayOr(to, utcDay(0)) };\n}\n\n/** Parse a `limit` query param, clamped to a sane window; falls back to `fallback` when absent/junk. */\nfunction parseLimit(value: string | undefined, fallback: number): number {\n const parsed = value === undefined ? Number.NaN : Number.parseInt(value, 10);\n if (!Number.isFinite(parsed)) return fallback;\n return Math.max(1, Math.min(200, parsed));\n}\n\n/**\n * JSON + SSE API consumed by the AI-gateway console SPA. Mounted at `apiBasePath` (set by\n * `RouterModule` in {@link AgentDashboardModule.forRoot}), so the controller routes are relative.\n */\n@Controller()\nexport class AgentApiController {\n constructor(private readonly dashboard: DashboardService) {}\n\n /** `{ byModel, byActor, trend }` for a day range (defaults to the last 30 days). */\n @Get('spend')\n spend(@Query('from') from?: string, @Query('to') to?: string): Promise<SpendOverview> {\n return this.dashboard.spend(resolveRange(from, to));\n }\n\n /** Top threads by cost (default 10, max 200) for a day range (defaults to the last 30 days). */\n @Get('top-threads')\n topThreads(\n @Query('from') from?: string,\n @Query('to') to?: string,\n @Query('limit') limit?: string,\n ): Promise<ThreadSpendRowWithLabel[]> {\n return this.dashboard.topThreads(resolveRange(from, to), parseLimit(limit, 10));\n }\n\n /** Most recent tool calls (default 50, max 200) for the activity feed. */\n @Get('tool-calls')\n toolCalls(@Query('limit') limit?: string): Promise<ToolCallActivityRow[]> {\n return this.dashboard.recentToolCalls(parseLimit(limit, 50));\n }\n\n /** Most recent threads (default 50, max 200) with rolled-up counts. */\n @Get('threads')\n threads(@Query('limit') limit?: string): Promise<ThreadActivityRowWithLabel[]> {\n return this.dashboard.recentThreads(parseLimit(limit, 50));\n }\n\n /**\n * Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when\n * no `AGENT_PRICING_STORE` is bound.\n */\n @Get('pricing')\n listPrices(): Promise<CurrentModelPrice[]> {\n return this.dashboard.listPrices();\n }\n\n /**\n * Set a model's current price. Body shape mirrors core's `ModelPriceInput`\n * (`{ modelId, inputPricePer1m, outputPricePer1m, cacheWritePricePer1m?, cacheReadPricePer1m? }`).\n * 501s when no `AGENT_PRICING_STORE` is bound; 400s on a malformed body.\n */\n @Post('pricing')\n upsertPrice(@Body() body: unknown): Promise<void> {\n return this.dashboard.upsertPrice(body);\n }\n\n /** Server-Sent Events stream of live `aviary:agent:*` events — the Live feed tails it. */\n @Sse('stream')\n stream(): Observable<{ data: LiveAgentEvent }> {\n return this.dashboard.streamEvents();\n }\n}\n","import { subscribe, unsubscribe } from 'node:diagnostics_channel';\nimport type {\n ActorSpendRow,\n AgentGovernanceQueries,\n AgentPricingStore,\n CurrentModelPrice,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ThreadSpendRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { channelName } from '@dudousxd/nestjs-diagnostics';\nimport { Inject, Injectable, NotImplementedException, Optional } from '@nestjs/common';\nimport { Observable } from 'rxjs';\nimport type { ActorDirectory } from './actor-directory.js';\nimport { parsePriceInput } from './parse-price-input.js';\nimport { AGENT_ACTOR_DIRECTORY, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE } from './tokens.js';\n\n/** An actor-scoped row decorated with its resolved display label — `null` when unbound or unresolved. */\nexport interface WithActorLabel {\n actorLabel: string | null;\n}\n\nexport type ActorSpendRowWithLabel = ActorSpendRow & WithActorLabel;\nexport type ThreadSpendRowWithLabel = ThreadSpendRow & WithActorLabel;\nexport type ThreadActivityRowWithLabel = ThreadActivityRow & WithActorLabel;\n\n/** The spend/usage overview the SPA renders on its headline section (`GET <api>/spend`). */\nexport interface SpendOverview {\n byModel: ModelSpendRow[];\n byActor: ActorSpendRowWithLabel[];\n trend: UsageTrendPoint[];\n}\n\n/** The message returned as a 501 when no `AGENT_PRICING_STORE` is bound. */\nconst PRICING_STORE_UNBOUND_MESSAGE =\n 'Pricing CRUD is unavailable: no AGENT_PRICING_STORE is bound. Bind a pricing store (e.g. ' +\n 'MikroOrmPricingStore from @dudousxd/nestjs-agent-store-mikro-orm) to enable it.';\n\n/** One live agent event forwarded over SSE, flattened from the `aviary:agent:*` diagnostics envelope. */\nexport interface LiveAgentEvent {\n /** The event name, e.g. `run.started` / `tool-call` / `quota.exceeded`. */\n event: string;\n /** Epoch millis the event was emitted. */\n ts: number;\n /** The library-defined payload (see the `Agent*Event` shapes in core's diagnostics). */\n payload: Record<string, unknown>;\n}\n\n/** The `aviary:agent:*` events the Live feed tails. Mirrors the telescope watcher's subscription. */\nconst AGENT_EVENTS = [\n 'run.started',\n 'message',\n 'tool-call',\n 'quota.exceeded',\n 'run.finished',\n 'delegated',\n] as const;\n\n/** The `node:diagnostics_channel` envelope `emit()` publishes (see `@dudousxd/nestjs-diagnostics`). */\ninterface AgentDiagnosticEnvelope {\n event: string;\n ts?: number;\n payload?: Record<string, unknown>;\n}\n\n/** Narrow the untyped diagnostics-channel message to the envelope we forward. */\nfunction isAgentEnvelope(message: unknown): message is AgentDiagnosticEnvelope {\n return (\n typeof message === 'object' &&\n message !== null &&\n 'event' in message &&\n typeof (message as { event: unknown }).event === 'string'\n );\n}\n\n/**\n * Read-model + live bridge backing the AI-gateway console.\n *\n * - Historical, restart-surviving spend/usage/threads come from the injected\n * {@link AGENT_GOVERNANCE_QUERIES} read-model (backed by a store adapter). The host must provide\n * that token — bind it via your `@dudousxd/nestjs-agent` module (global) alongside this dashboard.\n * - Live activity comes off the `aviary:agent:*` diagnostics channel, subscribed per SSE client and\n * unsubscribed when the client disconnects.\n * - `actorLabel` on actor-scoped rows comes from the OPTIONAL {@link AGENT_ACTOR_DIRECTORY} — `null`\n * on every row when nothing is bound, so the console degrades to raw `actorRef`s instead of failing.\n * - Pricing CRUD (`listPrices`/`upsertPrice`) reads/writes the OPTIONAL {@link AGENT_PRICING_STORE} —\n * a 501 with a clear message when nothing is bound.\n */\n@Injectable()\nexport class DashboardService {\n constructor(\n @Inject(AGENT_GOVERNANCE_QUERIES) private readonly queries: AgentGovernanceQueries,\n @Optional()\n @Inject(AGENT_ACTOR_DIRECTORY)\n private readonly actorDirectory?: ActorDirectory,\n @Optional()\n @Inject(AGENT_PRICING_STORE)\n private readonly pricingStore?: AgentPricingStore,\n ) {}\n\n /** Spend/usage overview for a day range: by-model + by-actor spend and the daily trend, in parallel. */\n async spend(range: GovernanceRange): Promise<SpendOverview> {\n const [byModel, byActorRaw, trend] = await Promise.all([\n this.queries.spendByModel(range),\n this.queries.spendByActor(range),\n this.queries.usageTrend(range),\n ]);\n const byActor = await this.withActorLabels(byActorRaw);\n return { byModel, byActor, trend };\n }\n\n /** Top threads by cost for a day range (default 10, highest cost first). */\n async topThreads(range: GovernanceRange, limit = 10): Promise<ThreadSpendRowWithLabel[]> {\n const rows = await this.queries.spendByThread(range, limit);\n return this.withActorLabels(rows);\n }\n\n /** Most recent tool calls (status/type/thread) for the Runs & tools activity feed. */\n recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n return this.queries.recentToolCalls(limit);\n }\n\n /** Most recent threads with rolled-up message/token counts. */\n async recentThreads(limit: number): Promise<ThreadActivityRowWithLabel[]> {\n const rows = await this.queries.recentThreads(limit);\n return this.withActorLabels(rows);\n }\n\n /**\n * Decorate actor-scoped rows with `actorLabel`, batching the distinct `actorRef`s into ONE\n * {@link ActorDirectory.resolveDisplay} call per response. `null` for every row when no directory\n * is bound, or for a ref the directory didn't resolve.\n */\n private async withActorLabels<Row extends { actorRef: string }>(\n rows: Row[],\n ): Promise<(Row & WithActorLabel)[]> {\n if (rows.length === 0) {\n return [];\n }\n if (this.actorDirectory === undefined) {\n return rows.map((row) => ({ ...row, actorLabel: null }));\n }\n const refs = [...new Set(rows.map((row) => row.actorRef))];\n const resolved = await this.actorDirectory.resolveDisplay(refs);\n return rows.map((row) => ({ ...row, actorLabel: resolved[row.actorRef] ?? null }));\n }\n\n /** Current price row per model, for the pricing tab. 501s when no `AGENT_PRICING_STORE` is bound. */\n async listPrices(): Promise<CurrentModelPrice[]> {\n if (this.pricingStore === undefined) {\n throw new NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);\n }\n return this.pricingStore.listCurrentPrices();\n }\n\n /**\n * Set a model's current price (`POST <api>/pricing` body). 501s when no `AGENT_PRICING_STORE` is\n * bound (checked BEFORE body validation, so an unbound store always reports as unimplemented rather\n * than as a validation error); otherwise the body is minimally validated via {@link parsePriceInput}.\n */\n async upsertPrice(body: unknown): Promise<void> {\n if (this.pricingStore === undefined) {\n throw new NotImplementedException(PRICING_STORE_UNBOUND_MESSAGE);\n }\n await this.pricingStore.upsertModelPrice(parsePriceInput(body));\n }\n\n /**\n * Live SSE stream of `aviary:agent:*` diagnostics events. One subscription per SSE client:\n * subscribing wires a handler onto each agent channel; the returned teardown removes them all when\n * the client disconnects (or the observable is otherwise unsubscribed).\n */\n streamEvents(): Observable<{ data: LiveAgentEvent }> {\n return new Observable<{ data: LiveAgentEvent }>((subscriber) => {\n const bindings = AGENT_EVENTS.map((event) => {\n const name = channelName('agent', event);\n const handler = (message: unknown): void => {\n if (!isAgentEnvelope(message)) return;\n subscriber.next({\n data: {\n event: message.event,\n ts: message.ts ?? Date.now(),\n payload: message.payload ?? {},\n },\n });\n };\n subscribe(name, handler);\n return { name, handler };\n });\n return () => {\n for (const binding of bindings) unsubscribe(binding.name, binding.handler);\n };\n });\n }\n}\n","import type { ModelPriceInput } from '@dudousxd/nestjs-agent-core';\nimport { BadRequestException } from '@nestjs/common';\n\n/**\n * Minimal shape guard for a `POST <api>/pricing` body — rejects junk before it reaches\n * `AgentPricingStore.upsertModelPrice`. Not a full schema validator (the store adapter owns real\n * constraints, e.g. uniqueness); this only checks the wire shape core's `ModelPriceInput` requires.\n */\nexport function parsePriceInput(body: unknown): ModelPriceInput {\n if (typeof body !== 'object' || body === null) {\n throw new BadRequestException('Expected a JSON object body.');\n }\n const { modelId, inputPricePer1m, outputPricePer1m, cacheWritePricePer1m, cacheReadPricePer1m } =\n body as Record<string, unknown>;\n\n if (typeof modelId !== 'string' || modelId.trim().length === 0) {\n throw new BadRequestException('\"modelId\" must be a non-empty string.');\n }\n if (!isFiniteNonNegative(inputPricePer1m)) {\n throw new BadRequestException('\"inputPricePer1m\" must be a non-negative number.');\n }\n if (!isFiniteNonNegative(outputPricePer1m)) {\n throw new BadRequestException('\"outputPricePer1m\" must be a non-negative number.');\n }\n if (cacheWritePricePer1m !== undefined && !isFiniteNonNegative(cacheWritePricePer1m)) {\n throw new BadRequestException(\n '\"cacheWritePricePer1m\" must be a non-negative number when present.',\n );\n }\n if (cacheReadPricePer1m !== undefined && !isFiniteNonNegative(cacheReadPricePer1m)) {\n throw new BadRequestException(\n '\"cacheReadPricePer1m\" must be a non-negative number when present.',\n );\n }\n\n return {\n modelId,\n inputPricePer1m,\n outputPricePer1m,\n ...(cacheWritePricePer1m !== undefined ? { cacheWritePricePer1m } : {}),\n ...(cacheReadPricePer1m !== undefined ? { cacheReadPricePer1m } : {}),\n };\n}\n\nfunction isFiniteNonNegative(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n","/**\n * DI tokens for the standalone AI-gateway dashboard.\n *\n * All use `Symbol.for(...)` (the global symbol registry) on purpose: pnpm peer multiplexing + dual\n * ESM/CJS can load a package more than once, and a plain `Symbol()` would mint a distinct token per\n * copy and break DI across the ESM/CJS split. A registered symbol collapses every copy onto the same\n * token.\n */\n\n/**\n * The governance read-model, owned by `@dudousxd/nestjs-agent-core`. We re-declare it here BY VALUE\n * (not by import) so DI does not depend on a runtime value-import of core resolving — `Symbol.for`\n * with the identical key resolves to the SAME symbol instance as core's own\n * `packages/core/src/tokens.ts` export. The key MUST stay byte-identical with that export.\n */\nexport const AGENT_GOVERNANCE_QUERIES = Symbol.for('@dudousxd/nestjs-agent:governance-queries');\n\n/**\n * Optional actor→label resolver (see {@link ActorDirectory} in `./actor-directory.js`), owned by\n * `@dudousxd/nestjs-agent-core`. Re-declared here BY VALUE for the same reason as\n * {@link AGENT_GOVERNANCE_QUERIES} above — the key MUST stay byte-identical with core's own\n * `AGENT_ACTOR_DIRECTORY` export so both copies collapse onto the same registered symbol. Optional:\n * the dashboard works with actorRef-only rows when nothing is bound.\n */\nexport const AGENT_ACTOR_DIRECTORY = Symbol.for('@dudousxd/nestjs-agent:actor-directory');\n\n/**\n * The pricing WRITE side (`AgentPricingStore`), owned by `@dudousxd/nestjs-agent-core`. Re-declared\n * here BY VALUE for the same reason as {@link AGENT_GOVERNANCE_QUERIES} above. Optional: the pricing\n * tab/endpoints 501 with a clear message when nothing is bound.\n */\nexport const AGENT_PRICING_STORE = Symbol.for('@dudousxd/nestjs-agent:pricing-store');\n\n/** DI token carrying the UI mount base (e.g. `/ai-gateway`). */\nexport const DASHBOARD_BASE_PATH = Symbol.for('@dudousxd/nestjs-agent-dashboard:base-path');\n\n/** DI token carrying the JSON API base the SPA fetches from (e.g. `/ai-gateway/api`). */\nexport const DASHBOARD_API_PATH = Symbol.for('@dudousxd/nestjs-agent-dashboard:api-path');\n","/**\n * Leading slash, no trailing slash (`'ai-gateway/'` -> `'/ai-gateway'`). Shared by\n * {@link AgentDashboardModule.forRoot} and {@link agentDashboardMountPaths} so the mount-path math\n * behind the module and the pure helper that mirrors it can never drift apart.\n */\nexport function normalizeDashboardPath(path: string): string {\n return `/${path.replace(/^\\/+|\\/+$/g, '')}`;\n}\n","import { normalizeDashboardPath } from './normalize-path.js';\n\n/** Same shape {@link AgentDashboardModule.forRoot} accepts — kept local so this stays a pure, DI-free helper. */\nexport interface AgentDashboardMountPathsOptions {\n basePath?: string;\n apiBasePath?: string;\n}\n\n/** Strip the leading slash `normalizeDashboardPath` adds — `setGlobalPrefix`'s `exclude` roots are unprefixed. */\nfunction unprefixed(path: string): string {\n return path.replace(/^\\/+/, '');\n}\n\n/**\n * Route roots a host must EXCLUDE from a global prefix (`setGlobalPrefix('api', { exclude })`) so\n * the AI-gateway dashboard's SPA and JSON API keep resolving at their configured mount paths instead\n * of being shifted under the prefix.\n *\n * Unlike a single-surface dashboard (e.g. `telescopeMountPaths()`), this one mounts TWO route roots —\n * the UI at `basePath` and its JSON API at `apiBasePath` — so excluding only one leaves the other\n * shadowed. `options` mirrors {@link AgentDashboardOptions} and resolves through the exact same\n * defaulting (`apiBasePath` falls back to `<basePath>/api`) as {@link AgentDashboardModule.forRoot},\n * so the excluded roots always agree with what actually got mounted.\n *\n * @example\n * ```ts\n * // Raw defaults (basePath `/ai-gateway`, apiBasePath `/ai-gateway/api`):\n * app.setGlobalPrefix('api', { exclude: agentDashboardMountPaths() });\n * // -> ['ai-gateway', 'ai-gateway/{*splat}', 'ai-gateway/api', 'ai-gateway/api/{*splat}']\n *\n * // The recommended pattern — apiBasePath nested under the app's own `/api` prefix — MUST pass the\n * // same options given to `forRoot(...)`:\n * const dashboardOptions = { apiBasePath: '/api/ai-gateway' };\n * app.setGlobalPrefix('api', { exclude: agentDashboardMountPaths(dashboardOptions) });\n * // -> ['ai-gateway', 'ai-gateway/{*splat}', 'api/ai-gateway', 'api/ai-gateway/{*splat}']\n * ```\n */\nexport function agentDashboardMountPaths(options?: AgentDashboardMountPathsOptions): string[] {\n const basePath = normalizeDashboardPath(options?.basePath ?? '/ai-gateway');\n const apiBasePath = normalizeDashboardPath(options?.apiBasePath ?? `${basePath}/api`);\n const base = unprefixed(basePath);\n const api = unprefixed(apiBasePath);\n return [base, `${base}/{*splat}`, api, `${api}/{*splat}`];\n}\n","import 'reflect-metadata';\nimport { type CanActivate, type DynamicModule, Module, type Type } from '@nestjs/common';\nimport { RouterModule } from '@nestjs/core';\nimport { AgentApiController } from './agent-api.controller.js';\nimport { AgentUiController } from './agent-ui.controller.js';\nimport { DashboardService } from './dashboard.service.js';\nimport { normalizeDashboardPath } from './normalize-path.js';\nimport { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH } from './tokens.js';\n\n/**\n * `@nestjs/common`'s own `GUARDS_METADATA` key, INLINED rather than deep-imported from\n * '@nestjs/common/constants' — that subpath has no extension and a strict ESM resolver (which the\n * built dual ESM/CJS output of this package is loaded under) 404s on it. A drift spec imports the\n * real constant (via the resolvable `'@nestjs/common/constants.js'` subpath) and asserts this literal\n * stays byte-identical to it.\n */\nconst GUARDS_METADATA = '__guards__';\n\nexport interface AgentDashboardOptions {\n /**\n * Where the SPA (UI) is served. Default `/ai-gateway`. This is a page route — keep it out of an\n * `/api` prefix so it reads as a UI, not an endpoint.\n */\n basePath?: string;\n /**\n * Where the JSON API is mounted (what the SPA fetches). Default `<basePath>/api`. Set it under\n * your app's `/api` prefix — e.g. `/api/ai-gateway` — so the API inherits the app's auth/proxy\n * rules while the UI stays at `basePath`.\n */\n apiBasePath?: string;\n /**\n * Guard classes fronting BOTH dashboard controllers (the SPA at `basePath` and its JSON API at\n * `apiBasePath`). Stamped onto each controller via `@nestjs/common`'s own `@UseGuards` metadata key\n * — REPLACE semantics, so a second `forRoot(...)` call overwrites (not appends to) whatever a prior\n * call stamped, same as re-applying `@UseGuards` by hand. Omit to leave the routes unguarded (the\n * host fronts them another way, e.g. a global guard or reverse-proxy auth).\n *\n * A guard's own DEPENDENCIES resolve from this module's `imports` (see {@link imports}) — the\n * dashboard module has no application context of its own to pull them from otherwise.\n */\n guards?: Type<CanActivate>[];\n /**\n * Extra `imports` merged into the dashboard's dynamic module — the DI resolution path for a class\n * passed to {@link guards} (or any other provider the controllers need reachable). Typically the\n * host's own auth module, e.g. `imports: [AuthModule]` alongside `guards: [JwtAuthGuard]`.\n */\n imports?: DynamicModule['imports'];\n}\n\n/** Leading slash, no trailing slash. */\nfunction normalize(path: string): string {\n return normalizeDashboardPath(path);\n}\n\n/** Stamp (or clear) `@UseGuards`-equivalent metadata on the dashboard controllers — REPLACE, not append. */\nfunction stampGuards(guards: Type<CanActivate>[] | undefined, ...controllers: Type[]): void {\n for (const controller of controllers) {\n Reflect.defineMetadata(GUARDS_METADATA, guards ?? [], controller);\n }\n}\n\n/** Holds the JSON API + SSE controller and its read service, mounted on its own path by `forRoot`. */\n@Module({\n controllers: [AgentApiController],\n providers: [DashboardService],\n exports: [DashboardService],\n})\nexport class AgentApiModule {}\n\n/**\n * Mounts the AI-gateway governance console: the bundled React SPA at `basePath` and its JSON + SSE\n * API at `apiBasePath` (default `<basePath>/api`).\n *\n * Import via `AgentDashboardModule.forRoot(...)` alongside your `@dudousxd/nestjs-agent` module\n * (global), which must provide `AGENT_GOVERNANCE_QUERIES` (bound by a store adapter). Front the\n * routes with the first-class `guards` option (plus `imports` for the guards' own dependencies) —\n * see {@link AgentDashboardOptions.guards}.\n */\n@Module({})\nexport class AgentDashboardModule {\n static forRoot(options: AgentDashboardOptions = {}): DynamicModule {\n const basePath = normalize(options.basePath ?? '/ai-gateway');\n const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);\n stampGuards(options.guards, AgentApiController, AgentUiController);\n return {\n module: AgentDashboardModule,\n imports: [\n ...(options.imports ?? []),\n AgentApiModule,\n RouterModule.register([\n { path: basePath, module: AgentDashboardModule }, // the UI controller below\n { path: apiBasePath, module: AgentApiModule },\n ]),\n ],\n controllers: [AgentUiController],\n providers: [\n { provide: DASHBOARD_BASE_PATH, useValue: basePath },\n { provide: DASHBOARD_API_PATH, useValue: apiBasePath },\n ],\n // Re-export the API module so its DashboardService reaches importers (e.g. the host's own controllers).\n exports: [AgentApiModule],\n };\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { basename, extname, join, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n Controller,\n Get,\n Header,\n Inject,\n NotFoundException,\n Param,\n StreamableFile,\n} from '@nestjs/common';\nimport { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH } from './tokens.js';\n\n/** The base the SPA bundle was built with (Vite `base`); rewritten to the configured base at serve time. */\nconst BUILD_BASE = '/ai-gateway';\n\n/** dist/server/agent-ui.controller.js -> ../spa (the Vite build output). */\nfunction spaDir(): string {\n return fileURLToPath(new URL('../spa', import.meta.url));\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n '.js': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.map': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.json': 'application/json; charset=utf-8',\n '.woff2': 'font/woff2',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Serves the bundled AI-gateway console SPA at the configured base (+ hashed assets at\n * `<base>/assets`). The path comes from `RouterModule` (set by\n * {@link AgentDashboardModule.forRoot}({ basePath })), so the controller routes are relative.\n */\n@Controller()\nexport class AgentUiController {\n private readonly dir = spaDir();\n\n constructor(\n @Inject(DASHBOARD_BASE_PATH) private readonly basePath: string,\n @Inject(DASHBOARD_API_PATH) private readonly apiBasePath: string,\n ) {}\n\n // index.html references hash-named bundles, so it MUST NOT be cached (stale bundle = the classic\n // \"stuck loading after a deploy\"). The hashed assets below are immutable.\n @Get()\n @Header('Content-Type', 'text/html; charset=utf-8')\n @Header('Cache-Control', 'no-store, must-revalidate')\n index(): string {\n const indexPath = join(this.dir, 'index.html');\n if (!existsSync(indexPath)) {\n throw new NotFoundException('Dashboard is not built. Run the package build.');\n }\n // The bundle was built with Vite base `/ai-gateway/`; rewrite asset URLs to the configured base\n // so the SPA loads from `<base>/assets` wherever it's mounted, and tell the client its API base.\n const html = readFileSync(indexPath, 'utf8').replaceAll(\n `=\"${BUILD_BASE}/`,\n `=\"${this.basePath}/`,\n );\n // __AGENT_BASE__ = where assets load; __AGENT_API__ = where the SPA fetches the JSON API.\n const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;\n return html.includes('</head>') ? html.replace('</head>', `${inject}</head>`) : inject + html;\n }\n\n @Get('assets/:file')\n @Header('Cache-Control', 'public, max-age=31536000, immutable')\n asset(@Param('file') file: string): StreamableFile {\n const safe = basename(file);\n if (safe !== file) throw new NotFoundException();\n const root = resolve(this.dir, 'assets');\n const assetPath = resolve(root, safe);\n if (!assetPath.startsWith(root + sep) || !existsSync(assetPath)) {\n throw new NotFoundException();\n }\n const type = CONTENT_TYPES[extname(safe)] ?? 'application/octet-stream';\n return new StreamableFile(readFileSync(assetPath), { type });\n }\n}\n"],"mappings":";;;;AACA,SAASA,MAAMC,YAAYC,KAAKC,MAAMC,OAAOC,WAAW;;;ACDxD,SAASC,WAAWC,mBAAmB;AAavC,SAASC,mBAAmB;AAC5B,SAASC,QAAQC,YAAYC,yBAAyBC,gBAAgB;AACtE,SAASC,cAAAA,mBAAkB;;;ACd3B,SAASC,2BAA2B;AAO7B,SAASC,gBAAgBC,MAAa;AAC3C,MAAI,OAAOA,SAAS,YAAYA,SAAS,MAAM;AAC7C,UAAM,IAAIC,oBAAoB,8BAAA;EAChC;AACA,QAAM,EAAEC,SAASC,iBAAiBC,kBAAkBC,sBAAsBC,oBAAmB,IAC3FN;AAEF,MAAI,OAAOE,YAAY,YAAYA,QAAQK,KAAI,EAAGC,WAAW,GAAG;AAC9D,UAAM,IAAIP,oBAAoB,uCAAA;EAChC;AACA,MAAI,CAACQ,oBAAoBN,eAAAA,GAAkB;AACzC,UAAM,IAAIF,oBAAoB,kDAAA;EAChC;AACA,MAAI,CAACQ,oBAAoBL,gBAAAA,GAAmB;AAC1C,UAAM,IAAIH,oBAAoB,mDAAA;EAChC;AACA,MAAII,yBAAyBK,UAAa,CAACD,oBAAoBJ,oBAAAA,GAAuB;AACpF,UAAM,IAAIJ,oBACR,oEAAA;EAEJ;AACA,MAAIK,wBAAwBI,UAAa,CAACD,oBAAoBH,mBAAAA,GAAsB;AAClF,UAAM,IAAIL,oBACR,mEAAA;EAEJ;AAEA,SAAO;IACLC;IACAC;IACAC;IACA,GAAIC,yBAAyBK,SAAY;MAAEL;IAAqB,IAAI,CAAC;IACrE,GAAIC,wBAAwBI,SAAY;MAAEJ;IAAoB,IAAI,CAAC;EACrE;AACF;AAlCgBP;AAoChB,SAASU,oBAAoBE,OAAc;AACzC,SAAO,OAAOA,UAAU,YAAYC,OAAOC,SAASF,KAAAA,KAAUA,SAAS;AACzE;AAFSF;;;AC7BF,IAAMK,2BAA2BC,OAAOC,IAAI,2CAAA;AAS5C,IAAMC,wBAAwBF,OAAOC,IAAI,wCAAA;AAOzC,IAAME,sBAAsBH,OAAOC,IAAI,sCAAA;AAGvC,IAAMG,sBAAsBJ,OAAOC,IAAI,4CAAA;AAGvC,IAAMI,qBAAqBL,OAAOC,IAAI,2CAAA;;;;;;;;;;;;;;;;;;;;AFA7C,IAAMK,gCACJ;AAcF,IAAMC,eAAe;EACnB;EACA;EACA;EACA;EACA;EACA;;AAWF,SAASC,gBAAgBC,SAAgB;AACvC,SACE,OAAOA,YAAY,YACnBA,YAAY,QACZ,WAAWA,WACX,OAAQA,QAA+BC,UAAU;AAErD;AAPSF;AAuBF,IAAMG,mBAAN,MAAMA;SAAAA;;;;;;EACX,YACqDC,SAGlCC,gBAGAC,cACjB;SAPmDF,UAAAA;SAGlCC,iBAAAA;SAGAC,eAAAA;EAChB;;EAGH,MAAMC,MAAMC,OAAgD;AAC1D,UAAM,CAACC,SAASC,YAAYC,KAAAA,IAAS,MAAMC,QAAQC,IAAI;MACrD,KAAKT,QAAQU,aAAaN,KAAAA;MAC1B,KAAKJ,QAAQW,aAAaP,KAAAA;MAC1B,KAAKJ,QAAQY,WAAWR,KAAAA;KACzB;AACD,UAAMS,UAAU,MAAM,KAAKC,gBAAgBR,UAAAA;AAC3C,WAAO;MAAED;MAASQ;MAASN;IAAM;EACnC;;EAGA,MAAMQ,WAAWX,OAAwBY,QAAQ,IAAwC;AACvF,UAAMC,OAAO,MAAM,KAAKjB,QAAQkB,cAAcd,OAAOY,KAAAA;AACrD,WAAO,KAAKF,gBAAgBG,IAAAA;EAC9B;;EAGAE,gBAAgBH,OAA+C;AAC7D,WAAO,KAAKhB,QAAQmB,gBAAgBH,KAAAA;EACtC;;EAGA,MAAMI,cAAcJ,OAAsD;AACxE,UAAMC,OAAO,MAAM,KAAKjB,QAAQoB,cAAcJ,KAAAA;AAC9C,WAAO,KAAKF,gBAAgBG,IAAAA;EAC9B;;;;;;EAOA,MAAcH,gBACZG,MACmC;AACnC,QAAIA,KAAKI,WAAW,GAAG;AACrB,aAAO,CAAA;IACT;AACA,QAAI,KAAKpB,mBAAmBqB,QAAW;AACrC,aAAOL,KAAKM,IAAI,CAACC,SAAS;QAAE,GAAGA;QAAKC,YAAY;MAAK,EAAA;IACvD;AACA,UAAMC,OAAO;SAAI,IAAIC,IAAIV,KAAKM,IAAI,CAACC,QAAQA,IAAII,QAAQ,CAAA;;AACvD,UAAMC,WAAW,MAAM,KAAK5B,eAAe6B,eAAeJ,IAAAA;AAC1D,WAAOT,KAAKM,IAAI,CAACC,SAAS;MAAE,GAAGA;MAAKC,YAAYI,SAASL,IAAII,QAAQ,KAAK;IAAK,EAAA;EACjF;;EAGA,MAAMG,aAA2C;AAC/C,QAAI,KAAK7B,iBAAiBoB,QAAW;AACnC,YAAM,IAAIU,wBAAwBtC,6BAAAA;IACpC;AACA,WAAO,KAAKQ,aAAa+B,kBAAiB;EAC5C;;;;;;EAOA,MAAMC,YAAYC,MAA8B;AAC9C,QAAI,KAAKjC,iBAAiBoB,QAAW;AACnC,YAAM,IAAIU,wBAAwBtC,6BAAAA;IACpC;AACA,UAAM,KAAKQ,aAAakC,iBAAiBC,gBAAgBF,IAAAA,CAAAA;EAC3D;;;;;;EAOAG,eAAqD;AACnD,WAAO,IAAIC,YAAqC,CAACC,eAAAA;AAC/C,YAAMC,WAAW9C,aAAa4B,IAAI,CAACzB,UAAAA;AACjC,cAAM4C,OAAOC,YAAY,SAAS7C,KAAAA;AAClC,cAAM8C,UAAU,wBAAC/C,YAAAA;AACf,cAAI,CAACD,gBAAgBC,OAAAA,EAAU;AAC/B2C,qBAAWK,KAAK;YACdC,MAAM;cACJhD,OAAOD,QAAQC;cACfiD,IAAIlD,QAAQkD,MAAMC,KAAKC,IAAG;cAC1BC,SAASrD,QAAQqD,WAAW,CAAC;YAC/B;UACF,CAAA;QACF,GATgB;AAUhBC,kBAAUT,MAAME,OAAAA;AAChB,eAAO;UAAEF;UAAME;QAAQ;MACzB,CAAA;AACA,aAAO,MAAA;AACL,mBAAWQ,WAAWX,SAAUY,aAAYD,QAAQV,MAAMU,QAAQR,OAAO;MAC3E;IACF,CAAA;EACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AD1LA,IAAMU,SAAS;AACf,IAAMC,UAAU;AAGhB,SAASC,OAAOC,SAAe;AAC7B,SAAO,IAAIC,KAAKA,KAAKC,IAAG,IAAKF,UAAUH,MAAAA,EAAQM,YAAW,EAAGC,MAAM,GAAG,EAAA;AACxE;AAFSL;AAKT,SAASM,MAAMC,OAA2BC,UAAgB;AACxD,SAAOD,UAAUE,UAAaV,QAAQW,KAAKH,KAAAA,IAASA,QAAQC;AAC9D;AAFSF;AAKT,SAASK,aACPC,MACAC,IAAsB;AAKtB,SAAO;IAAEC,SAASR,MAAMM,MAAMZ,OAAO,EAAA,CAAA;IAAMe,OAAOT,MAAMO,IAAIb,OAAO,CAAA,CAAA;EAAI;AACzE;AARSW;AAWT,SAASK,WAAWT,OAA2BC,UAAgB;AAC7D,QAAMS,SAASV,UAAUE,SAAYS,OAAOC,MAAMD,OAAOE,SAASb,OAAO,EAAA;AACzE,MAAI,CAACW,OAAOG,SAASJ,MAAAA,EAAS,QAAOT;AACrC,SAAOc,KAAKC,IAAI,GAAGD,KAAKE,IAAI,KAAKP,MAAAA,CAAAA;AACnC;AAJSD;AAWF,IAAMS,qBAAN,MAAMA;SAAAA;;;;EACX,YAA6BC,WAA6B;SAA7BA,YAAAA;EAA8B;;EAI3DC,MAAqBf,MAA4BC,IAAqC;AACpF,WAAO,KAAKa,UAAUC,MAAMhB,aAAaC,MAAMC,EAAAA,CAAAA;EACjD;;EAIAe,WACiBhB,MACFC,IACGgB,OACoB;AACpC,WAAO,KAAKH,UAAUE,WAAWjB,aAAaC,MAAMC,EAAAA,GAAKG,WAAWa,OAAO,EAAA,CAAA;EAC7E;;EAIAC,UAA0BD,OAAgD;AACxE,WAAO,KAAKH,UAAUK,gBAAgBf,WAAWa,OAAO,EAAA,CAAA;EAC1D;;EAIAG,QAAwBH,OAAuD;AAC7E,WAAO,KAAKH,UAAUO,cAAcjB,WAAWa,OAAO,EAAA,CAAA;EACxD;;;;;EAOAK,aAA2C;AACzC,WAAO,KAAKR,UAAUQ,WAAU;EAClC;;;;;;EAQAC,YAAoBC,MAA8B;AAChD,WAAO,KAAKV,UAAUS,YAAYC,IAAAA;EACpC;;EAIAC,SAA+C;AAC7C,WAAO,KAAKX,UAAUY,aAAY;EACpC;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AIjGO,SAASC,uBAAuBC,MAAY;AACjD,SAAO,IAAIA,KAAKC,QAAQ,cAAc,EAAA,CAAA;AACxC;AAFgBF;;;ACIhB,SAASG,WAAWC,MAAY;AAC9B,SAAOA,KAAKC,QAAQ,QAAQ,EAAA;AAC9B;AAFSF;AA4BF,SAASG,yBAAyBC,SAAyC;AAChF,QAAMC,WAAWC,uBAAuBF,SAASC,YAAY,aAAA;AAC7D,QAAME,cAAcD,uBAAuBF,SAASG,eAAe,GAAGF,QAAAA,MAAc;AACpF,QAAMG,OAAOR,WAAWK,QAAAA;AACxB,QAAMI,MAAMT,WAAWO,WAAAA;AACvB,SAAO;IAACC;IAAM,GAAGA,IAAAA;IAAiBC;IAAK,GAAGA,GAAAA;;AAC5C;AANgBN;;;ACrChB,OAAO;AACP,SAA+CO,cAAyB;AACxE,SAASC,oBAAoB;;;ACF7B,SAASC,YAAYC,oBAAoB;AACzC,SAASC,UAAUC,SAASC,MAAMC,SAASC,WAAW;AACtD,SAASC,qBAAqB;AAC9B,SACEC,cAAAA,aACAC,OAAAA,MACAC,QACAC,UAAAA,SACAC,mBACAC,OACAC,sBACK;;;;;;;;;;;;;;;;;;AAIP,IAAMC,aAAa;AAGnB,SAASC,SAAAA;AACP,SAAOC,cAAc,IAAIC,IAAI,UAAU,YAAYC,GAAG,CAAA;AACxD;AAFSH;AAIT,IAAMI,gBAAwC;EAC5C,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,UAAU;EACV,QAAQ;AACV;AAQO,IAAMC,oBAAN,MAAMA;SAAAA;;;;;EACMC,MAAMN,OAAAA;EAEvB,YACgDO,UACDC,aAC7C;SAF8CD,WAAAA;SACDC,cAAAA;EAC5C;;;EAOHC,QAAgB;AACd,UAAMC,YAAYC,KAAK,KAAKL,KAAK,YAAA;AACjC,QAAI,CAACM,WAAWF,SAAAA,GAAY;AAC1B,YAAM,IAAIG,kBAAkB,gDAAA;IAC9B;AAGA,UAAMC,OAAOC,aAAaL,WAAW,MAAA,EAAQM,WAC3C,KAAKjB,UAAAA,KACL,KAAK,KAAKQ,QAAQ,GAAG;AAGvB,UAAMU,SAAS,kCAAkC,KAAKV,QAAQ,2BAA2B,KAAKC,WAAW;AACzG,WAAOM,KAAKI,SAAS,SAAA,IAAaJ,KAAKK,QAAQ,WAAW,GAAGF,MAAAA,SAAe,IAAIA,SAASH;EAC3F;EAIAM,MAAqBC,MAA8B;AACjD,UAAMC,OAAOC,SAASF,IAAAA;AACtB,QAAIC,SAASD,KAAM,OAAM,IAAIR,kBAAAA;AAC7B,UAAMW,OAAOC,QAAQ,KAAKnB,KAAK,QAAA;AAC/B,UAAMoB,YAAYD,QAAQD,MAAMF,IAAAA;AAChC,QAAI,CAACI,UAAUC,WAAWH,OAAOI,GAAAA,KAAQ,CAAChB,WAAWc,SAAAA,GAAY;AAC/D,YAAM,IAAIb,kBAAAA;IACZ;AACA,UAAMgB,OAAOzB,cAAc0B,QAAQR,IAAAA,CAAAA,KAAU;AAC7C,WAAO,IAAIS,eAAehB,aAAaW,SAAAA,GAAY;MAAEG;IAAK,CAAA;EAC5D;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ADhEA,IAAMG,kBAAkB;AAkCxB,SAASC,UAAUC,MAAY;AAC7B,SAAOC,uBAAuBD,IAAAA;AAChC;AAFSD;AAKT,SAASG,YAAYC,WAA4CC,aAAmB;AAClF,aAAWC,cAAcD,aAAa;AACpCE,YAAQC,eAAeT,iBAAiBK,UAAU,CAAA,GAAIE,UAAAA;EACxD;AACF;AAJSH;AAYF,IAAMM,iBAAN,MAAMA;SAAAA;;;AAAgB;;;IAJ3BJ,aAAa;MAACK;;IACdC,WAAW;MAACC;;IACZC,SAAS;MAACD;;;;AAcL,IAAME,uBAAN,MAAMA,sBAAAA;SAAAA;;;EACX,OAAOC,QAAQC,UAAiC,CAAC,GAAkB;AACjE,UAAMC,WAAWjB,UAAUgB,QAAQC,YAAY,aAAA;AAC/C,UAAMC,cAAclB,UAAUgB,QAAQE,eAAe,GAAGD,QAAAA,MAAc;AACtEd,gBAAYa,QAAQZ,QAAQM,oBAAoBS,iBAAAA;AAChD,WAAO;MACLC,QAAQN;MACRO,SAAS;WACHL,QAAQK,WAAW,CAAA;QACvBZ;QACAa,aAAaC,SAAS;UACpB;YAAEtB,MAAMgB;YAAUG,QAAQN;UAAqB;UAC/C;YAAEb,MAAMiB;YAAaE,QAAQX;UAAe;SAC7C;;MAEHJ,aAAa;QAACc;;MACdR,WAAW;QACT;UAAEa,SAASC;UAAqBC,UAAUT;QAAS;QACnD;UAAEO,SAASG;UAAoBD,UAAUR;QAAY;;;MAGvDL,SAAS;QAACJ;;IACZ;EACF;AACF;;;;","names":["Body","Controller","Get","Post","Query","Sse","subscribe","unsubscribe","channelName","Inject","Injectable","NotImplementedException","Optional","Observable","BadRequestException","parsePriceInput","body","BadRequestException","modelId","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","trim","length","isFiniteNonNegative","undefined","value","Number","isFinite","AGENT_GOVERNANCE_QUERIES","Symbol","for","AGENT_ACTOR_DIRECTORY","AGENT_PRICING_STORE","DASHBOARD_BASE_PATH","DASHBOARD_API_PATH","PRICING_STORE_UNBOUND_MESSAGE","AGENT_EVENTS","isAgentEnvelope","message","event","DashboardService","queries","actorDirectory","pricingStore","spend","range","byModel","byActorRaw","trend","Promise","all","spendByModel","spendByActor","usageTrend","byActor","withActorLabels","topThreads","limit","rows","spendByThread","recentToolCalls","recentThreads","length","undefined","map","row","actorLabel","refs","Set","actorRef","resolved","resolveDisplay","listPrices","NotImplementedException","listCurrentPrices","upsertPrice","body","upsertModelPrice","parsePriceInput","streamEvents","Observable","subscriber","bindings","name","channelName","handler","next","data","ts","Date","now","payload","subscribe","binding","unsubscribe","DAY_MS","ISO_DAY","utcDay","daysAgo","Date","now","toISOString","slice","dayOr","value","fallback","undefined","test","resolveRange","from","to","fromDay","toDay","parseLimit","parsed","Number","NaN","parseInt","isFinite","Math","max","min","AgentApiController","dashboard","spend","topThreads","limit","toolCalls","recentToolCalls","threads","recentThreads","listPrices","upsertPrice","body","stream","streamEvents","normalizeDashboardPath","path","replace","unprefixed","path","replace","agentDashboardMountPaths","options","basePath","normalizeDashboardPath","apiBasePath","base","api","Module","RouterModule","existsSync","readFileSync","basename","extname","join","resolve","sep","fileURLToPath","Controller","Get","Header","Inject","NotFoundException","Param","StreamableFile","BUILD_BASE","spaDir","fileURLToPath","URL","url","CONTENT_TYPES","AgentUiController","dir","basePath","apiBasePath","index","indexPath","join","existsSync","NotFoundException","html","readFileSync","replaceAll","inject","includes","replace","asset","file","safe","basename","root","resolve","assetPath","startsWith","sep","type","extname","StreamableFile","GUARDS_METADATA","normalize","path","normalizeDashboardPath","stampGuards","guards","controllers","controller","Reflect","defineMetadata","AgentApiModule","AgentApiController","providers","DashboardService","exports","AgentDashboardModule","forRoot","options","basePath","apiBasePath","AgentUiController","module","imports","RouterModule","register","provide","DASHBOARD_BASE_PATH","useValue","DASHBOARD_API_PATH"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.relative{position:relative}.z-10{z-index:10}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-5{margin-bottom:1.25rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-4{height:1rem}.h-8{height:2rem}.max-h-\[520px\]{max-height:520px}.min-h-full{min-height:100%}.w-2\.5{width:.625rem}.w-24{width:6rem}.w-32{width:8rem}.w-4{width:1rem}.w-40{width:10rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[560px\]{min-width:560px}.min-w-\[640px\]{min-width:640px}.max-w-\[1180px\]{max-width:1180px}.max-w-\[240px\]{max-width:240px}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-dashed{border-style:dashed}.border-\[var\(--accent\)\]{border-color:var(--accent)}.border-\[var\(--line\)\]{border-color:var(--line)}.border-\[var\(--line-soft\)\]{border-color:var(--line-soft)}.border-transparent{border-color:transparent}.bg-\[var\(--panel\)\]{background-color:var(--panel)}.bg-transparent{background-color:transparent}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pl-4{padding-left:1rem}.pr-4{padding-right:1rem}.text-left{text-align:left}.text-right{text-align:right}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-none{line-height:1}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-\[var\(--accent\)\]{color:var(--accent)}.text-\[var\(--bad\)\]{color:var(--bad)}.text-\[var\(--good\)\]{color:var(--good)}.text-\[var\(--muted\)\]{color:var(--muted)}.text-\[var\(--text\)\]{color:var(--text)}.text-\[var\(--warn\)\]{color:var(--warn)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}:root{--bg: #08080b;--panel: #0d0d12;--panel-2: #101017;--line: #1d1d26;--line-soft: #16161d;--text: #e8e8ee;--muted: #7c7c88;--accent: #a78bfa;--accent-2: #22d3ee;--good: #34d399;--warn: #fbbf24;--bad: #f87171}*{box-sizing:border-box}html,body,#root{height:100%}body{margin:0;background:var(--bg);color:var(--text);font-family:Space Grotesk,ui-sans-serif,system-ui,sans-serif;-webkit-font-smoothing:antialiased}.app-bg{position:fixed;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;background-image:radial-gradient(900px 420px at 82% -10%,rgba(167,139,250,.1),transparent 70%),radial-gradient(700px 360px at 8% -12%,rgba(34,211,238,.06),transparent 70%),linear-gradient(to right,var(--line-soft) 1px,transparent 1px),linear-gradient(to bottom,var(--line-soft) 1px,transparent 1px);background-size:100% 100%,100% 100%,46px 46px,46px 46px;-webkit-mask-image:linear-gradient(to bottom,black,black 62%,transparent);mask-image:linear-gradient(to bottom,black,black 62%,transparent);opacity:.55}.mono{font-family:JetBrains Mono,ui-monospace,monospace}.tnum{font-variant-numeric:tabular-nums}.panel{background:linear-gradient(180deg,var(--panel-2),var(--panel));border:1px solid var(--line);border-radius:12px}.s-ok,.s-completed,.s-success{color:var(--good)}.s-running,.s-pending{color:var(--accent-2)}.s-forbidden,.s-denied,.s-failed,.s-error{color:var(--bad)}.s-warn{color:var(--warn)}.dot{width:7px;height:7px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 18%,transparent);display:inline-block}.pulse{animation:pulse 1.6s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.35}}@keyframes rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:rise .32s cubic-bezier(.2,.7,.2,1) both}.bar-track{background:var(--line);border-radius:999px;overflow:hidden}.bar-fill{height:100%;border-radius:999px;background:linear-gradient(90deg,var(--accent),var(--accent-2))}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#26262c;border:3px solid var(--bg);border-radius:999px}.hover\:bg-\[var\(--panel-2\)\]:hover{background-color:var(--panel-2)}.hover\:text-\[var\(--text\)\]:hover{color:var(--text)}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width: 640px){.sm\:flex-row{flex-direction:row}}@media (min-width: 768px){.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:col-span-2{grid-column:span 2 / span 2}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var be=e=>{throw TypeError(e)};var Vt=(e,t,s)=>t.has(e)||be("Cannot "+s);var i=(e,t,s)=>(Vt(e,t,"read from private field"),s?s.call(e):t.get(e)),d=(e,t,s)=>t.has(e)?be("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,s),u=(e,t,s,r)=>(Vt(e,t,"write to private field"),r?r.call(e,s):t.set(e,s),s),v=(e,t,s)=>(Vt(e,t,"access private method"),s);var $t=(e,t,s,r)=>({set _(n){u(e,t,n,s)},get _(){return i(e,t,r)}});import{r as C,j as y,p as ts,L as es,D as ss,C as rs,U as is,W as ns,T as as,A as os,a as us,P as hs,R as cs,b as ls,M as ds,S as fs,c as ps}from"./index-DXmRzl_c.js";var It=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},mt=typeof window>"u"||"Deno"in globalThis;function K(){}function ys(e,t){return typeof e=="function"?e(t):e}function Xt(e){return typeof e=="number"&&e>=0&&e!==1/0}function _e(e,t){return Math.max(e+(t||0)-Date.now(),0)}function St(e,t){return typeof e=="function"?e(t):e}function $(e,t){return typeof e=="function"?e(t):e}function ge(e,t){const{type:s="all",exact:r,fetchStatus:n,predicate:a,queryKey:o,stale:h}=e;if(o){if(r){if(t.queryHash!==fe(o,t.options))return!1}else if(!kt(t.queryKey,o))return!1}if(s!=="all"){const l=t.isActive();if(s==="active"&&!l||s==="inactive"&&l)return!1}return!(typeof h=="boolean"&&t.isStale()!==h||n&&n!==t.state.fetchStatus||a&&!a(t))}function we(e,t){const{exact:s,status:r,predicate:n,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(s){if(vt(t.options.mutationKey)!==vt(a))return!1}else if(!kt(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||n&&!n(t))}function fe(e,t){return((t==null?void 0:t.queryKeyHashFn)||vt)(e)}function vt(e){return JSON.stringify(e,(t,s)=>Zt(s)?Object.keys(s).sort().reduce((r,n)=>(r[n]=s[n],r),{}):s)}function kt(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?!Object.keys(t).some(s=>!kt(e[s],t[s])):!1}function Ke(e,t){if(e===t)return e;const s=Se(e)&&Se(t);if(s||Zt(e)&&Zt(t)){const r=s?e:Object.keys(e),n=r.length,a=s?t:Object.keys(t),o=a.length,h=s?[]:{};let l=0;for(let b=0;b<o;b++){const f=s?b:a[b];(!s&&r.includes(f)||s)&&e[f]===void 0&&t[f]===void 0?(h[f]=void 0,l++):(h[f]=Ke(e[f],t[f]),h[f]===e[f]&&e[f]!==void 0&&l++)}return n===o&&l===n?e:h}return t}function Wt(e,t){if(!t||Object.keys(e).length!==Object.keys(t).length)return!1;for(const s in e)if(e[s]!==t[s])return!1;return!0}function Se(e){return Array.isArray(e)&&e.length===Object.keys(e).length}function Zt(e){if(!xe(e))return!1;const t=e.constructor;if(t===void 0)return!0;const s=t.prototype;return!(!xe(s)||!s.hasOwnProperty("isPrototypeOf")||Object.getPrototypeOf(e)!==Object.prototype)}function xe(e){return Object.prototype.toString.call(e)==="[object Object]"}function ms(e){return new Promise(t=>{setTimeout(t,e)})}function te(e,t,s){return typeof s.structuralSharing=="function"?s.structuralSharing(e,t):s.structuralSharing!==!1?Ke(e,t):t}function vs(e,t,s=0){const r=[...e,t];return s&&r.length>s?r.slice(1):r}function bs(e,t,s=0){const r=[t,...e];return s&&r.length>s?r.slice(0,-1):r}var pe=Symbol();function He(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===pe?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}var ht,tt,xt,Te,gs=(Te=class extends It{constructor(){super();d(this,ht);d(this,tt);d(this,xt);u(this,xt,t=>{if(!mt&&window.addEventListener){const s=()=>t();return window.addEventListener("visibilitychange",s,!1),()=>{window.removeEventListener("visibilitychange",s)}}})}onSubscribe(){i(this,tt)||this.setEventListener(i(this,xt))}onUnsubscribe(){var t;this.hasListeners()||((t=i(this,tt))==null||t.call(this),u(this,tt,void 0))}setEventListener(t){var s;u(this,xt,t),(s=i(this,tt))==null||s.call(this),u(this,tt,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){i(this,ht)!==t&&(u(this,ht,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(s=>{s(t)})}isFocused(){var t;return typeof i(this,ht)=="boolean"?i(this,ht):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},ht=new WeakMap,tt=new WeakMap,xt=new WeakMap,Te),ye=new gs,Ct,et,Ot,Me,ws=(Me=class extends It{constructor(){super();d(this,Ct,!0);d(this,et);d(this,Ot);u(this,Ot,t=>{if(!mt&&window.addEventListener){const s=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",s,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",s),window.removeEventListener("offline",r)}}})}onSubscribe(){i(this,et)||this.setEventListener(i(this,Ot))}onUnsubscribe(){var t;this.hasListeners()||((t=i(this,et))==null||t.call(this),u(this,et,void 0))}setEventListener(t){var s;u(this,Ot,t),(s=i(this,et))==null||s.call(this),u(this,et,t(this.setOnline.bind(this)))}setOnline(t){i(this,Ct)!==t&&(u(this,Ct,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return i(this,Ct)}},Ct=new WeakMap,et=new WeakMap,Ot=new WeakMap,Me),Yt=new ws;function ee(){let e,t;const s=new Promise((n,a)=>{e=n,t=a});s.status="pending",s.catch(()=>{});function r(n){Object.assign(s,n),delete s.resolve,delete s.reject}return s.resolve=n=>{r({status:"fulfilled",value:n}),e(n)},s.reject=n=>{r({status:"rejected",reason:n}),t(n)},s}function Ss(e){return Math.min(1e3*2**e,3e4)}function Ge(e){return(e??"online")==="online"?Yt.isOnline():!0}var $e=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function Jt(e){return e instanceof $e}function Be(e){let t=!1,s=0,r=!1,n;const a=ee(),o=p=>{var S;r||(g(new $e(p)),(S=e.abort)==null||S.call(e))},h=()=>{t=!0},l=()=>{t=!1},b=()=>ye.isFocused()&&(e.networkMode==="always"||Yt.isOnline())&&e.canRun(),f=()=>Ge(e.networkMode)&&e.canRun(),c=p=>{var S;r||(r=!0,(S=e.onSuccess)==null||S.call(e,p),n==null||n(),a.resolve(p))},g=p=>{var S;r||(r=!0,(S=e.onError)==null||S.call(e,p),n==null||n(),a.reject(p))},m=()=>new Promise(p=>{var S;n=j=>{(r||b())&&p(j)},(S=e.onPause)==null||S.call(e)}).then(()=>{var p;n=void 0,r||(p=e.onContinue)==null||p.call(e)}),E=()=>{if(r)return;let p;const S=s===0?e.initialPromise:void 0;try{p=S??e.fn()}catch(j){p=Promise.reject(j)}Promise.resolve(p).then(c).catch(j=>{var H;if(r)return;const A=e.retry??(mt?0:3),P=e.retryDelay??Ss,T=typeof P=="function"?P(s,j):P,L=A===!0||typeof A=="number"&&s<A||typeof A=="function"&&A(s,j);if(t||!L){g(j);return}s++,(H=e.onFail)==null||H.call(e,s,j),ms(T).then(()=>b()?void 0:m()).then(()=>{t?g(j):E()})})};return{promise:a,cancel:o,continue:()=>(n==null||n(),a),cancelRetry:h,continueRetry:l,canStart:f,start:()=>(f()?E():m().then(E),a)}}function xs(){let e=[],t=0,s=h=>{h()},r=h=>{h()},n=h=>setTimeout(h,0);const a=h=>{t?e.push(h):n(()=>{s(h)})},o=()=>{const h=e;e=[],h.length&&n(()=>{r(()=>{h.forEach(l=>{s(l)})})})};return{batch:h=>{let l;t++;try{l=h()}finally{t--,t||o()}return l},batchCalls:h=>(...l)=>{a(()=>{h(...l)})},schedule:a,setNotifyFunction:h=>{s=h},setBatchNotifyFunction:h=>{r=h},setScheduler:h=>{n=h}}}var D=xs(),ct,Ae,ze=(Ae=class{constructor(){d(this,ct)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),Xt(this.gcTime)&&u(this,ct,setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(mt?1/0:5*60*1e3))}clearGcTimeout(){i(this,ct)&&(clearTimeout(i(this,ct)),u(this,ct,void 0))}},ct=new WeakMap,Ae),Pt,Rt,_,M,Lt,lt,G,V,Qe,Cs=(Qe=class extends ze{constructor(t){super();d(this,G);d(this,Pt);d(this,Rt);d(this,_);d(this,M);d(this,Lt);d(this,lt);u(this,lt,!1),u(this,Lt,t.defaultOptions),this.setOptions(t.options),this.observers=[],u(this,_,t.cache),this.queryKey=t.queryKey,this.queryHash=t.queryHash,u(this,Pt,Os(this.options)),this.state=t.state??i(this,Pt),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=i(this,M))==null?void 0:t.promise}setOptions(t){this.options={...i(this,Lt),...t},this.updateGcTime(this.options.gcTime)}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&i(this,_).remove(this)}setData(t,s){const r=te(this.state.data,t,this.options);return v(this,G,V).call(this,{data:r,type:"success",dataUpdatedAt:s==null?void 0:s.updatedAt,manual:s==null?void 0:s.manual}),r}setState(t,s){v(this,G,V).call(this,{type:"setState",state:t,setStateOptions:s})}cancel(t){var r,n;const s=(r=i(this,M))==null?void 0:r.promise;return(n=i(this,M))==null||n.cancel(t),s?s.then(K).catch(K):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(i(this,Pt))}isActive(){return this.observers.some(t=>$(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===pe||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStale(){return this.state.isInvalidated?!0:this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0}isStaleByTime(t=0){return this.state.isInvalidated||this.state.data===void 0||!_e(this.state.dataUpdatedAt,t)}onFocus(){var s;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(s=i(this,M))==null||s.continue()}onOnline(){var s;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(s=i(this,M))==null||s.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),i(this,_).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(s=>s!==t),this.observers.length||(i(this,M)&&(i(this,lt)?i(this,M).cancel({revert:!0}):i(this,M).cancelRetry()),this.scheduleGc()),i(this,_).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||v(this,G,V).call(this,{type:"invalidate"})}fetch(t,s){var l,b,f;if(this.state.fetchStatus!=="idle"){if(this.state.data!==void 0&&(s!=null&&s.cancelRefetch))this.cancel({silent:!0});else if(i(this,M))return i(this,M).continueRetry(),i(this,M).promise}if(t&&this.setOptions(t),!this.options.queryFn){const c=this.observers.find(g=>g.options.queryFn);c&&this.setOptions(c.options)}const r=new AbortController,n=c=>{Object.defineProperty(c,"signal",{enumerable:!0,get:()=>(u(this,lt,!0),r.signal)})},a=()=>{const c=He(this.options,s),g={queryKey:this.queryKey,meta:this.meta};return n(g),u(this,lt,!1),this.options.persister?this.options.persister(c,g,this):c(g)},o={fetchOptions:s,options:this.options,queryKey:this.queryKey,state:this.state,fetchFn:a};n(o),(l=this.options.behavior)==null||l.onFetch(o,this),u(this,Rt,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((b=o.fetchOptions)==null?void 0:b.meta))&&v(this,G,V).call(this,{type:"fetch",meta:(f=o.fetchOptions)==null?void 0:f.meta});const h=c=>{var g,m,E,p;Jt(c)&&c.silent||v(this,G,V).call(this,{type:"error",error:c}),Jt(c)||((m=(g=i(this,_).config).onError)==null||m.call(g,c,this),(p=(E=i(this,_).config).onSettled)==null||p.call(E,this.state.data,c,this)),this.scheduleGc()};return u(this,M,Be({initialPromise:s==null?void 0:s.initialPromise,fn:o.fetchFn,abort:r.abort.bind(r),onSuccess:c=>{var g,m,E,p;if(c===void 0){h(new Error(`${this.queryHash} data is undefined`));return}try{this.setData(c)}catch(S){h(S);return}(m=(g=i(this,_).config).onSuccess)==null||m.call(g,c,this),(p=(E=i(this,_).config).onSettled)==null||p.call(E,c,this.state.error,this),this.scheduleGc()},onError:h,onFail:(c,g)=>{v(this,G,V).call(this,{type:"failed",failureCount:c,error:g})},onPause:()=>{v(this,G,V).call(this,{type:"pause"})},onContinue:()=>{v(this,G,V).call(this,{type:"continue"})},retry:o.options.retry,retryDelay:o.options.retryDelay,networkMode:o.options.networkMode,canRun:()=>!0})),i(this,M).start()}},Pt=new WeakMap,Rt=new WeakMap,_=new WeakMap,M=new WeakMap,Lt=new WeakMap,lt=new WeakMap,G=new WeakSet,V=function(t){const s=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...We(r.data,this.options),fetchMeta:t.meta??null};case"success":return{...r,data:t.data,dataUpdateCount:r.dataUpdateCount+1,dataUpdatedAt:t.dataUpdatedAt??Date.now(),error:null,isInvalidated:!1,status:"success",...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};case"error":const n=t.error;return Jt(n)&&n.revert&&i(this,Rt)?{...i(this,Rt),fetchStatus:"idle"}:{...r,error:n,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:n,fetchStatus:"idle",status:"error"};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=s(this.state),D.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),i(this,_).notify({query:this,type:"updated",action:t})})},Qe);function We(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:Ge(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function Os(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,s=t!==void 0,r=s?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:s?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:s?"success":"pending",fetchStatus:"idle"}}var B,Ie,Ps=(Ie=class extends It{constructor(t={}){super();d(this,B);this.config=t,u(this,B,new Map)}build(t,s,r){const n=s.queryKey,a=s.queryHash??fe(n,s);let o=this.get(a);return o||(o=new Cs({cache:this,queryKey:n,queryHash:a,options:t.defaultQueryOptions(s),state:r,defaultOptions:t.getQueryDefaults(n)}),this.add(o)),o}add(t){i(this,B).has(t.queryHash)||(i(this,B).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const s=i(this,B).get(t.queryHash);s&&(t.destroy(),s===t&&i(this,B).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){D.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return i(this,B).get(t)}getAll(){return[...i(this,B).values()]}find(t){const s={exact:!0,...t};return this.getAll().find(r=>ge(s,r))}findAll(t={}){const s=this.getAll();return Object.keys(t).length>0?s.filter(r=>ge(t,r)):s}notify(t){D.batch(()=>{this.listeners.forEach(s=>{s(t)})})}onFocus(){D.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){D.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},B=new WeakMap,Ie),z,I,dt,W,Z,qe,Rs=(qe=class extends ze{constructor(t){super();d(this,W);d(this,z);d(this,I);d(this,dt);this.mutationId=t.mutationId,u(this,I,t.mutationCache),u(this,z,[]),this.state=t.state||Ye(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){i(this,z).includes(t)||(i(this,z).push(t),this.clearGcTimeout(),i(this,I).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){u(this,z,i(this,z).filter(s=>s!==t)),this.scheduleGc(),i(this,I).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){i(this,z).length||(this.state.status==="pending"?this.scheduleGc():i(this,I).remove(this))}continue(){var t;return((t=i(this,dt))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var n,a,o,h,l,b,f,c,g,m,E,p,S,j,A,P,T,L,H,Q;u(this,dt,Be({fn:()=>this.options.mutationFn?this.options.mutationFn(t):Promise.reject(new Error("No mutationFn found")),onFail:(F,O)=>{v(this,W,Z).call(this,{type:"failed",failureCount:F,error:O})},onPause:()=>{v(this,W,Z).call(this,{type:"pause"})},onContinue:()=>{v(this,W,Z).call(this,{type:"continue"})},retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>i(this,I).canRun(this)}));const s=this.state.status==="pending",r=!i(this,dt).canStart();try{if(!s){v(this,W,Z).call(this,{type:"pending",variables:t,isPaused:r}),await((a=(n=i(this,I).config).onMutate)==null?void 0:a.call(n,t,this));const O=await((h=(o=this.options).onMutate)==null?void 0:h.call(o,t));O!==this.state.context&&v(this,W,Z).call(this,{type:"pending",context:O,variables:t,isPaused:r})}const F=await i(this,dt).start();return await((b=(l=i(this,I).config).onSuccess)==null?void 0:b.call(l,F,t,this.state.context,this)),await((c=(f=this.options).onSuccess)==null?void 0:c.call(f,F,t,this.state.context)),await((m=(g=i(this,I).config).onSettled)==null?void 0:m.call(g,F,null,this.state.variables,this.state.context,this)),await((p=(E=this.options).onSettled)==null?void 0:p.call(E,F,null,t,this.state.context)),v(this,W,Z).call(this,{type:"success",data:F}),F}catch(F){try{throw await((j=(S=i(this,I).config).onError)==null?void 0:j.call(S,F,t,this.state.context,this)),await((P=(A=this.options).onError)==null?void 0:P.call(A,F,t,this.state.context)),await((L=(T=i(this,I).config).onSettled)==null?void 0:L.call(T,void 0,F,this.state.variables,this.state.context,this)),await((Q=(H=this.options).onSettled)==null?void 0:Q.call(H,void 0,F,t,this.state.context)),F}finally{v(this,W,Z).call(this,{type:"error",error:F})}}finally{i(this,I).runNext(this)}}},z=new WeakMap,I=new WeakMap,dt=new WeakMap,W=new WeakSet,Z=function(t){const s=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=s(this.state),D.batch(()=>{i(this,z).forEach(r=>{r.onMutationUpdate(t)}),i(this,I).notify({mutation:this,type:"updated",action:t})})},qe);function Ye(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var N,Nt,Ue,Es=(Ue=class extends It{constructor(t={}){super();d(this,N);d(this,Nt);this.config=t,u(this,N,new Map),u(this,Nt,Date.now())}build(t,s,r){const n=new Rs({mutationCache:this,mutationId:++$t(this,Nt)._,options:t.defaultMutationOptions(s),state:r});return this.add(n),n}add(t){const s=Bt(t),r=i(this,N).get(s)??[];r.push(t),i(this,N).set(s,r),this.notify({type:"added",mutation:t})}remove(t){var r;const s=Bt(t);if(i(this,N).has(s)){const n=(r=i(this,N).get(s))==null?void 0:r.filter(a=>a!==t);n&&(n.length===0?i(this,N).delete(s):i(this,N).set(s,n))}this.notify({type:"removed",mutation:t})}canRun(t){var r;const s=(r=i(this,N).get(Bt(t)))==null?void 0:r.find(n=>n.state.status==="pending");return!s||s===t}runNext(t){var r;const s=(r=i(this,N).get(Bt(t)))==null?void 0:r.find(n=>n!==t&&n.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}clear(){D.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}getAll(){return[...i(this,N).values()].flat()}find(t){const s={exact:!0,...t};return this.getAll().find(r=>we(s,r))}findAll(t={}){return this.getAll().filter(s=>we(t,s))}notify(t){D.batch(()=>{this.listeners.forEach(s=>{s(t)})})}resumePausedMutations(){const t=this.getAll().filter(s=>s.state.isPaused);return D.batch(()=>Promise.all(t.map(s=>s.continue().catch(K))))}},N=new WeakMap,Nt=new WeakMap,Ue);function Bt(e){var t;return((t=e.options.scope)==null?void 0:t.id)??String(e.mutationId)}function Ce(e){return{onFetch:(t,s)=>{var f,c,g,m,E;const r=t.options,n=(g=(c=(f=t.fetchOptions)==null?void 0:f.meta)==null?void 0:c.fetchMore)==null?void 0:g.direction,a=((m=t.state.data)==null?void 0:m.pages)||[],o=((E=t.state.data)==null?void 0:E.pageParams)||[];let h={pages:[],pageParams:[]},l=0;const b=async()=>{let p=!1;const S=P=>{Object.defineProperty(P,"signal",{enumerable:!0,get:()=>(t.signal.aborted?p=!0:t.signal.addEventListener("abort",()=>{p=!0}),t.signal)})},j=He(t.options,t.fetchOptions),A=async(P,T,L)=>{if(p)return Promise.reject();if(T==null&&P.pages.length)return Promise.resolve(P);const H={queryKey:t.queryKey,pageParam:T,direction:L?"backward":"forward",meta:t.options.meta};S(H);const Q=await j(H),{maxPages:F}=t.options,O=L?bs:vs;return{pages:O(P.pages,Q,F),pageParams:O(P.pageParams,T,F)}};if(n&&a.length){const P=n==="backward",T=P?Fs:Oe,L={pages:a,pageParams:o},H=T(r,L);h=await A(L,H,P)}else{const P=e??a.length;do{const T=l===0?o[0]??r.initialPageParam:Oe(r,h);if(l>0&&T==null)break;h=await A(h,T),l++}while(l<P)}return h};t.options.persister?t.fetchFn=()=>{var p,S;return(S=(p=t.options).persister)==null?void 0:S.call(p,b,{queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},s)}:t.fetchFn=b}}}function Oe(e,{pages:t,pageParams:s}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,s[r],s):void 0}function Fs(e,{pages:t,pageParams:s}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,s[0],s):void 0}var R,st,rt,Et,Ft,it,Dt,jt,ke,Ds=(ke=class{constructor(e={}){d(this,R);d(this,st);d(this,rt);d(this,Et);d(this,Ft);d(this,it);d(this,Dt);d(this,jt);u(this,R,e.queryCache||new Ps),u(this,st,e.mutationCache||new Es),u(this,rt,e.defaultOptions||{}),u(this,Et,new Map),u(this,Ft,new Map),u(this,it,0)}mount(){$t(this,it)._++,i(this,it)===1&&(u(this,Dt,ye.subscribe(async e=>{e&&(await this.resumePausedMutations(),i(this,R).onFocus())})),u(this,jt,Yt.subscribe(async e=>{e&&(await this.resumePausedMutations(),i(this,R).onOnline())})))}unmount(){var e,t;$t(this,it)._--,i(this,it)===0&&((e=i(this,Dt))==null||e.call(this),u(this,Dt,void 0),(t=i(this,jt))==null||t.call(this),u(this,jt,void 0))}isFetching(e){return i(this,R).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return i(this,st).findAll({...e,status:"pending"}).length}getQueryData(e){var s;const t=this.defaultQueryOptions({queryKey:e});return(s=i(this,R).get(t.queryHash))==null?void 0:s.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),s=i(this,R).build(this,t),r=s.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&s.isStaleByTime(St(t.staleTime,s))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return i(this,R).findAll(e).map(({queryKey:t,state:s})=>{const r=s.data;return[t,r]})}setQueryData(e,t,s){const r=this.defaultQueryOptions({queryKey:e}),n=i(this,R).get(r.queryHash),a=n==null?void 0:n.state.data,o=ys(t,a);if(o!==void 0)return i(this,R).build(this,r).setData(o,{...s,manual:!0})}setQueriesData(e,t,s){return D.batch(()=>i(this,R).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,s)]))}getQueryState(e){var s;const t=this.defaultQueryOptions({queryKey:e});return(s=i(this,R).get(t.queryHash))==null?void 0:s.state}removeQueries(e){const t=i(this,R);D.batch(()=>{t.findAll(e).forEach(s=>{t.remove(s)})})}resetQueries(e,t){const s=i(this,R),r={type:"active",...e};return D.batch(()=>(s.findAll(e).forEach(n=>{n.reset()}),this.refetchQueries(r,t)))}cancelQueries(e,t={}){const s={revert:!0,...t},r=D.batch(()=>i(this,R).findAll(e).map(n=>n.cancel(s)));return Promise.all(r).then(K).catch(K)}invalidateQueries(e,t={}){return D.batch(()=>{if(i(this,R).findAll(e).forEach(r=>{r.invalidate()}),(e==null?void 0:e.refetchType)==="none")return Promise.resolve();const s={...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"};return this.refetchQueries(s,t)})}refetchQueries(e,t={}){const s={...t,cancelRefetch:t.cancelRefetch??!0},r=D.batch(()=>i(this,R).findAll(e).filter(n=>!n.isDisabled()).map(n=>{let a=n.fetch(void 0,s);return s.throwOnError||(a=a.catch(K)),n.state.fetchStatus==="paused"?Promise.resolve():a}));return Promise.all(r).then(K)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const s=i(this,R).build(this,t);return s.isStaleByTime(St(t.staleTime,s))?s.fetch(t):Promise.resolve(s.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(K).catch(K)}fetchInfiniteQuery(e){return e.behavior=Ce(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(K).catch(K)}ensureInfiniteQueryData(e){return e.behavior=Ce(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return Yt.isOnline()?i(this,st).resumePausedMutations():Promise.resolve()}getQueryCache(){return i(this,R)}getMutationCache(){return i(this,st)}getDefaultOptions(){return i(this,rt)}setDefaultOptions(e){u(this,rt,e)}setQueryDefaults(e,t){i(this,Et).set(vt(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...i(this,Et).values()],s={};return t.forEach(r=>{kt(e,r.queryKey)&&Object.assign(s,r.defaultOptions)}),s}setMutationDefaults(e,t){i(this,Ft).set(vt(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...i(this,Ft).values()];let s={};return t.forEach(r=>{kt(e,r.mutationKey)&&(s={...s,...r.defaultOptions})}),s}defaultQueryOptions(e){if(e._defaulted)return e;const t={...i(this,rt).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=fe(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===pe&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...i(this,rt).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){i(this,R).clear(),i(this,st).clear()}},R=new WeakMap,st=new WeakMap,rt=new WeakMap,Et=new WeakMap,Ft=new WeakMap,it=new WeakMap,Dt=new WeakMap,jt=new WeakMap,ke),U,w,_t,q,ft,Tt,nt,Y,Kt,Mt,At,pt,yt,at,Qt,x,Ut,se,re,ie,ne,ae,oe,ue,Ve,Le,js=(Le=class extends It{constructor(t,s){super();d(this,x);d(this,U);d(this,w);d(this,_t);d(this,q);d(this,ft);d(this,Tt);d(this,nt);d(this,Y);d(this,Kt);d(this,Mt);d(this,At);d(this,pt);d(this,yt);d(this,at);d(this,Qt,new Set);this.options=s,u(this,U,t),u(this,Y,null),u(this,nt,ee()),this.options.experimental_prefetchInRender||i(this,nt).reject(new Error("experimental_prefetchInRender feature flag is not enabled")),this.bindMethods(),this.setOptions(s)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(i(this,w).addObserver(this),Pe(i(this,w),this.options)?v(this,x,Ut).call(this):this.updateResult(),v(this,x,ne).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return he(i(this,w),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return he(i(this,w),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,v(this,x,ae).call(this),v(this,x,oe).call(this),i(this,w).removeObserver(this)}setOptions(t,s){const r=this.options,n=i(this,w);if(this.options=i(this,U).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof $(this.options.enabled,i(this,w))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");v(this,x,ue).call(this),i(this,w).setOptions(this.options),r._defaulted&&!Wt(this.options,r)&&i(this,U).getQueryCache().notify({type:"observerOptionsUpdated",query:i(this,w),observer:this});const a=this.hasListeners();a&&Re(i(this,w),n,this.options,r)&&v(this,x,Ut).call(this),this.updateResult(s),a&&(i(this,w)!==n||$(this.options.enabled,i(this,w))!==$(r.enabled,i(this,w))||St(this.options.staleTime,i(this,w))!==St(r.staleTime,i(this,w)))&&v(this,x,se).call(this);const o=v(this,x,re).call(this);a&&(i(this,w)!==n||$(this.options.enabled,i(this,w))!==$(r.enabled,i(this,w))||o!==i(this,at))&&v(this,x,ie).call(this,o)}getOptimisticResult(t){const s=i(this,U).getQueryCache().build(i(this,U),t),r=this.createResult(s,t);return Ms(this,r)&&(u(this,q,r),u(this,Tt,this.options),u(this,ft,i(this,w).state)),r}getCurrentResult(){return i(this,q)}trackResult(t,s){const r={};return Object.keys(t).forEach(n=>{Object.defineProperty(r,n,{configurable:!1,enumerable:!0,get:()=>(this.trackProp(n),s==null||s(n),t[n])})}),r}trackProp(t){i(this,Qt).add(t)}getCurrentQuery(){return i(this,w)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const s=i(this,U).defaultQueryOptions(t),r=i(this,U).getQueryCache().build(i(this,U),s);return r.fetch().then(()=>this.createResult(r,s))}fetch(t){return v(this,x,Ut).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),i(this,q)))}createResult(t,s){var F;const r=i(this,w),n=this.options,a=i(this,q),o=i(this,ft),h=i(this,Tt),b=t!==r?t.state:i(this,_t),{state:f}=t;let c={...f},g=!1,m;if(s._optimisticResults){const O=this.hasListeners(),gt=!O&&Pe(t,s),wt=O&&Re(t,r,s,n);(gt||wt)&&(c={...c,...We(f.data,t.options)}),s._optimisticResults==="isRestoring"&&(c.fetchStatus="idle")}let{error:E,errorUpdatedAt:p,status:S}=c;if(s.select&&c.data!==void 0)if(a&&c.data===(o==null?void 0:o.data)&&s.select===i(this,Kt))m=i(this,Mt);else try{u(this,Kt,s.select),m=s.select(c.data),m=te(a==null?void 0:a.data,m,s),u(this,Mt,m),u(this,Y,null)}catch(O){u(this,Y,O)}else m=c.data;if(s.placeholderData!==void 0&&m===void 0&&S==="pending"){let O;if(a!=null&&a.isPlaceholderData&&s.placeholderData===(h==null?void 0:h.placeholderData))O=a.data;else if(O=typeof s.placeholderData=="function"?s.placeholderData((F=i(this,At))==null?void 0:F.state.data,i(this,At)):s.placeholderData,s.select&&O!==void 0)try{O=s.select(O),u(this,Y,null)}catch(gt){u(this,Y,gt)}O!==void 0&&(S="success",m=te(a==null?void 0:a.data,O,s),g=!0)}i(this,Y)&&(E=i(this,Y),m=i(this,Mt),p=Date.now(),S="error");const j=c.fetchStatus==="fetching",A=S==="pending",P=S==="error",T=A&&j,L=m!==void 0,Q={status:S,fetchStatus:c.fetchStatus,isPending:A,isSuccess:S==="success",isError:P,isInitialLoading:T,isLoading:T,data:m,dataUpdatedAt:c.dataUpdatedAt,error:E,errorUpdatedAt:p,failureCount:c.fetchFailureCount,failureReason:c.fetchFailureReason,errorUpdateCount:c.errorUpdateCount,isFetched:c.dataUpdateCount>0||c.errorUpdateCount>0,isFetchedAfterMount:c.dataUpdateCount>b.dataUpdateCount||c.errorUpdateCount>b.errorUpdateCount,isFetching:j,isRefetching:j&&!A,isLoadingError:P&&!L,isPaused:c.fetchStatus==="paused",isPlaceholderData:g,isRefetchError:P&&L,isStale:me(t,s),refetch:this.refetch,promise:i(this,nt)};if(this.options.experimental_prefetchInRender){const O=Gt=>{Q.status==="error"?Gt.reject(Q.error):Q.data!==void 0&&Gt.resolve(Q.data)},gt=()=>{const Gt=u(this,nt,Q.promise=ee());O(Gt)},wt=i(this,nt);switch(wt.status){case"pending":t.queryHash===r.queryHash&&O(wt);break;case"fulfilled":(Q.status==="error"||Q.data!==wt.value)&>();break;case"rejected":(Q.status!=="error"||Q.error!==wt.reason)&>();break}}return Q}updateResult(t){const s=i(this,q),r=this.createResult(i(this,w),this.options);if(u(this,ft,i(this,w).state),u(this,Tt,this.options),i(this,ft).data!==void 0&&u(this,At,i(this,w)),Wt(r,s))return;u(this,q,r);const n={},a=()=>{if(!s)return!0;const{notifyOnChangeProps:o}=this.options,h=typeof o=="function"?o():o;if(h==="all"||!h&&!i(this,Qt).size)return!0;const l=new Set(h??i(this,Qt));return this.options.throwOnError&&l.add("error"),Object.keys(i(this,q)).some(b=>{const f=b;return i(this,q)[f]!==s[f]&&l.has(f)})};(t==null?void 0:t.listeners)!==!1&&a()&&(n.listeners=!0),v(this,x,Ve).call(this,{...n,...t})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&v(this,x,ne).call(this)}},U=new WeakMap,w=new WeakMap,_t=new WeakMap,q=new WeakMap,ft=new WeakMap,Tt=new WeakMap,nt=new WeakMap,Y=new WeakMap,Kt=new WeakMap,Mt=new WeakMap,At=new WeakMap,pt=new WeakMap,yt=new WeakMap,at=new WeakMap,Qt=new WeakMap,x=new WeakSet,Ut=function(t){v(this,x,ue).call(this);let s=i(this,w).fetch(this.options,t);return t!=null&&t.throwOnError||(s=s.catch(K)),s},se=function(){v(this,x,ae).call(this);const t=St(this.options.staleTime,i(this,w));if(mt||i(this,q).isStale||!Xt(t))return;const r=_e(i(this,q).dataUpdatedAt,t)+1;u(this,pt,setTimeout(()=>{i(this,q).isStale||this.updateResult()},r))},re=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(i(this,w)):this.options.refetchInterval)??!1},ie=function(t){v(this,x,oe).call(this),u(this,at,t),!(mt||$(this.options.enabled,i(this,w))===!1||!Xt(i(this,at))||i(this,at)===0)&&u(this,yt,setInterval(()=>{(this.options.refetchIntervalInBackground||ye.isFocused())&&v(this,x,Ut).call(this)},i(this,at)))},ne=function(){v(this,x,se).call(this),v(this,x,ie).call(this,v(this,x,re).call(this))},ae=function(){i(this,pt)&&(clearTimeout(i(this,pt)),u(this,pt,void 0))},oe=function(){i(this,yt)&&(clearInterval(i(this,yt)),u(this,yt,void 0))},ue=function(){const t=i(this,U).getQueryCache().build(i(this,U),this.options);if(t===i(this,w))return;const s=i(this,w);u(this,w,t),u(this,_t,t.state),this.hasListeners()&&(s==null||s.removeObserver(this),t.addObserver(this))},Ve=function(t){D.batch(()=>{t.listeners&&this.listeners.forEach(s=>{s(i(this,q))}),i(this,U).getQueryCache().notify({query:i(this,w),type:"observerResultsUpdated"})})},Le);function Ts(e,t){return $(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function Pe(e,t){return Ts(e,t)||e.state.data!==void 0&&he(e,t,t.refetchOnMount)}function he(e,t,s){if($(t.enabled,e)!==!1){const r=typeof s=="function"?s(e):s;return r==="always"||r!==!1&&me(e,t)}return!1}function Re(e,t,s,r){return(e!==t||$(r.enabled,e)===!1)&&(!s.suspense||e.state.status!=="error")&&me(e,s)}function me(e,t){return $(t.enabled,e)!==!1&&e.isStaleByTime(St(t.staleTime,e))}function Ms(e,t){return!Wt(e.getCurrentResult(),t)}var ot,ut,k,J,X,zt,ce,Ne,As=(Ne=class extends It{constructor(t,s){super();d(this,X);d(this,ot);d(this,ut);d(this,k);d(this,J);u(this,ot,t),this.setOptions(s),this.bindMethods(),v(this,X,zt).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(t){var r;const s=this.options;this.options=i(this,ot).defaultMutationOptions(t),Wt(this.options,s)||i(this,ot).getMutationCache().notify({type:"observerOptionsUpdated",mutation:i(this,k),observer:this}),s!=null&&s.mutationKey&&this.options.mutationKey&&vt(s.mutationKey)!==vt(this.options.mutationKey)?this.reset():((r=i(this,k))==null?void 0:r.state.status)==="pending"&&i(this,k).setOptions(this.options)}onUnsubscribe(){var t;this.hasListeners()||(t=i(this,k))==null||t.removeObserver(this)}onMutationUpdate(t){v(this,X,zt).call(this),v(this,X,ce).call(this,t)}getCurrentResult(){return i(this,ut)}reset(){var t;(t=i(this,k))==null||t.removeObserver(this),u(this,k,void 0),v(this,X,zt).call(this),v(this,X,ce).call(this)}mutate(t,s){var r;return u(this,J,s),(r=i(this,k))==null||r.removeObserver(this),u(this,k,i(this,ot).getMutationCache().build(i(this,ot),this.options)),i(this,k).addObserver(this),i(this,k).execute(t)}},ot=new WeakMap,ut=new WeakMap,k=new WeakMap,J=new WeakMap,X=new WeakSet,zt=function(){var s;const t=((s=i(this,k))==null?void 0:s.state)??Ye();u(this,ut,{...t,isPending:t.status==="pending",isSuccess:t.status==="success",isError:t.status==="error",isIdle:t.status==="idle",mutate:this.mutate,reset:this.reset})},ce=function(t){D.batch(()=>{var s,r,n,a,o,h,l,b;if(i(this,J)&&this.hasListeners()){const f=i(this,ut).variables,c=i(this,ut).context;(t==null?void 0:t.type)==="success"?((r=(s=i(this,J)).onSuccess)==null||r.call(s,t.data,f,c),(a=(n=i(this,J)).onSettled)==null||a.call(n,t.data,null,f,c)):(t==null?void 0:t.type)==="error"&&((h=(o=i(this,J)).onError)==null||h.call(o,t.error,f,c),(b=(l=i(this,J)).onSettled)==null||b.call(l,void 0,t.error,f,c))}this.listeners.forEach(f=>{f(i(this,ut))})})},Ne),Je=C.createContext(void 0),ve=e=>{const t=C.useContext(Je);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Qs=({client:e,children:t})=>(C.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),y.jsx(Je.Provider,{value:e,children:t})),Xe=C.createContext(!1),Is=()=>C.useContext(Xe);Xe.Provider;function qs(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var Us=C.createContext(qs()),ks=()=>C.useContext(Us);function Ze(e,t){return typeof e=="function"?e(...t):!!e}function le(){}var Ls=(e,t)=>{(e.suspense||e.throwOnError||e.experimental_prefetchInRender)&&(t.isReset()||(e.retryOnMount=!1))},Ns=e=>{C.useEffect(()=>{e.clearReset()},[e])},_s=({result:e,errorResetBoundary:t,throwOnError:s,query:r})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&Ze(s,[e.error,r]),Ks=e=>{e.suspense&&(e.staleTime===void 0&&(e.staleTime=1e3),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3)))},Hs=(e,t)=>e.isLoading&&e.isFetching&&!t,Gs=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,Ee=(e,t,s)=>t.fetchOptimistic(e).catch(()=>{s.clearReset()});function $s(e,t,s){var f,c,g,m,E;const r=ve(),n=Is(),a=ks(),o=r.defaultQueryOptions(e);(c=(f=r.getDefaultOptions().queries)==null?void 0:f._experimental_beforeQuery)==null||c.call(f,o),o._optimisticResults=n?"isRestoring":"optimistic",Ks(o),Ls(o,a),Ns(a);const h=!r.getQueryCache().get(o.queryHash),[l]=C.useState(()=>new t(r,o)),b=l.getOptimisticResult(o);if(C.useSyncExternalStore(C.useCallback(p=>{const S=n?le:l.subscribe(D.batchCalls(p));return l.updateResult(),S},[l,n]),()=>l.getCurrentResult(),()=>l.getCurrentResult()),C.useEffect(()=>{l.setOptions(o,{listeners:!1})},[o,l]),Gs(o,b))throw Ee(o,l,a);if(_s({result:b,errorResetBoundary:a,throwOnError:o.throwOnError,query:r.getQueryCache().get(o.queryHash)}))throw b.error;if((m=(g=r.getDefaultOptions().queries)==null?void 0:g._experimental_afterQuery)==null||m.call(g,o,b),o.experimental_prefetchInRender&&!mt&&Hs(b,n)){const p=h?Ee(o,l,a):(E=r.getQueryCache().get(o.queryHash))==null?void 0:E.promise;p==null||p.catch(le).finally(()=>{l.updateResult()})}return o.notifyOnChangeProps?b:l.trackResult(b)}function Ht(e,t){return $s(e,js)}function Bs(e,t){const s=ve(),[r]=C.useState(()=>new As(s,e));C.useEffect(()=>{r.setOptions(e)},[r,e]);const n=C.useSyncExternalStore(C.useCallback(o=>r.subscribe(D.batchCalls(o)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),a=C.useCallback((o,h)=>{r.mutate(o,h).catch(le)},[r]);if(n.error&&Ze(r.options.throwOnError,[n.error]))throw n.error;return{...n,mutate:a,mutateAsync:n.mutate}}const zs=864e5,Ws=/^\d{4}-\d{2}-\d{2}$/;function Fe(e,t=Date.now()){return new Date(t-e*zs).toISOString().slice(0,10)}function Ys(e=30,t=Date.now()){return{fromDay:Fe(e-1,t),toDay:Fe(0,t)}}function Vs(e){return Ws.test(e)}function de(){return typeof window<"u"&&window.__AGENT_API__?window.__AGENT_API__:`${typeof window<"u"&&window.__AGENT_BASE__||"/ai-gateway"}/api`}async function qt(e,t){const s=await fetch(de()+e,t);if(!s.ok)throw new Error(`${s.status} ${s.statusText}`);return await s.json()}const bt={spend(e){const t=new URLSearchParams({from:e.fromDay,to:e.toDay});return qt(`/spend?${t.toString()}`)},topThreads(e,t=10){const s=new URLSearchParams({from:e.fromDay,to:e.toDay,limit:`${t}`});return qt(`/top-threads?${s.toString()}`)},toolCalls(e=50){return qt(`/tool-calls?limit=${e}`)},threads(e=50){return qt(`/threads?limit=${e}`)},pricing(){return qt("/pricing")},async upsertPrice(e){const t=await fetch(`${de()}/pricing`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(`${t.status} ${t.statusText}`)},streamEvents(e){const t=new EventSource(`${de()}/stream`);return t.onmessage=s=>{try{e(JSON.parse(s.data))}catch{}},()=>t.close()}};function Js(e){return Ht({queryKey:["spend",e.fromDay,e.toDay],queryFn:()=>bt.spend(e)})}function Xs(e,t=10){return Ht({queryKey:["top-threads",e.fromDay,e.toDay,t],queryFn:()=>bt.topThreads(e,t)})}function Zs(e=50){return Ht({queryKey:["tool-calls",e],queryFn:()=>bt.toolCalls(e)})}function tr(e=50){return Ht({queryKey:["threads",e],queryFn:()=>bt.threads(e)})}function er(){return Ht({queryKey:["pricing"],queryFn:()=>bt.pricing()})}function sr(){const e=ve();return Bs({mutationFn:t=>bt.upsertPrice(t),onSuccess:()=>{e.invalidateQueries({queryKey:["pricing"]})}})}function rr(e=200){const[t,s]=C.useState([]),[r,n]=C.useState(!1),a=C.useRef(0);return C.useEffect(()=>{n(!0);const o=bt.streamEvents(h=>{a.current+=1,s(l=>ts(l,h,a.current,e))});return()=>{n(!1),o()}},[e]),{events:t,connected:r}}const ir=[{key:"spend",label:"Spend & usage",icon:y.jsx(ss,{})},{key:"models",label:"Models",icon:y.jsx(rs,{})},{key:"actors",label:"Actors & budgets",icon:y.jsx(is,{})},{key:"runs",label:"Runs & tools",icon:y.jsx(ns,{})},{key:"pricing",label:"Pricing",icon:y.jsx(as,{})},{key:"live",label:"Live",icon:y.jsx(os,{})}],nr={byModel:[],byActor:[],trend:[]},ar=[],or=[],ur=[],hr=[],cr="501";function lr(){const[e,t]=C.useState(Ys()),[s,r]=C.useState("spend"),n=Js(e),a=Xs(e),o=Zs(),h=tr(),l=er(),b=sr(),f=rr(),c=n.data??nr,g=l.isError&&l.error instanceof Error?l.error.message.startsWith(cr):!1;return y.jsxs("div",{className:"relative min-h-full",children:[y.jsx("div",{className:"app-bg"}),y.jsxs("div",{className:"relative z-10 mx-auto max-w-[1180px] px-5 py-5",children:[y.jsx(fr,{range:e,onRange:t,connected:f.connected,liveCount:f.events.length}),y.jsx("nav",{className:"mb-5 flex flex-wrap gap-1",children:ir.map(m=>y.jsxs("button",{type:"button",onClick:()=>r(m.key),className:`flex items-center gap-2 rounded-lg border px-3 py-1.5 text-xs transition-colors ${s===m.key?"border-[var(--accent)]/50 bg-[var(--accent)]/10 text-[var(--text)]":"border-transparent text-[var(--muted)] hover:text-[var(--text)]"}`,children:[m.icon,m.label,m.key==="live"&&f.events.length>0&&y.jsx("span",{className:"mono tnum rounded bg-[var(--accent)]/20 px-1 text-[10px] text-[var(--accent)]",children:f.events.length})]},m.key))}),y.jsx(dr,{section:s,overview:c,topThreads:a.data??ur,loadingSpend:n.isLoading,errorSpend:n.isError,toolCalls:o.data??ar,threads:h.data??or,liveEvents:f.events,connected:f.connected,prices:l.data??hr,loadingPrices:l.isLoading,pricingUnavailable:g,onUpsertPrice:m=>b.mutateAsync(m),savingPrice:b.isPending})]})]})}function dr({section:e,overview:t,topThreads:s,loadingSpend:r,errorSpend:n,toolCalls:a,threads:o,liveEvents:h,connected:l,prices:b,loadingPrices:f,pricingUnavailable:c,onUpsertPrice:g,savingPrice:m}){if(n&&(e==="spend"||e==="models"||e==="actors"))return y.jsx("div",{className:"panel p-6 text-sm text-[var(--bad)]",children:"Failed to load the read-model. Is the governance read-model bound and the API reachable?"});if(r&&(e==="spend"||e==="models"||e==="actors"))return y.jsx("div",{className:"panel animate-pulse p-6 text-sm text-[var(--muted)]",children:"Loading…"});switch(e){case"spend":return y.jsx(fs,{overview:t,topThreads:s});case"models":return y.jsx(ds,{rows:t.byModel});case"actors":return y.jsx(ls,{rows:t.byActor});case"runs":return y.jsx(cs,{toolCalls:a,threads:o});case"pricing":return y.jsx(hs,{prices:b,loading:f,unavailable:c,onUpsert:g,saving:m});case"live":return y.jsx(us,{events:h,connected:l});default:return null}}function fr({range:e,onRange:t,connected:s,liveCount:r}){return y.jsxs("header",{className:"mb-5 flex flex-wrap items-center gap-4",children:[y.jsxs("div",{className:"flex items-center gap-2.5",children:[y.jsx("div",{className:"grid h-8 w-8 place-items-center rounded-lg border border-[var(--accent)]/40 bg-[var(--accent)]/10",children:y.jsx(es,{className:"h-4 w-4 text-[var(--accent)]"})}),y.jsxs("div",{className:"leading-none",children:[y.jsx("div",{className:"text-sm font-semibold tracking-tight",children:"AI gateway"}),y.jsx("div",{className:"mono text-[10px] uppercase tracking-[0.2em] text-[var(--muted)]",children:"governance console"})]})]}),y.jsxs("div",{className:"ml-auto flex flex-wrap items-center gap-2",children:[y.jsx(De,{label:"From",value:e.fromDay,onChange:n=>t({...e,fromDay:n})}),y.jsx(De,{label:"To",value:e.toDay,onChange:n=>t({...e,toDay:n})}),y.jsxs("span",{className:"flex items-center gap-1.5 rounded-lg border border-[var(--line)] px-2.5 py-1.5 text-[11px] text-[var(--muted)]",children:[y.jsx("span",{className:`dot ${s?"s-ok pulse":"s-failed"}`,"aria-hidden":!0}),"live ",r>0?`· ${r}`:""]})]})]})}function De({label:e,value:t,onChange:s}){return y.jsxs("label",{className:"flex items-center gap-1.5 rounded-lg border border-[var(--line)] bg-[var(--panel)] px-2.5 py-1 text-[11px] text-[var(--muted)]",children:[y.jsx("span",{className:"uppercase tracking-wider",children:e}),y.jsx("input",{type:"date",value:t,onChange:r=>{const n=r.target.value;Vs(n)&&s(n)},className:"mono bg-transparent text-[var(--text)] outline-none"})]})}const pr=new Ds({defaultOptions:{queries:{refetchInterval:5e3,refetchOnWindowFocus:!1,retry:1}}}),je=document.getElementById("root");je&&ps.createRoot(je).render(y.jsx(C.StrictMode,{children:y.jsx(Qs,{client:pr,children:y.jsx(lr,{})})}));
|