@cat-factory/app 0.286.5 → 0.287.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.
@@ -5,6 +5,7 @@ import { lastCompleteRollupDay } from '@cat-factory/contracts'
5
5
  import type {
6
6
  ReportActivityDimension,
7
7
  ReportActivityRow,
8
+ ReportSpendDimension,
8
9
  ReportSpendRow,
9
10
  ReportWindow,
10
11
  } from '~/types/execution'
@@ -56,12 +57,14 @@ const WINDOWS: { value: ReportWindow; label: string }[] = [
56
57
  { value: '90d', label: t('reports.window.ninetyDays') },
57
58
  ]
58
59
 
59
- // The dimension the paired spend + activity breakdowns are grouped by. Model and agent
60
- // kind have no activity counterpart (a run carries no single kind), so they render
61
- // unconditionally above rather than joining this switch.
60
+ // The dimension the paired spend + activity breakdowns are grouped by. Model and agent kind
61
+ // have no activity counterpart (a run carries no single kind), and neither do ticket and run
62
+ // (a ticket counts no runs of its own, and a run IS the unit), so those four render as
63
+ // spend-only cards rather than joining this switch.
62
64
  const DIMENSIONS: { value: ReportActivityDimension; label: string }[] = [
63
65
  { value: 'workspace', label: t('reports.dimension.workspace') },
64
66
  { value: 'service', label: t('reports.dimension.service') },
67
+ { value: 'repo', label: t('reports.dimension.repo') },
65
68
  { value: 'taskType', label: t('reports.dimension.taskType') },
66
69
  ]
67
70
  const dimension = ref<ReportActivityDimension>('workspace')
@@ -80,6 +83,7 @@ const spendByDimension = computed<ReportSpendRow[]>(() => {
80
83
  if (!spend) return []
81
84
  if (dimension.value === 'workspace') return spend.byWorkspace
82
85
  if (dimension.value === 'service') return spend.byService
86
+ if (dimension.value === 'repo') return spend.byRepo
83
87
  return spend.byTaskType
84
88
  })
85
89
  const activityByDimension = computed<ReportActivityRow[]>(() => {
@@ -87,9 +91,19 @@ const activityByDimension = computed<ReportActivityRow[]>(() => {
87
91
  if (!activity) return []
88
92
  if (dimension.value === 'workspace') return activity.byWorkspace
89
93
  if (dimension.value === 'service') return activity.byService
94
+ if (dimension.value === 'repo') return activity.byRepo
90
95
  return activity.byTaskType
91
96
  })
92
97
 
98
+ /**
99
+ * What a given breakdown left out, or null when it is complete. Only the activity-scaled
100
+ * dimensions are ever capped, so this is null for everything else and the card renders no
101
+ * footer at all.
102
+ */
103
+ function capFor(dimension: ReportSpendDimension) {
104
+ return view.value?.capped.find((cap) => cap.dimension === dimension) ?? null
105
+ }
106
+
93
107
  const DAY_MS = 24 * 60 * 60 * 1000
94
108
 
95
109
  // How the window's SPEND half was answered. The long (TCO) windows read the durable
@@ -408,22 +422,12 @@ watch(
408
422
  </section>
409
423
  </div>
410
424
 
411
- <!-- The TCO axes: what a repository, a ticket and a single run actually cost.
412
- Spend-only, like the pair above, because a run's activity is already sliced by
413
- the service that owns the repo and there is no second population to pair a
414
- ticket with, and a run IS the unit activity counts. -->
415
- <div class="grid gap-6 md:grid-cols-3">
416
- <section>
417
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">
418
- {{ t('reports.spend.byRepo') }}
419
- </h2>
420
- <ReportsSpendBreakdown
421
- :rows="view.spend.byRepo"
422
- :currency="currency"
423
- test-id="reports-spend-repo"
424
- :label-of="sliceLabel"
425
- />
426
- </section>
425
+ <!-- The two spend-only TCO axes: what a ticket and a single run cost. There is no
426
+ second population to pair a ticket with, and a run IS the unit activity counts.
427
+ The repository axis has both halves, so it sits in the paired switch below.
428
+ Both of these grow with ACTIVITY rather than with a catalog, so both are the
429
+ breakdowns the projection caps, and each says so under its own card. -->
430
+ <div class="grid gap-6 md:grid-cols-2">
427
431
  <section>
428
432
  <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">
429
433
  {{ t('reports.spend.byTicket') }}
@@ -433,6 +437,7 @@ watch(
433
437
  :currency="currency"
434
438
  test-id="reports-spend-ticket"
435
439
  :label-of="sliceLabel"
440
+ :cap="capFor('ticket')"
436
441
  />
437
442
  </section>
438
443
  <section>
@@ -444,6 +449,7 @@ watch(
444
449
  :currency="currency"
445
450
  test-id="reports-spend-run"
446
451
  :label-of="sliceLabel"
452
+ :cap="capFor('run')"
447
453
  />
448
454
  </section>
449
455
  </div>
@@ -1,13 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
- import type { ReportSpendRow } from '~/types/execution'
3
+ import type { ReportSpendCap, ReportSpendRow } from '~/types/execution'
4
4
  import { maxOf, segmentPct, spendMagnitude } from './ReportsPanel.logic'
5
5
 
6
6
  // One ranked spend breakdown: a horizontal bar per slice, split into the metered
7
7
  // (`violet-500`, real money) and subscription (`amber-600`, illustrative equivalent-API
8
8
  // cost) segments with a surface gap between them. Extracted from `ReportsPanel.vue` because
9
- // the panel renders four of these against different dimensions the shape is identical,
10
- // only the row list and the heading differ.
9
+ // the panel renders five of these against different dimensions: the shape is identical, only
10
+ // the row list and the heading differ.
11
11
  //
12
12
  // Every bar is scaled against the HEAVIEST slice in this list, so a full bar means "the
13
13
  // biggest consumer here", never an absolute budget. The panel owns the legend (the two
@@ -18,6 +18,13 @@ const props = defineProps<{
18
18
  testId: string
19
19
  /** Resolves a slice's display name (the panel owns the unattributed/i18n vocabulary). */
20
20
  labelOf: (row: ReportSpendRow) => string
21
+ /**
22
+ * What this breakdown left out, when the projection capped it. Rendered as a footer note:
23
+ * a reader who assumes a list is complete would read the heaviest hundred repositories as
24
+ * the whole bill, so the tail is STATED rather than left to be inferred from the row count.
25
+ * The window totals above still cover it, which is what the note says.
26
+ */
27
+ cap?: ReportSpendCap | null
21
28
  }>()
22
29
 
23
30
  const { t, n } = useI18n()
@@ -70,5 +77,10 @@ const max = computed(() => maxOf(props.rows, spendMagnitude))
70
77
  </p>
71
78
  </li>
72
79
  </ul>
80
+ <p v-if="cap" class="mt-3 text-[10px] text-slate-500" :data-testid="`${testId}-capped`">
81
+ {{
82
+ t('reports.spend.capped', { shown: n(cap.returned), omitted: n(cap.omitted) }, cap.omitted)
83
+ }}
84
+ </p>
73
85
  </div>
74
86
  </template>
@@ -4,9 +4,9 @@ import type { ReportWindow, ReportsView } from '~/types/execution'
4
4
  import { useAccountsStore } from '~/stores/accounts'
5
5
 
6
6
  /**
7
- * Reports: cross-cutting usage analytics for the active account spend per model and
8
- * agent kind, spend + run activity per workspace / service / task type, and a spend trend,
9
- * over a selectable window and optionally narrowed to one board.
7
+ * Reports: cross-cutting usage analytics for the active account: spend per model, agent
8
+ * kind, ticket and run, spend + run activity per workspace / service / repository / task
9
+ * type, and a spend trend, over a selectable window and optionally narrowed to one board.
10
10
  *
11
11
  * The sibling of the `platformObservability` store: same account scope, same admin gate,
12
12
  * same on-demand load. Nothing is pushed live (these are periodic rollups); changing the
@@ -43,6 +43,7 @@ export type {
43
43
  ReportSpendDimension,
44
44
  ReportActivityDimension,
45
45
  ReportSpendRow,
46
+ ReportSpendCap,
46
47
  ReportActivityRow,
47
48
  ReportTrendPoint,
48
49
  ReportTotals,
@@ -4022,6 +4022,7 @@
4022
4022
  "dimension": {
4023
4023
  "workspace": "Board",
4024
4024
  "service": "Service",
4025
+ "repo": "Repository",
4025
4026
  "taskType": "Aufgabentyp"
4026
4027
  },
4027
4028
  "breakdown": {
@@ -4048,14 +4049,14 @@
4048
4049
  "spend": {
4049
4050
  "byModel": "Kosten nach Modell",
4050
4051
  "byAgentKind": "Kosten nach Agententyp",
4051
- "byRepo": "Kosten nach Repository",
4052
4052
  "byTicket": "Kosten nach Ticket",
4053
4053
  "byRun": "Kosten nach Lauf",
4054
4054
  "heading": "Kosten",
4055
4055
  "empty": "In diesem Zeitraum wurde keine Nutzung erfasst.",
4056
4056
  "calls": "{count} Aufruf | {count} Aufrufe",
4057
4057
  "tokens": "{input} rein / {output} raus",
4058
- "subscriptionAside": "+{value} Abo"
4058
+ "subscriptionAside": "+{value} Abo",
4059
+ "capped": "Angezeigt werden die {shown} teuersten. {omitted} weiterer Eintrag ist nicht aufgeführt, in den Summen oben aber enthalten. | Angezeigt werden die {shown} teuersten. {omitted} weitere Einträge sind nicht aufgeführt, in den Summen oben aber enthalten."
4059
4060
  },
4060
4061
  "activity": {
4061
4062
  "heading": "Läufe",
@@ -2073,6 +2073,7 @@
2073
2073
  "dimension": {
2074
2074
  "workspace": "Board",
2075
2075
  "service": "Service",
2076
+ "repo": "Repository",
2076
2077
  "taskType": "Task type"
2077
2078
  },
2078
2079
  "breakdown": {
@@ -2099,14 +2100,14 @@
2099
2100
  "spend": {
2100
2101
  "byModel": "Spend by model",
2101
2102
  "byAgentKind": "Spend by agent kind",
2102
- "byRepo": "Spend by repository",
2103
2103
  "byTicket": "Spend by ticket",
2104
2104
  "byRun": "Spend by run",
2105
2105
  "heading": "Spend",
2106
2106
  "empty": "No recorded usage in this window.",
2107
2107
  "calls": "{count} call | {count} calls",
2108
2108
  "tokens": "{input} in / {output} out",
2109
- "subscriptionAside": "+{value} subscription"
2109
+ "subscriptionAside": "+{value} subscription",
2110
+ "capped": "Showing the {shown} costliest. {omitted} more is not listed, though the totals above still include it. | Showing the {shown} costliest. {omitted} more are not listed, though the totals above still include them."
2110
2111
  },
2111
2112
  "activity": {
2112
2113
  "heading": "Runs",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "Tablero",
1971
1971
  "service": "Servicio",
1972
+ "repo": "Repositorio",
1972
1973
  "taskType": "Tipo de tarea"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "Gasto por modelo",
1997
1998
  "byAgentKind": "Gasto por tipo de agente",
1998
- "byRepo": "Gasto por repositorio",
1999
1999
  "byTicket": "Gasto por tique",
2000
2000
  "byRun": "Gasto por ejecución",
2001
2001
  "heading": "Gasto",
2002
2002
  "empty": "No se registró uso en este periodo.",
2003
2003
  "calls": "{count} llamada | {count} llamadas",
2004
2004
  "tokens": "{input} de entrada / {output} de salida",
2005
- "subscriptionAside": "+{value} suscripción"
2005
+ "subscriptionAside": "+{value} suscripción",
2006
+ "capped": "Se muestran los {shown} más costosos. Hay {omitted} más que no aparece, aunque los totales de arriba sí lo incluyen. | Se muestran los {shown} más costosos. Hay {omitted} más que no aparecen, aunque los totales de arriba sí los incluyen."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "Ejecuciones",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "Tableau",
1971
1971
  "service": "Service",
1972
+ "repo": "Dépôt",
1972
1973
  "taskType": "Type de tâche"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "Dépense par modèle",
1997
1998
  "byAgentKind": "Dépense par type d’agent",
1998
- "byRepo": "Dépense par dépôt",
1999
1999
  "byTicket": "Dépense par ticket",
2000
2000
  "byRun": "Dépense par exécution",
2001
2001
  "heading": "Dépense",
2002
2002
  "empty": "Aucune utilisation enregistrée sur cette période.",
2003
2003
  "calls": "{count} appel | {count} appels",
2004
2004
  "tokens": "{input} en entrée / {output} en sortie",
2005
- "subscriptionAside": "+{value} abonnement"
2005
+ "subscriptionAside": "+{value} abonnement",
2006
+ "capped": "Les {shown} plus coûteux sont affichés. {omitted} autre n’est pas listé, mais les totaux ci-dessus l’incluent. | Les {shown} plus coûteux sont affichés. {omitted} autres ne sont pas listés, mais les totaux ci-dessus les incluent."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "Exécutions",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "לוח",
1971
1971
  "service": "שירות",
1972
+ "repo": "מאגר",
1972
1973
  "taskType": "סוג משימה"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "עלות לפי מודל",
1997
1998
  "byAgentKind": "עלות לפי סוג סוכן",
1998
- "byRepo": "עלות לפי מאגר",
1999
1999
  "byTicket": "עלות לפי כרטיס",
2000
2000
  "byRun": "עלות לפי הרצה",
2001
2001
  "heading": "עלות",
2002
2002
  "empty": "לא נרשם שימוש בטווח הזה.",
2003
2003
  "calls": "קריאה אחת | שתי קריאות | {count} קריאות",
2004
2004
  "tokens": "{input} נכנס / {output} יוצא",
2005
- "subscriptionAside": "+{value} מנוי"
2005
+ "subscriptionAside": "+{value} מנוי",
2006
+ "capped": "מוצגים {shown} היקרים ביותר. פריט אחד נוסף אינו מופיע ברשימה, אך הסיכומים שלמעלה כוללים גם אותו. | מוצגים {shown} היקרים ביותר. שני פריטים נוספים אינם מופיעים ברשימה, אך הסיכומים שלמעלה כוללים גם אותם. | מוצגים {shown} היקרים ביותר. {omitted} פריטים נוספים אינם מופיעים ברשימה, אך הסיכומים שלמעלה כוללים גם אותם."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "ריצות",
@@ -4022,6 +4022,7 @@
4022
4022
  "dimension": {
4023
4023
  "workspace": "Board",
4024
4024
  "service": "Servizio",
4025
+ "repo": "Repository",
4025
4026
  "taskType": "Tipo di attività"
4026
4027
  },
4027
4028
  "breakdown": {
@@ -4048,14 +4049,14 @@
4048
4049
  "spend": {
4049
4050
  "byModel": "Spesa per modello",
4050
4051
  "byAgentKind": "Spesa per tipo di agente",
4051
- "byRepo": "Spesa per repository",
4052
4052
  "byTicket": "Spesa per ticket",
4053
4053
  "byRun": "Spesa per esecuzione",
4054
4054
  "heading": "Spesa",
4055
4055
  "empty": "Nessun utilizzo registrato in questo periodo.",
4056
4056
  "calls": "{count} chiamata | {count} chiamate",
4057
4057
  "tokens": "{input} in ingresso / {output} in uscita",
4058
- "subscriptionAside": "+{value} abbonamento"
4058
+ "subscriptionAside": "+{value} abbonamento",
4059
+ "capped": "Vengono mostrati i {shown} più costosi. Ne resta {omitted} non elencato, ma i totali qui sopra lo includono. | Vengono mostrati i {shown} più costosi. Ne restano altri {omitted} non elencati, ma i totali qui sopra li includono."
4059
4060
  },
4060
4061
  "activity": {
4061
4062
  "heading": "Esecuzioni",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "ボード",
1971
1971
  "service": "サービス",
1972
+ "repo": "リポジトリ",
1972
1973
  "taskType": "タスクの種類"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "モデル別の費用",
1997
1998
  "byAgentKind": "エージェント種別の費用",
1998
- "byRepo": "リポジトリ別の費用",
1999
1999
  "byTicket": "チケット別の費用",
2000
2000
  "byRun": "実行別の費用",
2001
2001
  "heading": "費用",
2002
2002
  "empty": "この期間に記録された利用はありません。",
2003
2003
  "calls": "{count} 件の呼び出し | {count} 件の呼び出し",
2004
2004
  "tokens": "入力 {input} / 出力 {output}",
2005
- "subscriptionAside": "+{value} サブスクリプション"
2005
+ "subscriptionAside": "+{value} サブスクリプション",
2006
+ "capped": "費用の大きい上位 {shown} 件を表示しています。ほかに {omitted} 件は一覧にありませんが、上の合計には含まれています。 | 費用の大きい上位 {shown} 件を表示しています。ほかに {omitted} 件は一覧にありませんが、上の合計には含まれています。"
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "実行",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "Tablica",
1971
1971
  "service": "Usługa",
1972
+ "repo": "Repozytorium",
1972
1973
  "taskType": "Typ zadania"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "Koszty według modelu",
1997
1998
  "byAgentKind": "Koszty według typu agenta",
1998
- "byRepo": "Koszty według repozytorium",
1999
1999
  "byTicket": "Koszty według zgłoszenia",
2000
2000
  "byRun": "Koszty według uruchomienia",
2001
2001
  "heading": "Koszty",
2002
2002
  "empty": "W tym okresie nie zarejestrowano użycia.",
2003
2003
  "calls": "{count} wywołanie | {count} wywołania | {count} wywołań",
2004
2004
  "tokens": "{input} wejścia / {output} wyjścia",
2005
- "subscriptionAside": "+{value} subskrypcja"
2005
+ "subscriptionAside": "+{value} subskrypcja",
2006
+ "capped": "Pokazano {shown} najdroższych. Kolejnej {omitted} pozycji nie ujęto na liście, ale sumy powyżej ją uwzględniają. | Pokazano {shown} najdroższych. Kolejnych {omitted} pozycji nie ujęto na liście, ale sumy powyżej je uwzględniają. | Pokazano {shown} najdroższych. Kolejnych {omitted} pozycji nie ujęto na liście, ale sumy powyżej je uwzględniają."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "Uruchomienia",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "Pano",
1971
1971
  "service": "Servis",
1972
+ "repo": "Depo",
1972
1973
  "taskType": "Görev türü"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "Modele göre harcama",
1997
1998
  "byAgentKind": "Ajan türüne göre harcama",
1998
- "byRepo": "Depoya göre harcama",
1999
1999
  "byTicket": "Bilete göre harcama",
2000
2000
  "byRun": "Çalıştırmaya göre harcama",
2001
2001
  "heading": "Harcama",
2002
2002
  "empty": "Bu dönemde kayıtlı kullanım yok.",
2003
2003
  "calls": "{count} çağrı | {count} çağrı",
2004
2004
  "tokens": "{input} giriş / {output} çıkış",
2005
- "subscriptionAside": "+{value} abonelik"
2005
+ "subscriptionAside": "+{value} abonelik",
2006
+ "capped": "En maliyetli {shown} tanesi gösteriliyor. {omitted} tanesi listelenmiyor, ancak yukarıdaki toplamlara dahil. | En maliyetli {shown} tanesi gösteriliyor. {omitted} tanesi listelenmiyor, ancak yukarıdaki toplamlara dahil."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "Çalıştırmalar",
@@ -1969,6 +1969,7 @@
1969
1969
  "dimension": {
1970
1970
  "workspace": "Дошка",
1971
1971
  "service": "Сервіс",
1972
+ "repo": "Репозиторій",
1972
1973
  "taskType": "Тип завдання"
1973
1974
  },
1974
1975
  "breakdown": {
@@ -1995,14 +1996,14 @@
1995
1996
  "spend": {
1996
1997
  "byModel": "Витрати за моделлю",
1997
1998
  "byAgentKind": "Витрати за типом агента",
1998
- "byRepo": "Витрати за репозиторієм",
1999
1999
  "byTicket": "Витрати за тікетом",
2000
2000
  "byRun": "Витрати за запуском",
2001
2001
  "heading": "Витрати",
2002
2002
  "empty": "За цей період використання не зафіксовано.",
2003
2003
  "calls": "{count} виклик | {count} виклики | {count} викликів",
2004
2004
  "tokens": "{input} вхід / {output} вихід",
2005
- "subscriptionAside": "+{value} підписка"
2005
+ "subscriptionAside": "+{value} підписка",
2006
+ "capped": "Показано {shown} найдорожчих. Ще {omitted} позицію не наведено в списку, але підсумки вище її враховують. | Показано {shown} найдорожчих. Ще {omitted} позиції не наведено в списку, але підсумки вище їх ураховують. | Показано {shown} найдорожчих. Ще {omitted} позицій не наведено в списку, але підсумки вище їх ураховують."
2006
2007
  },
2007
2008
  "activity": {
2008
2009
  "heading": "Запуски",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.286.5",
3
+ "version": "0.287.0",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,7 +18,7 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@cat-factory/contracts": "0.333.0",
21
+ "@cat-factory/contracts": "0.334.0",
22
22
  "@modular-frontend/core": "0.6.0",
23
23
  "@modular-vue/core": "^1.5.0",
24
24
  "@modular-vue/journeys": "^1.4.0",
@@ -35,7 +35,7 @@
35
35
  "@vue-flow/core": "^1.48.2",
36
36
  "@vue-flow/node-resizer": "^1.5.1",
37
37
  "@vueuse/core": "^14.4.0",
38
- "markdown-it": "^15.0.0",
38
+ "markdown-it": "^15.0.1",
39
39
  "pinia": "^4.0.3",
40
40
  "pinia-plugin-persistedstate": "^4.7.1",
41
41
  "valibot": "^1.4.2",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",
47
- "happy-dom": "^20.11.8",
47
+ "happy-dom": "^20.11.12",
48
48
  "msw": "^2.15.0",
49
49
  "nuxt": "^4.5.2",
50
50
  "typescript": "^6.0.3",