@carlonicora/nextjs-jsonapi 3.16.0 → 3.17.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.
Files changed (29) hide show
  1. package/dist/{BlockNoteEditor-SGISBQD5.mjs → BlockNoteEditor-6DYL5NZD.mjs} +2 -2
  2. package/dist/{BlockNoteEditor-S43PQJEC.js → BlockNoteEditor-DGPIAJI4.js} +9 -9
  3. package/dist/{BlockNoteEditor-S43PQJEC.js.map → BlockNoteEditor-DGPIAJI4.js.map} +1 -1
  4. package/dist/billing/index.js +335 -335
  5. package/dist/billing/index.mjs +1 -1
  6. package/dist/{chunk-AOWHVECO.js → chunk-5EV234WK.js} +17 -25
  7. package/dist/chunk-5EV234WK.js.map +1 -0
  8. package/dist/{chunk-47CLHN2G.mjs → chunk-MHR553J3.mjs} +17 -25
  9. package/dist/{chunk-47CLHN2G.mjs.map → chunk-MHR553J3.mjs.map} +1 -1
  10. package/dist/client/index.js +2 -2
  11. package/dist/client/index.mjs +1 -1
  12. package/dist/components/index.d.mts +3 -2
  13. package/dist/components/index.d.ts +3 -2
  14. package/dist/components/index.js +2 -2
  15. package/dist/components/index.mjs +1 -1
  16. package/dist/contexts/index.js +2 -2
  17. package/dist/contexts/index.mjs +1 -1
  18. package/dist/features/help/index.js +31 -31
  19. package/dist/features/help/index.mjs +1 -1
  20. package/dist/features/tokenusage/index.js +75 -75
  21. package/dist/features/tokenusage/index.mjs +1 -1
  22. package/package.json +1 -1
  23. package/src/features/assistant/components/parts/AssistantThread.tsx +6 -3
  24. package/src/features/assistant/components/parts/__tests__/AssistantThread.spec.tsx +36 -5
  25. package/src/features/assistant-message/components/MessageList.tsx +14 -10
  26. package/src/features/notification/components/modals/NotificationModal.tsx +8 -16
  27. package/src/features/notification/components/modals/__tests__/NotificationModal.spec.tsx +156 -0
  28. package/dist/chunk-AOWHVECO.js.map +0 -1
  29. /package/dist/{BlockNoteEditor-SGISBQD5.mjs.map → BlockNoteEditor-6DYL5NZD.mjs.map} +0 -0
@@ -26,7 +26,7 @@
26
26
 
27
27
 
28
28
 
29
- var _chunkAOWHVECOjs = require('../../chunk-AOWHVECO.js');
29
+ var _chunk5EV234WKjs = require('../../chunk-5EV234WK.js');
30
30
  require('../../chunk-ODH2LYWC.js');
31
31
 
32
32
 
@@ -70,7 +70,7 @@ function TokenUsageAdminFilterBar({ granularity, companyId, metric, companies, o
70
70
  };
71
71
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2", children: [
72
72
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
73
- _chunkAOWHVECOjs.DateRangeSelector,
73
+ _chunk5EV234WKjs.DateRangeSelector,
74
74
  {
75
75
  onDateChange: (range) => {
76
76
  if (!_optionalChain([range, 'optionalAccess', _ => _.from]) || !_optionalChain([range, 'optionalAccess', _2 => _2.to])) return;
@@ -105,16 +105,16 @@ function TokenUsageAdminFilterBar({ granularity, companyId, metric, companies, o
105
105
  }
106
106
  ),
107
107
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
108
- _chunkAOWHVECOjs.Select,
108
+ _chunk5EV234WKjs.Select,
109
109
  {
110
110
  items: companyItems,
111
111
  value: _nullishCoalesce(companyId, () => ( ALL_COMPANIES)),
112
112
  onValueChange: (value) => onChange({ companyId: !value || value === ALL_COMPANIES ? void 0 : value }),
113
113
  children: [
114
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectTrigger, { className: "w-56", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectValue, { placeholder: t("token_usage.admin.all_companies") }) }),
115
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.SelectContent, { children: [
116
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectItem, { value: ALL_COMPANIES, children: t("token_usage.admin.all_companies") }),
117
- companies.map((company) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectItem, { value: company.id, children: company.label }, company.id))
114
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectTrigger, { className: "w-56", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectValue, { placeholder: t("token_usage.admin.all_companies") }) }),
115
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.SelectContent, { children: [
116
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectItem, { value: ALL_COMPANIES, children: t("token_usage.admin.all_companies") }),
117
+ companies.map((company) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectItem, { value: company.id, children: company.label }, company.id))
118
118
  ] })
119
119
  ]
120
120
  }
@@ -137,7 +137,7 @@ function Segmented({
137
137
  children: options.map((option) => {
138
138
  const selected = option.value === value;
139
139
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
140
- _chunkAOWHVECOjs.Button,
140
+ _chunk5EV234WKjs.Button,
141
141
  {
142
142
  type: "button",
143
143
  size: "sm",
@@ -219,7 +219,7 @@ var TokenUsageAdminProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void
219
219
  pageUrl = TOKEN_USAGE_ADMIN_PAGE_URL
220
220
  }) => {
221
221
  const t = _nextintl.useTranslations.call(void 0, );
222
- const generateUrl = _chunkAOWHVECOjs.usePageUrlGenerator.call(void 0, );
222
+ const generateUrl = _chunk5EV234WKjs.usePageUrlGenerator.call(void 0, );
223
223
  const [filters, setFilterState] = _react.useState.call(void 0, () => {
224
224
  const range = defaultRange();
225
225
  return {
@@ -337,7 +337,7 @@ var TokenUsageAdminProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void
337
337
  error
338
338
  ]
339
339
  );
340
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageAdminContext.Provider, { value: contextValue, children }) });
340
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageAdminContext.Provider, { value: contextValue, children }) });
341
341
  }, "TokenUsageAdminProvider");
342
342
  var useTokenUsageAdmin = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => {
343
343
  const ctx = _react.useContext.call(void 0, TokenUsageAdminContext);
@@ -497,7 +497,7 @@ function LeadTile({
497
497
  previousLabel,
498
498
  decimal
499
499
  }) {
500
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": testId, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
500
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": testId, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
501
501
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: label }),
502
502
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-primary text-xl font-semibold tabular-nums", children: value }),
503
503
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1", children: [
@@ -514,7 +514,7 @@ function SupportingTile({
514
514
  delta,
515
515
  decimal
516
516
  }) {
517
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": testId, size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
517
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": testId, size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
518
518
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: label }),
519
519
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-2", children: [
520
520
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-medium tabular-nums", children: value }),
@@ -611,8 +611,8 @@ function TokenUsageBreakdownTable({ rows, metric }) {
611
611
  // The package's <Table> wraps itself in an `overflow-x-clip` container, which
612
612
  // would swallow the overflow before this scroller ever saw it — hence the
613
613
  // child override. Wide metric tables must scroll, never widen the page.
614
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Table, { children: [
615
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableRow, { children: columns.map((column) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableHead, { className: _chunkTBSMAL5Yjs.cn.call(void 0, column.numeric && "text-end"), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
614
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Table, { children: [
615
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableRow, { children: columns.map((column) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableHead, { className: _chunkTBSMAL5Yjs.cn.call(void 0, column.numeric && "text-end"), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
616
616
  "button",
617
617
  {
618
618
  type: "button",
@@ -627,20 +627,20 @@ function TokenUsageBreakdownTable({ rows, metric }) {
627
627
  ]
628
628
  }
629
629
  ) }, column.key)) }) }),
630
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableBody, { children: sortedRows.map((row) => {
630
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableBody, { children: sortedRows.map((row) => {
631
631
  const value = metricValue(row, metric);
632
632
  const share = total > 0 ? value / total * 100 : 0;
633
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.TableRow, { "data-testid": `breakdown-row-${row.id}`, children: [
634
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-xs", children: row.id === "other" ? t("token_usage.admin.other") : row.label }),
635
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-muted-foreground text-xs", children: _nullishCoalesce(row.sublabel, () => ( "")) }),
636
- showActiveUsers && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: row.activeUsers === void 0 ? "" : decimal(row.activeUsers, 0) }),
637
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.calls, 0) }),
638
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.tokensIn, 0) }),
639
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.tokensOut, 0) }),
640
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: percent(cacheHitPercentage(row.cached, row.tokensIn)) }),
641
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: formatValue(row.cost, "cost") }),
642
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: formatValue(row.credits, "credits") }),
643
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.TableCell, { className: "text-end text-xs tabular-nums", children: percent(share) })
633
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.TableRow, { "data-testid": `breakdown-row-${row.id}`, children: [
634
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-xs", children: row.id === "other" ? t("token_usage.admin.other") : row.label }),
635
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-muted-foreground text-xs", children: _nullishCoalesce(row.sublabel, () => ( "")) }),
636
+ showActiveUsers && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: row.activeUsers === void 0 ? "" : decimal(row.activeUsers, 0) }),
637
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.calls, 0) }),
638
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.tokensIn, 0) }),
639
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.tokensOut, 0) }),
640
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: percent(cacheHitPercentage(row.cached, row.tokensIn)) }),
641
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: formatValue(row.cost, "cost") }),
642
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: formatValue(row.credits, "credits") }),
643
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.TableCell, { className: "text-end text-xs tabular-nums", children: percent(share) })
644
644
  ] }, row.id);
645
645
  }) })
646
646
  ] }) })
@@ -838,7 +838,7 @@ function TokenUsageTimelineChart({ rows, metric, stackBy, className }) {
838
838
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className, dir: "ltr", children: [
839
839
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", "data-testid": "timeline-data", children: JSON.stringify(chartData) }),
840
840
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", "data-testid": "timeline-series", children: JSON.stringify(seriesKeys) }),
841
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.ChartContainer, { config: chartConfig, className: "aspect-auto h-72 w-full", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _recharts.BarChart, { accessibilityLayer: true, data: chartData, margin: { top: 8, right: 8, bottom: 0, left: 0 }, children: [
841
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.ChartContainer, { config: chartConfig, className: "aspect-auto h-72 w-full", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _recharts.BarChart, { accessibilityLayer: true, data: chartData, margin: { top: 8, right: 8, bottom: 0, left: 0 }, children: [
842
842
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _recharts.CartesianGrid, { vertical: false }),
843
843
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
844
844
  _recharts.XAxis,
@@ -862,10 +862,10 @@ function TokenUsageTimelineChart({ rows, metric, stackBy, className }) {
862
862
  }
863
863
  ),
864
864
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
865
- _chunkAOWHVECOjs.ChartTooltip,
865
+ _chunk5EV234WKjs.ChartTooltip,
866
866
  {
867
867
  content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
868
- _chunkAOWHVECOjs.ChartTooltipContent,
868
+ _chunk5EV234WKjs.ChartTooltipContent,
869
869
  {
870
870
  labelFormatter: (value) => bucketDate(String(value), granularity),
871
871
  valueFormatter: (value) => formatValue(Number(value), metric),
@@ -874,7 +874,7 @@ function TokenUsageTimelineChart({ rows, metric, stackBy, className }) {
874
874
  )
875
875
  }
876
876
  ),
877
- seriesKeys.length >= 2 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.ChartLegend, { content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.ChartLegendContent, {}) }) : null,
877
+ seriesKeys.length >= 2 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.ChartLegend, { content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.ChartLegendContent, {}) }) : null,
878
878
  seriesKeys.map((series, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
879
879
  _recharts.Bar,
880
880
  {
@@ -926,19 +926,19 @@ function TokenUsageAdminContainer() {
926
926
  [t]
927
927
  );
928
928
  if (error) {
929
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
929
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
930
930
  }
931
- if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
931
+ if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
932
932
  const emptyLabel = t("token_usage.admin.no_data");
933
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
933
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
934
934
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageAdminTiles, { summary, metric: filters.metric, singleCustomerMode: hidePlatform }),
935
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
936
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: [
937
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.usage_over_time") }),
938
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardAction, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
935
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
936
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardHeader, { children: [
937
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.usage_over_time") }),
938
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardAction, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
939
939
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: t("token_usage.admin.stack_by") }),
940
940
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
941
- _chunkAOWHVECOjs.Select,
941
+ _chunk5EV234WKjs.Select,
942
942
  {
943
943
  items: stackByItems,
944
944
  value: filters.stackBy,
@@ -946,29 +946,29 @@ function TokenUsageAdminContainer() {
946
946
  if (value) setFilters({ stackBy: value });
947
947
  },
948
948
  children: [
949
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectTrigger, { size: "sm", className: "w-36", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectValue, {}) }),
950
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectContent, { children: STACK_BY_VALUES.map((value) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SelectItem, { value, children: stackByItems[value] }, value)) })
949
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectTrigger, { size: "sm", className: "w-36", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectValue, {}) }),
950
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectContent, { children: STACK_BY_VALUES.map((value) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SelectItem, { value, children: stackByItems[value] }, value)) })
951
951
  ]
952
952
  }
953
953
  )
954
954
  ] }) })
955
955
  ] }),
956
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageTimelineChart, { rows: timeline, metric: filters.metric, stackBy: filters.stackBy }) })
956
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageTimelineChart, { rows: timeline, metric: filters.metric, stackBy: filters.stackBy }) })
957
957
  ] }),
958
958
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-4 md:grid-cols-2", children: [
959
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
960
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.by_company") }) }),
961
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byCompany, metric: filters.metric, emptyLabel }) })
959
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.by_company") }) }),
961
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byCompany, metric: filters.metric, emptyLabel }) })
962
962
  ] }),
963
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
964
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.by_user") }) }),
965
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byUser, metric: filters.metric, emptyLabel }) })
963
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
964
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.by_user") }) }),
965
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byUser, metric: filters.metric, emptyLabel }) })
966
966
  ] })
967
967
  ] }),
968
968
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkTBSMAL5Yjs.cn.call(void 0, "grid gap-4", !hidePlatform && "md:grid-cols-2"), children: [
969
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
970
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.customer_by_operation") }) }),
971
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
969
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
970
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.customer_by_operation") }) }),
971
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
972
972
  TokenUsageRankedBar,
973
973
  {
974
974
  rows: byCustomerOperation,
@@ -978,9 +978,9 @@ function TokenUsageAdminContainer() {
978
978
  }
979
979
  ) })
980
980
  ] }),
981
- !hidePlatform && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
982
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.platform_by_operation") }) }),
983
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
981
+ !hidePlatform && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
982
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.platform_by_operation") }) }),
983
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
984
984
  TokenUsageRankedBar,
985
985
  {
986
986
  rows: byOperation,
@@ -991,9 +991,9 @@ function TokenUsageAdminContainer() {
991
991
  ) })
992
992
  ] })
993
993
  ] }),
994
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
995
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.admin.detail") }) }),
996
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageBreakdownTable, { rows: byCompany, metric: filters.metric }) })
994
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
995
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.admin.detail") }) }),
996
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageBreakdownTable, { rows: byCompany, metric: filters.metric }) })
997
997
  ] })
998
998
  ] }) });
999
999
  }
@@ -1114,7 +1114,7 @@ var TOKEN_USAGE_REPORT_I18N_KEYS = [
1114
1114
 
1115
1115
  function TokenUsageReportFilterBar({ onChange }) {
1116
1116
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { "data-help": "tokenusage.filters", className: "flex flex-wrap items-center gap-2", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1117
- _chunkAOWHVECOjs.DateRangeSelector,
1117
+ _chunk5EV234WKjs.DateRangeSelector,
1118
1118
  {
1119
1119
  onDateChange: (range) => {
1120
1120
  if (!_optionalChain([range, 'optionalAccess', _10 => _10.from]) || !_optionalChain([range, 'optionalAccess', _11 => _11.to])) return;
@@ -1147,7 +1147,7 @@ var TokenUsageReportProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void
1147
1147
  pageUrl = TOKEN_USAGE_REPORT_PAGE_URL
1148
1148
  }) => {
1149
1149
  const t = _nextintl.useTranslations.call(void 0, );
1150
- const generateUrl = _chunkAOWHVECOjs.usePageUrlGenerator.call(void 0, );
1150
+ const generateUrl = _chunk5EV234WKjs.usePageUrlGenerator.call(void 0, );
1151
1151
  const [filters, setFilterState] = _react.useState.call(void 0, () => {
1152
1152
  const range = defaultRange2();
1153
1153
  return { from: _nullishCoalesce(initialFrom, () => ( range.from)), to: _nullishCoalesce(initialTo, () => ( range.to)) };
@@ -1211,7 +1211,7 @@ var TokenUsageReportProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void
1211
1211
  () => ({ summary, timeline, byOperation, byTarget, targetPanelTitleKey, filters, setFilters, isLoading, error }),
1212
1212
  [summary, timeline, byOperation, byTarget, targetPanelTitleKey, filters, setFilters, isLoading, error]
1213
1213
  );
1214
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageReportContext.Provider, { value: contextValue, children }) });
1214
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageReportContext.Provider, { value: contextValue, children }) });
1215
1215
  }, "TokenUsageReportProvider");
1216
1216
  var useTokenUsageReport = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => {
1217
1217
  const ctx = _react.useContext.call(void 0, TokenUsageReportContext);
@@ -1239,7 +1239,7 @@ function TokenUsageReportTiles({ summary, metric, balances }) {
1239
1239
  const monthlyColor = monthlyPercentage > 75 ? "text-success" : monthlyPercentage >= 5 ? "text-warning" : "text-destructive";
1240
1240
  const whole = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (value) => decimal(Math.max(0, Math.floor(value)), 0), "whole");
1241
1241
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3", children: [
1242
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": "tile-used", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
1242
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": "tile-used", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
1243
1243
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: t("token_usage.report.used_in_period") }),
1244
1244
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-primary text-xl font-semibold tabular-nums", children: formatValue(metricValue(current, metric), metric) }),
1245
1245
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1", children: [
@@ -1255,7 +1255,7 @@ function TokenUsageReportTiles({ summary, metric, balances }) {
1255
1255
  ] })
1256
1256
  ] }) }),
1257
1257
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3 sm:grid-cols-3", children: [
1258
- balances && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": "tile-monthly", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
1258
+ balances && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": "tile-monthly", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
1259
1259
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: t("token_usage.report.monthly_left") }),
1260
1260
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-baseline gap-1", children: [
1261
1261
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { "data-testid": "tile-monthly-value", className: _chunkTBSMAL5Yjs.cn.call(void 0, "text-sm font-medium tabular-nums", monthlyColor), children: whole(balances.availableMonthlyCredits) }),
@@ -1265,11 +1265,11 @@ function TokenUsageReportTiles({ summary, metric, balances }) {
1265
1265
  ] })
1266
1266
  ] })
1267
1267
  ] }) }),
1268
- balances && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": "tile-extra", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
1268
+ balances && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": "tile-extra", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
1269
1269
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: t("token_usage.report.extra_credits") }),
1270
1270
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-medium tabular-nums", children: whole(balances.availableExtraCredits) })
1271
1271
  ] }) }),
1272
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { "data-testid": "tile-calls", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.CardContent, { className: "grid gap-1", children: [
1272
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { "data-testid": "tile-calls", size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.CardContent, { className: "grid gap-1", children: [
1273
1273
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: t("token_usage.report.calls") }),
1274
1274
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-medium tabular-nums", children: decimal(current.calls, 0) })
1275
1275
  ] }) })
@@ -1311,21 +1311,21 @@ function TokenUsageReportContainer({ balances = null }) {
1311
1311
  const t = _nextintl.useTranslations.call(void 0, );
1312
1312
  const { summary, timeline, byOperation, byTarget, isLoading, error, targetPanelTitleKey } = useTokenUsageReport();
1313
1313
  if (error) {
1314
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
1314
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
1315
1315
  }
1316
- if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
1316
+ if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
1317
1317
  const emptyLabel = t("token_usage.report.no_data");
1318
1318
  const targetTitle = targetPanelTitleKey && byTarget.length > 0 ? t(targetPanelTitleKey) : void 0;
1319
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
1319
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
1320
1320
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageReportTiles, { summary, metric: "credits", balances }),
1321
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
1322
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.report.usage_over_time") }) }),
1323
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageTimelineChart, { rows: timeline, metric: "credits", stackBy: "type" }) })
1321
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
1322
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.report.usage_over_time") }) }),
1323
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageTimelineChart, { rows: timeline, metric: "credits", stackBy: "type" }) })
1324
1324
  ] }),
1325
1325
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkTBSMAL5Yjs.cn.call(void 0, "grid gap-4", targetTitle && "md:grid-cols-2"), children: [
1326
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
1327
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: t("token_usage.report.by_operation") }) }),
1328
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1326
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
1327
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: t("token_usage.report.by_operation") }) }),
1328
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1329
1329
  TokenUsageRankedBar,
1330
1330
  {
1331
1331
  rows: byOperation,
@@ -1335,9 +1335,9 @@ function TokenUsageReportContainer({ balances = null }) {
1335
1335
  }
1336
1336
  ) })
1337
1337
  ] }),
1338
- targetTitle && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAOWHVECOjs.Card, { children: [
1339
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardTitle, { children: targetTitle }) }),
1340
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOWHVECOjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byTarget, metric: "credits", emptyLabel }) })
1338
+ targetTitle && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk5EV234WKjs.Card, { children: [
1339
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardTitle, { children: targetTitle }) }),
1340
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5EV234WKjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TokenUsageRankedBar, { rows: byTarget, metric: "credits", emptyLabel }) })
1341
1341
  ] })
1342
1342
  ] })
1343
1343
  ] }) });
@@ -26,7 +26,7 @@ import {
26
26
  TableHeader,
27
27
  TableRow,
28
28
  usePageUrlGenerator
29
- } from "../../chunk-47CLHN2G.mjs";
29
+ } from "../../chunk-MHR553J3.mjs";
30
30
  import "../../chunk-IALPADOD.mjs";
31
31
  import {
32
32
  AbstractService,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nextjs-jsonapi",
3
- "version": "3.16.0",
3
+ "version": "3.17.0",
4
4
  "description": "Next.js JSON:API client with server/client support and caching",
5
5
  "author": "Carlo Nicora",
6
6
  "license": "GPL-3.0-or-later",
@@ -27,10 +27,13 @@ export function AssistantThread({
27
27
  renderApprovalAction,
28
28
  renderMention,
29
29
  }: Props) {
30
- const endRef = useRef<HTMLDivElement>(null);
30
+ const lastMessageRef = useRef<HTMLDivElement>(null);
31
31
 
32
+ // `block: "start"` on purpose: the reader should land on the FIRST line of the
33
+ // newest message, not at the end of the thread. Scrolling to the bottom would
34
+ // drop them at the last line of a long answer and force them to scroll back up.
32
35
  useEffect(() => {
33
- endRef.current?.scrollIntoView({ behavior: "smooth" });
36
+ lastMessageRef.current?.scrollIntoView({ block: "start", behavior: "smooth" });
34
37
  }, [messages.length, sending]);
35
38
 
36
39
  return (
@@ -42,9 +45,9 @@ export function AssistantThread({
42
45
  onRetry={onRetry}
43
46
  renderApprovalAction={renderApprovalAction}
44
47
  renderMention={renderMention}
48
+ lastMessageRef={lastMessageRef}
45
49
  />
46
50
  {sending && <AssistantStatusLine status={status} />}
47
- <div ref={endRef} />
48
51
  </div>
49
52
  );
50
53
  }
@@ -1,22 +1,38 @@
1
- import { describe, it, expect, vi, beforeAll } from "vitest";
1
+ import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
2
2
  import { render, screen } from "@testing-library/react";
3
3
  import type { ApiDataInterface } from "../../../../../core";
4
4
  import type { AssistantMessageInterface } from "../../../../assistant-message/data/AssistantMessageInterface";
5
5
  import { AssistantThread } from "../AssistantThread";
6
6
 
7
+ // jsdom lacks scrollIntoView. Spy on it AND record the element it was called
8
+ // on, so the auto-scroll target can be asserted, not just the options.
9
+ const scrollTargets: Element[] = [];
10
+ const scrollIntoView = vi.fn(function (this: Element) {
11
+ scrollTargets.push(this);
12
+ });
13
+
7
14
  beforeAll(() => {
8
- // jsdom lacks scrollIntoView
9
- Element.prototype.scrollIntoView = vi.fn();
15
+ Element.prototype.scrollIntoView = scrollIntoView;
16
+ });
17
+
18
+ beforeEach(() => {
19
+ scrollIntoView.mockClear();
20
+ scrollTargets.length = 0;
10
21
  });
11
22
 
12
- function buildMessageStub(p: { role: "user" | "assistant"; content?: string }): AssistantMessageInterface {
23
+ function buildMessageStub(p: {
24
+ role: "user" | "assistant";
25
+ content?: string;
26
+ position?: number;
27
+ }): AssistantMessageInterface {
13
28
  return {
14
29
  id: Math.random().toString(36).slice(2),
15
30
  type: "assistant-messages",
16
31
  role: p.role,
17
32
  content: p.content ?? "",
18
- position: 0,
33
+ position: p.position ?? 0,
19
34
  references: [] as ApiDataInterface[],
35
+ citations: [],
20
36
  suggestedQuestions: [] as string[],
21
37
  createdAt: new Date(),
22
38
  updatedAt: new Date(),
@@ -36,4 +52,19 @@ describe("AssistantThread", () => {
36
52
  // When not sending, AssistantStatusLine should not render → the default "thinking" key should be absent
37
53
  expect(screen.queryByText("features.assistant.thinking")).not.toBeInTheDocument();
38
54
  });
55
+
56
+ it("scrolls the newest message to the TOP of the viewport, not the thread bottom", () => {
57
+ const msgs = [
58
+ buildMessageStub({ role: "user", content: "older question", position: 0 }),
59
+ buildMessageStub({ role: "assistant", content: "newest answer", position: 1 }),
60
+ ];
61
+ render(<AssistantThread messages={msgs} sending={false} onSelectFollowUp={vi.fn()} />);
62
+
63
+ expect(scrollIntoView).toHaveBeenCalledWith({ block: "start", behavior: "smooth" });
64
+
65
+ // …and it must be the LAST message element that scrolled, not a trailing spacer
66
+ expect(scrollTargets).toHaveLength(1);
67
+ expect(scrollTargets[0].textContent).toContain("newest answer");
68
+ expect(scrollTargets[0].textContent).not.toContain("older question");
69
+ });
39
70
  });
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import type { RefObject } from "react";
3
4
  import { AssistantMessageInterface } from "../data/AssistantMessageInterface";
4
5
  import { MessageItem, type ApprovalActionRenderer, type MentionRenderer } from "./MessageItem";
5
6
 
@@ -10,6 +11,7 @@ interface Props {
10
11
  onRetry?: (tempId: string) => void;
11
12
  renderApprovalAction?: ApprovalActionRenderer;
12
13
  renderMention?: MentionRenderer;
14
+ lastMessageRef?: RefObject<HTMLDivElement | null>;
13
15
  }
14
16
 
15
17
  export function MessageList({
@@ -19,6 +21,7 @@ export function MessageList({
19
21
  onRetry,
20
22
  renderApprovalAction,
21
23
  renderMention,
24
+ lastMessageRef,
22
25
  }: Props) {
23
26
  const ordered = [...messages].sort((a, b) => a.position - b.position);
24
27
 
@@ -33,16 +36,17 @@ export function MessageList({
33
36
  return (
34
37
  <div className="flex min-w-0 flex-col gap-y-3">
35
38
  {ordered.map((m, i) => (
36
- <MessageItem
37
- key={m.id}
38
- message={m}
39
- isLatestAssistant={i === lastAssistantIndex}
40
- onSelectFollowUp={onSelectFollowUp}
41
- failedMessageIds={failedMessageIds}
42
- onRetry={onRetry}
43
- renderApprovalAction={renderApprovalAction}
44
- renderMention={renderMention}
45
- />
39
+ <div key={m.id} ref={i === ordered.length - 1 ? lastMessageRef : undefined} className="flex min-w-0 flex-col">
40
+ <MessageItem
41
+ message={m}
42
+ isLatestAssistant={i === lastAssistantIndex}
43
+ onSelectFollowUp={onSelectFollowUp}
44
+ failedMessageIds={failedMessageIds}
45
+ onRetry={onRetry}
46
+ renderApprovalAction={renderApprovalAction}
47
+ renderMention={renderMention}
48
+ />
49
+ </div>
46
50
  ))}
47
51
  </div>
48
52
  );
@@ -89,8 +89,6 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
89
89
  // The initial load is owned by NotificationContextProvider's mount effect.
90
90
  // The bell still refreshes on open when the cache is stale (see handleOpenChange).
91
91
 
92
- const processSocketNotificationsRef = useRef<NodeJS.Timeout | null>(null);
93
-
94
92
  const processSocketNotifications = useCallback(() => {
95
93
  if (socketNotifications.length === 0) {
96
94
  return;
@@ -120,6 +118,9 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
120
118
  showToast(toastNotification.title, {
121
119
  description: toastNotification.description,
122
120
  action: toastNotification.action,
121
+ // A toast that offers something to press stays until dismissed; a
122
+ // plain notice keeps sonner's default timeout.
123
+ duration: toastNotification.action ? Infinity : undefined,
123
124
  });
124
125
  });
125
126
 
@@ -139,21 +140,12 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
139
140
  checkCircuitBreaker,
140
141
  ]);
141
142
 
142
- // 🔗 SOCKET: Throttled processing with 300ms delay
143
+ // Drain the socket queue in the same commit it arrives in. `useNotificationSync`
144
+ // (mounted higher in the tree) drains the same queue without toasting; child
145
+ // effects run first, so the modal wins only if it does not defer. A deferred
146
+ // drain always found the queue already emptied and no toast ever showed.
143
147
  useEffect(() => {
144
- if (processSocketNotificationsRef.current) {
145
- clearTimeout(processSocketNotificationsRef.current);
146
- }
147
-
148
- processSocketNotificationsRef.current = setTimeout(() => {
149
- processSocketNotifications();
150
- }, 300); // 300ms throttle
151
-
152
- return () => {
153
- if (processSocketNotificationsRef.current) {
154
- clearTimeout(processSocketNotificationsRef.current);
155
- }
156
- };
148
+ processSocketNotifications();
157
149
  }, [processSocketNotifications]);
158
150
 
159
151
  const handleOpenChange = (newlyRequestedOpenState: boolean) => {