feat(seed): génération PDF cohérente par facture via @react-pdf/renderer
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 57s
Build & Deploy API / build-and-deploy (push) Successful in 1m40s

Chaque facture seedée a maintenant son propre PDF dont le contenu
matche exactement les meta DB (vendeur = org du user, client = client
réel, numéro / dates / montant cohérents). Plus de réutilisation
round-robin de PDFs disque non-cohérents.

Stack :
  - @react-pdf/renderer : composants React déclaratifs, StyleSheet
    inspiré du SPA (mêmes tokens couleur Rubis), même mental model que
    le frontend.
  - InvoiceDocument décomposé en sous-composants Header / Addresses /
    ItemsTable / Totals / Footer pour itération facile.
  - Items générés depuis un pool B2B (conseil, dev, audit, formation,
    livraison, photo, …) avec quantités/prix unitaires qui s'ajustent
    pour que la somme matche le total TTC stocké.

Le command `seed:demo --reset` :
  - wipe les invoice-pdfs/{orgId}/* sur MinIO (paginé)
  - re-génère 227 PDFs (27 actionnables + 200 historiques)
  - CA cumulé paid ≈ 400 K€ pile sur la cible

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ordinarthur 2026-05-07 12:59:55 +02:00
parent 040e787ee5
commit b96b62aab6
5 changed files with 1416 additions and 444 deletions

View File

@ -11,7 +11,7 @@ import ActivityEvent from '#models/activity_event'
import RelanceTask from '#models/relance_task'
import CheckinTask from '#models/checkin_task'
import { provisionDefaultPlans } from '#services/default_plans'
import { seedDemoOrg } from '#database/factories'
import { seedDemoOrg, wipeOrgInvoicePdfs } from '#database/factories'
/**
* Peuple l'org d'un user existant avec des données de démo réalistes
@ -90,6 +90,15 @@ export default class SeedDemo extends BaseCommand {
await ActivityEvent.query({ client: trx }).where('organization_id', org.id).delete()
await Invoice.query({ client: trx }).where('organization_id', org.id).delete()
await Client.query({ client: trx }).where('organization_id', org.id).delete()
// Drop tous les PDFs MinIO de l'org pour repartir d'un drive propre.
// Hors transaction (drive n'a pas de notion de tx) — si la suite
// échoue, les PDFs sont déjà partis : pas grave, ils étaient destinés
// au reset de toute façon.
const wiped = await wipeOrgInvoicePdfs(org.id)
if (wiped > 0) {
this.logger.info(`MinIO : ${wiped} PDFs de facture supprimés.`)
}
}
// Configure l'org : nom (si fourni) + bucket volume mensuel

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,481 @@
/**
* Génération de PDFs de factures via `@react-pdf/renderer` composants
* React déclaratifs, mêmes couleurs que le SPA, maintenable de bout en
* bout sans switcher de mental model.
*
* Le `renderToBuffer(<InvoiceDocument …/>)` produit un Buffer uploadable
* tel quel via `drive.use().put(key, buf)`.
*
* Polices : on reste sur Helvetica intégrée (pas besoin de loader des
* fichiers TTF, ça simplifie la portabilité prod).
*/
import { DateTime } from 'luxon'
import {
Document,
Page,
View,
Text,
StyleSheet,
renderToBuffer,
} from '@react-pdf/renderer'
import * as React from 'react'
// ---------------------------------------------------------------------------
// Types — exposés pour factories.ts
// ---------------------------------------------------------------------------
export type InvoiceItem = {
description: string
unit: string
quantity: number
unitPriceHtCents: number
}
export type PdfInvoiceInput = {
seller: {
name: string
address: string
siret: string | null
tvaNumber: string | null
email: string
phone: string | null
iban: string
}
client: {
name: string
contactFirstName: string | null
contactLastName: string | null
address: string | null
siret: string | null
}
invoice: {
numero: string
issueDate: Date
dueDate: Date
items: InvoiceItem[]
note?: string | null
}
}
// ---------------------------------------------------------------------------
// Tokens de marque (cf. CLAUDE.md → palette)
// ---------------------------------------------------------------------------
const C = {
rubis: '#9F1239',
rubisDeep: '#771328',
rubisGlow: '#FBE4EA',
cream: '#FAF7F2',
cream2: '#F5EFE7',
ink: '#1A1410',
ink2: '#4F4640',
ink3: '#8A7F76',
line: '#E8E0D6',
white: '#FFFFFF',
} as const
// ---------------------------------------------------------------------------
// Helpers de formatage FR
// ---------------------------------------------------------------------------
const FR_DATE = new Intl.DateTimeFormat('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
function formatDate(d: Date): string {
return FR_DATE.format(d)
}
const FR_EUROS = new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 2,
})
function formatEuros(cents: number): string {
return FR_EUROS.format(cents / 100)
}
// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------
const styles = StyleSheet.create({
page: {
backgroundColor: C.white,
fontFamily: 'Helvetica',
fontSize: 10,
color: C.ink,
paddingBottom: 60,
},
// Header bandeau
header: {
backgroundColor: C.rubisDeep,
color: C.white,
paddingHorizontal: 48,
paddingVertical: 32,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
},
headerLeft: { flex: 1, paddingRight: 16 },
sellerName: {
fontFamily: 'Helvetica-Bold',
fontSize: 20,
marginBottom: 10,
},
sellerMeta: {
fontSize: 8.5,
color: C.cream2,
lineHeight: 1.5,
},
headerRight: { width: 180, alignItems: 'flex-end' },
factureLabel: {
fontFamily: 'Helvetica-Bold',
fontSize: 26,
marginBottom: 8,
},
factureMeta: {
fontSize: 9,
color: C.cream2,
lineHeight: 1.5,
},
// Addresses
addresses: {
paddingHorizontal: 48,
paddingTop: 32,
flexDirection: 'row',
justifyContent: 'space-between',
},
addressBlock: { flex: 1 },
addressBlockRight: { flex: 1, alignItems: 'flex-end' },
eyebrow: {
fontFamily: 'Helvetica-Bold',
fontSize: 8,
letterSpacing: 1,
color: C.ink3,
marginBottom: 6,
},
clientName: {
fontFamily: 'Helvetica-Bold',
fontSize: 13,
color: C.ink,
marginBottom: 4,
},
clientMeta: {
fontSize: 9.5,
color: C.ink2,
lineHeight: 1.4,
},
clientSiret: {
fontSize: 8,
color: C.ink3,
marginTop: 4,
},
dueDate: {
fontFamily: 'Helvetica-Bold',
fontSize: 15,
color: C.rubis,
marginBottom: 4,
},
dueDateSub: {
fontSize: 9,
color: C.ink3,
},
// Items table
table: {
marginTop: 36,
paddingHorizontal: 48,
},
tableHeader: {
backgroundColor: C.cream2,
flexDirection: 'row',
paddingVertical: 8,
paddingHorizontal: 10,
},
th: {
fontFamily: 'Helvetica-Bold',
fontSize: 8.5,
letterSpacing: 0.5,
color: C.ink3,
},
tableRow: {
flexDirection: 'row',
paddingVertical: 10,
paddingHorizontal: 10,
borderBottomWidth: 0.5,
borderBottomColor: C.line,
},
tdDescription: { flex: 5 },
tdQty: { flex: 1, textAlign: 'right' },
tdUnit: { flex: 1.5, textAlign: 'right' },
tdTotal: { flex: 2, textAlign: 'right' },
itemDesc: {
fontSize: 10,
color: C.ink,
},
itemUnit: {
fontSize: 8,
color: C.ink3,
marginTop: 2,
},
// Totals
totals: {
marginTop: 18,
paddingHorizontal: 48,
flexDirection: 'row',
justifyContent: 'flex-end',
},
totalsBlock: { width: 240 },
totalRow: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: 4,
},
totalLabel: {
fontSize: 10,
color: C.ink2,
},
totalValue: {
fontFamily: 'Helvetica-Bold',
fontSize: 10,
color: C.ink,
},
totalTtcRow: {
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: C.rubisGlow,
paddingVertical: 10,
paddingHorizontal: 12,
marginTop: 8,
alignItems: 'center',
},
totalTtcLabel: {
fontFamily: 'Helvetica-Bold',
fontSize: 11,
color: C.rubisDeep,
},
totalTtcValue: {
fontFamily: 'Helvetica-Bold',
fontSize: 14,
color: C.rubisDeep,
},
// Note libre
note: {
marginTop: 28,
paddingHorizontal: 48,
fontSize: 9,
fontStyle: 'italic',
color: C.ink3,
lineHeight: 1.4,
},
// Footer fixe en bas de page
footer: {
position: 'absolute',
bottom: 24,
left: 48,
right: 48,
textAlign: 'center',
},
footerLine: {
fontSize: 7.5,
color: C.ink3,
lineHeight: 1.5,
},
footerBrand: {
fontSize: 7,
color: C.ink3,
marginTop: 4,
},
})
// ---------------------------------------------------------------------------
// Composants
// ---------------------------------------------------------------------------
function InvoiceDocument({ data }: { data: PdfInvoiceInput }) {
const totalHt = data.invoice.items.reduce(
(s, i) => s + i.quantity * i.unitPriceHtCents,
0
)
const tva = Math.round(totalHt * 0.2)
const totalTtc = totalHt + tva
const paymentTermDays = Math.round(
DateTime.fromJSDate(data.invoice.dueDate)
.startOf('day')
.diff(
DateTime.fromJSDate(data.invoice.issueDate).startOf('day'),
'days'
).days
)
return (
<Document
title={`Facture ${data.invoice.numero}`}
author={data.seller.name}
creator="Rubis"
>
<Page size="A4" style={styles.page}>
<Header data={data} />
<Addresses data={data} paymentTermDays={paymentTermDays} />
<ItemsTable items={data.invoice.items} />
<Totals totalHt={totalHt} tva={tva} totalTtc={totalTtc} />
{data.invoice.note ? <Text style={styles.note}>{data.invoice.note}</Text> : null}
<Footer iban={data.seller.iban} />
</Page>
</Document>
)
}
function Header({ data }: { data: PdfInvoiceInput }) {
return (
<View style={styles.header}>
<View style={styles.headerLeft}>
<Text style={styles.sellerName}>{data.seller.name}</Text>
<Text style={styles.sellerMeta}>
{data.seller.address} · {data.seller.email}
{data.seller.phone ? ` · ${data.seller.phone}` : ''}
</Text>
{data.seller.siret ? (
<Text style={styles.sellerMeta}>
SIRET {data.seller.siret}
{data.seller.tvaNumber ? ` · TVA ${data.seller.tvaNumber}` : ''}
</Text>
) : null}
</View>
<View style={styles.headerRight}>
<Text style={styles.factureLabel}>FACTURE</Text>
<Text style={styles.factureMeta}>N° {data.invoice.numero}</Text>
<Text style={styles.factureMeta}>
Émise le {formatDate(data.invoice.issueDate)}
</Text>
</View>
</View>
)
}
function Addresses({
data,
paymentTermDays,
}: {
data: PdfInvoiceInput
paymentTermDays: number
}) {
const { client } = data
const contactName = [client.contactFirstName, client.contactLastName]
.filter(Boolean)
.join(' ')
return (
<View style={styles.addresses}>
<View style={styles.addressBlock}>
<Text style={styles.eyebrow}>ADRESSÉE À</Text>
<Text style={styles.clientName}>{client.name}</Text>
{contactName ? (
<Text style={styles.clientMeta}>À l'attention de {contactName}</Text>
) : null}
{client.address ? (
<Text style={styles.clientMeta}>{client.address}</Text>
) : null}
{client.siret ? (
<Text style={styles.clientSiret}>SIRET {client.siret}</Text>
) : null}
</View>
<View style={styles.addressBlockRight}>
<Text style={styles.eyebrow}>ÉCHÉANCE</Text>
<Text style={styles.dueDate}>{formatDate(data.invoice.dueDate)}</Text>
<Text style={styles.dueDateSub}>Soit {paymentTermDays} jours</Text>
</View>
</View>
)
}
function ItemsTable({ items }: { items: InvoiceItem[] }) {
return (
<View style={styles.table}>
<View style={styles.tableHeader}>
<Text style={[styles.th, styles.tdDescription]}>DÉSIGNATION</Text>
<Text style={[styles.th, styles.tdQty]}>QTÉ</Text>
<Text style={[styles.th, styles.tdUnit]}>P.U. HT</Text>
<Text style={[styles.th, styles.tdTotal]}>TOTAL HT</Text>
</View>
{items.map((item, idx) => {
const itemTotalHt = item.quantity * item.unitPriceHtCents
return (
<View key={idx} style={styles.tableRow}>
<View style={styles.tdDescription}>
<Text style={styles.itemDesc}>{item.description}</Text>
<Text style={styles.itemUnit}>{item.unit}</Text>
</View>
<Text style={[styles.itemDesc, styles.tdQty]}>{item.quantity}</Text>
<Text style={[styles.itemDesc, styles.tdUnit]}>
{formatEuros(item.unitPriceHtCents)}
</Text>
<Text style={[styles.itemDesc, styles.tdTotal]}>
{formatEuros(itemTotalHt)}
</Text>
</View>
)
})}
</View>
)
}
function Totals({
totalHt,
tva,
totalTtc,
}: {
totalHt: number
tva: number
totalTtc: number
}) {
return (
<View style={styles.totals}>
<View style={styles.totalsBlock}>
<View style={styles.totalRow}>
<Text style={styles.totalLabel}>Total HT</Text>
<Text style={styles.totalValue}>{formatEuros(totalHt)}</Text>
</View>
<View style={styles.totalRow}>
<Text style={styles.totalLabel}>TVA 20%</Text>
<Text style={styles.totalValue}>{formatEuros(tva)}</Text>
</View>
<View style={styles.totalTtcRow}>
<Text style={styles.totalTtcLabel}>TOTAL TTC</Text>
<Text style={styles.totalTtcValue}>{formatEuros(totalTtc)}</Text>
</View>
</View>
</View>
)
}
function Footer({ iban }: { iban: string }) {
return (
<View style={styles.footer} fixed>
<Text style={styles.footerLine}>
Règlement par virement IBAN {iban} · Pénalités de retard : 3× taux légal
· Indemnité forfaitaire 40 (art. L.441-10 C. com.)
</Text>
<Text style={styles.footerBrand}>Émise via Rubis Sur l'Ongle</Text>
</View>
)
}
// ---------------------------------------------------------------------------
// API publique
// ---------------------------------------------------------------------------
export async function generateInvoicePdfBuffer(
data: PdfInvoiceInput
): Promise<Buffer> {
return renderToBuffer(<InvoiceDocument data={data} />)
}

View File

@ -50,6 +50,7 @@
"@types/luxon": "^3.7.1",
"@types/node": "~25.6.0",
"@types/pg": "^8.20.0",
"@types/react": "^19.2.14",
"eslint": "^10.2.0",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
@ -74,6 +75,7 @@
"@aws-sdk/client-s3": "^3.1043.0",
"@aws-sdk/s3-request-presigner": "^3.1043.0",
"@japa/api-client": "^3.2.1",
"@react-pdf/renderer": "^4.5.1",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.3.1",
"better-sqlite3": "^12.9.0",
@ -81,6 +83,7 @@
"ioredis": "^5.10.1",
"luxon": "^3.7.2",
"pg": "^8.20.0",
"react": "^19.2.5",
"reflect-metadata": "^0.2.2"
},
"hotHook": {

439
pnpm-lock.yaml generated
View File

@ -77,6 +77,9 @@ importers:
'@japa/api-client':
specifier: ^3.2.1
version: 3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0)
'@react-pdf/renderer':
specifier: ^4.5.1
version: 4.5.1(react@19.2.5)
'@tuyau/core':
specifier: ^1.2.2
version: 1.2.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))
@ -98,6 +101,9 @@ importers:
pg:
specifier: ^8.20.0
version: 8.20.0
react:
specifier: ^19.2.5
version: 19.2.5
reflect-metadata:
specifier: ^0.2.2
version: 0.2.2
@ -125,7 +131,7 @@ importers:
version: 5.3.0
'@poppinss/ts-exec':
specifier: ^1.4.4
version: 1.4.4
version: 1.4.4(@swc/helpers@0.5.21)
'@types/luxon':
specifier: ^3.7.1
version: 3.7.1
@ -135,6 +141,9 @@ importers:
'@types/pg':
specifier: ^8.20.0
version: 8.20.0
'@types/react':
specifier: ^19.2.14
version: 19.2.14
eslint:
specifier: ^10.2.0
version: 10.3.0(jiti@2.7.0)
@ -1489,6 +1498,10 @@ packages:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
'@noble/ciphers@1.3.0':
resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
engines: {node: ^14.21.3 || >=16}
'@noble/hashes@1.8.0':
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
engines: {node: ^14.21.3 || >=16}
@ -1934,6 +1947,49 @@ packages:
'@radix-ui/rect@1.1.1':
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
'@react-pdf/fns@3.1.3':
resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==}
'@react-pdf/font@4.0.8':
resolution: {integrity: sha512-deNd+emtZAJho1IlzKL9bRoLAGv/6oXOIKO2oZfs4RuXUrK1onLHbJO7e2YoVLPFP/sQxisRTnzdJFtd35iKwA==}
'@react-pdf/image@3.1.0':
resolution: {integrity: sha512-ks7Ry8v711r8NvKWSELehj0BXBNPRihSnWsM09nDD8Ur175zbWBCK217LLwQMKDNYDVpkZaipdoJPom1LGaE9g==}
'@react-pdf/layout@4.6.1':
resolution: {integrity: sha512-gN6PmWoEffvlIkifLfEhMsVucRywVMyH3rnxdyOVOhGy0nWJKKGpHyPc4plbDdpP6EfZ0r8prHXujDSkIG2nSA==}
'@react-pdf/pdfkit@5.1.1':
resolution: {integrity: sha512-wNcdSsNlNYyGHGAgIdt453egBF7fiF9UxpRlklUfVvu8OWCrUppG9xiUrPLVoKiqWet5tMi0w6LmuFUJuYqjEg==}
'@react-pdf/primitives@4.3.0':
resolution: {integrity: sha512-nYXoZ36pvwNzbc54+DbL8RCn15jU7woJ9D/svnh5tpUXekJ+CbI4mZLo6boSv24CvJgychOu6h7gxX03B4ps0A==}
'@react-pdf/reconciler@2.0.0':
resolution: {integrity: sha512-7zaPRujpbHSmCpIrZ+b9HSTJHthcVZzX0Wx7RzvQGsGBUbHP4p6s5itXrAIOuQuPvDepoHGNOvf6xUuMVvdoyw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@react-pdf/render@4.5.1':
resolution: {integrity: sha512-IW/N4HWJWtioBXCf7n02IR24VJJ8gbdS3jGypf+vW/rSErEx3/URRzh9UK6Ma8Fpog9+T/W6GE2NHJ5AAKHhVA==}
'@react-pdf/renderer@4.5.1':
resolution: {integrity: sha512-5r1VQrE6FRLXX5wWUxwZzM24E2BJMo6g8AQWuS8WyPs9ugu5yMnb2g8/RpPYka/Z6J+RUEWc32wty2NoUJF42Q==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@react-pdf/stylesheet@6.2.1':
resolution: {integrity: sha512-2+UEk+7e+z8baaWi2l5kPLWmwtJeOI+T5wW9GGeN3iDH7vd3kbTqOpN1yt9mmfNVZFxQsnDHpznFb5v5UF983A==}
'@react-pdf/svg@1.1.0':
resolution: {integrity: sha512-cTIHXiz9x1HrbfqzfxfZP3FRdDwUXG77QWF6Fb5MP/lV3ONxR+g0Z3hwtBatCS9HeGBQCpxX/Lzb8wHE+co1PA==}
'@react-pdf/textkit@6.3.0':
resolution: {integrity: sha512-v6+V8nAcVwm7s2s1jIG2MD3Iw//x/k+XrH1foWOELBE4b32pyDgKyPXN/6KJE0dnX7+fVy27uctLNCLNMvzKzQ==}
'@react-pdf/types@2.11.1':
resolution: {integrity: sha512-i9xQgfaDU9QoeNnbp6rltXCWg1huEh195rpOuN8cE4BZ2FuLdQrsIcb2dhFF9aOxXf+XBA6LOSpIW051MDD/bw==}
'@reduxjs/toolkit@2.11.2':
resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==}
peerDependencies:
@ -2494,6 +2550,9 @@ packages:
'@swc/counter@0.1.3':
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
'@swc/helpers@0.5.21':
resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==}
'@swc/types@0.1.26':
resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==}
@ -3004,6 +3063,9 @@ packages:
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
abs-svg-path@0.1.1:
resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==}
abstract-logging@2.0.1:
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
@ -3101,6 +3163,10 @@ packages:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
base64-js@0.0.8:
resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
engines: {node: '>= 0.4'}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@ -3117,6 +3183,9 @@ packages:
resolution: {integrity: sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==}
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x}
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
@ -3141,6 +3210,12 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
brotli@1.3.3:
resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==}
browserify-zlib@0.2.0:
resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==}
browserslist@4.28.2:
resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@ -3272,6 +3347,10 @@ packages:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
clone@2.1.2:
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
engines: {node: '>=0.8'}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@ -3290,6 +3369,14 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
color-name@2.1.0:
resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==}
engines: {node: '>=12.20'}
color-string@2.1.4:
resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==}
engines: {node: '>=18'}
colorette@2.0.19:
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
@ -3516,6 +3603,9 @@ packages:
dezalgo@1.0.4:
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
dfa@1.2.0:
resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==}
diff@8.0.4:
resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
engines: {node: '>=0.3.1'}
@ -3546,6 +3636,9 @@ packages:
resolution: {integrity: sha512-sFz64DCRjirhwHLxofFqxYQm6DCp6o0Ix7jwKQvuCHPn4GMRZNuBZyLPu9Ccmk/QSCAMZt6FOUqA8JZCQvA9fw==}
engines: {node: '>=14.16'}
emoji-regex-xs@1.0.0:
resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@ -3735,6 +3828,10 @@ packages:
eventemitter3@5.0.4:
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
@ -3805,6 +3902,9 @@ packages:
picomatch:
optional: true
fflate@0.8.2:
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
figures@6.1.0:
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
engines: {node: '>=18'}
@ -3862,6 +3962,9 @@ packages:
'@google-cloud/storage':
optional: true
fontkit@2.0.4:
resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
@ -4017,6 +4120,12 @@ packages:
hot-hook@1.0.0:
resolution: {integrity: sha512-OkZm5tTE4ej8ur8VlcQwMm8G9sFxu4D+shM+ol/h4mrUhuZvFkjk5n/nWKmLq3COmy6epLN7XIIQJ75tnqCGIw==}
hsl-to-hex@1.0.0:
resolution: {integrity: sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==}
hsl-to-rgb-for-reals@1.1.1:
resolution: {integrity: sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==}
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
@ -4046,6 +4155,9 @@ packages:
engines: {node: '>=18'}
hasBin: true
hyphen@1.14.1:
resolution: {integrity: sha512-kvL8xYl5QMTh+LwohVN72ciOxC0OEV79IPdJSTwEXok9y9QHebXGdFgrED4sWfiax/ODx++CAMk3hMy4XPJPOw==}
ical-generator@10.2.0:
resolution: {integrity: sha512-XR5FsiDWCsz5MwBwMA/sQqR3A9H240xkXIeXOabV7uNAiieP+TA9rleVvlwPLRXMz+CXME8cGuDd7cdnE5At6w==}
engines: {node: 20 || 22 || >=24}
@ -4229,6 +4341,9 @@ packages:
resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
engines: {node: '>=18'}
is-url@1.2.4:
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
is-wsl@3.1.1:
resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
engines: {node: '>=16'}
@ -4240,6 +4355,9 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
jay-peg@1.1.1:
resolution: {integrity: sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==}
jest-diff@30.3.0:
resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
@ -4252,6 +4370,9 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
js-md5@0.8.3:
resolution: {integrity: sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@ -4452,6 +4573,9 @@ packages:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
linebreak@1.1.0:
resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
lint-staged@15.5.2:
resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==}
engines: {node: '>=18.12.0'}
@ -4488,6 +4612,10 @@ packages:
resolution: {integrity: sha512-iLs7dGSyjZiUgvrUvuD3FndAxVJk+TywBkkkwUSm9HdYoskJalWg5qVsEiXeufPvRVPbCUmNQewg798rx+sPXg==}
engines: {node: '>=20'}
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
loupe@3.2.1:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
@ -4521,6 +4649,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
media-engine@1.0.3:
resolution: {integrity: sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==}
media-typer@1.1.0:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'}
@ -4654,6 +4785,9 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
normalize-svg-path@1.1.0:
resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==}
normalize-url@8.1.1:
resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==}
engines: {node: '>=14.16'}
@ -4669,6 +4803,10 @@ packages:
nwsapi@2.2.23:
resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
@ -4717,6 +4855,12 @@ packages:
package-manager-detector@1.6.0:
resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
pako@0.2.9:
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -4733,6 +4877,9 @@ packages:
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
engines: {node: '>=18'}
parse-svg-path@0.1.2:
resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==}
parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
@ -4847,6 +4994,12 @@ packages:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
png-js@2.0.0:
resolution: {integrity: sha512-GdzJuUMc6ZSpxFJWVxtOH1bzYHym+TOnveqUjb+VJIbZWbZzyiRGFiKhbiielfpYbgMlhHVhsJ0FTazfuRFkMA==}
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
postcss@8.5.14:
resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
engines: {node: ^10 || ^12 || >=14}
@ -4912,6 +5065,9 @@ packages:
process-warning@5.0.0:
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@ -4930,6 +5086,9 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
queue@6.0.2:
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
@ -4957,6 +5116,9 @@ packages:
peerDependencies:
react: ^19.2.5
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
react-is@17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
@ -5080,6 +5242,10 @@ packages:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
@ -5103,6 +5269,9 @@ packages:
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
engines: {node: '>=18'}
restructure@3.0.2:
resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==}
retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
@ -5157,6 +5326,9 @@ packages:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
scheduler@0.25.0-rc-603e6108-20241029:
resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==}
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
@ -5389,6 +5561,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
svg-arc-to-cubic-bezier@3.2.0:
resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
@ -5440,6 +5615,9 @@ packages:
timekeeper@2.3.1:
resolution: {integrity: sha512-LeQRS7/4JcC0PgdSFnfUiStQEdiuySlCj/5SJ18D+T1n9BoY7PxKFfCwLulpHXoLUFr67HxBddQdEX47lDGx1g==}
tiny-inflate@1.0.3:
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@ -5594,6 +5772,12 @@ packages:
undici-types@7.19.2:
resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==}
unicode-properties@1.4.1:
resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==}
unicode-trie@2.0.0:
resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
unicorn-magic@0.3.0:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
@ -5664,6 +5848,10 @@ packages:
victory-vendor@37.3.6:
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
vite-compatible-readable-stream@3.6.1:
resolution: {integrity: sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==}
engines: {node: '>= 6'}
vite-node@3.2.4:
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@ -5892,6 +6080,9 @@ packages:
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
engines: {node: '>=18'}
yoga-layout@3.2.1:
resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==}
youch-core@0.3.3:
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
@ -7305,6 +7496,8 @@ snapshots:
'@tybys/wasm-util': 0.10.2
optional: true
'@noble/ciphers@1.3.0': {}
'@noble/hashes@1.8.0': {}
'@nodable/entities@2.1.0': {}
@ -7405,9 +7598,9 @@ snapshots:
pluralize: 8.0.0
slugify: 1.6.9
'@poppinss/ts-exec@1.4.4':
'@poppinss/ts-exec@1.4.4(@swc/helpers@0.5.21)':
dependencies:
'@swc/core': 1.15.33
'@swc/core': 1.15.33(@swc/helpers@0.5.21)
get-tsconfig: 4.14.0
transitivePeerDependencies:
- '@swc/helpers'
@ -7742,6 +7935,110 @@ snapshots:
'@radix-ui/rect@1.1.1': {}
'@react-pdf/fns@3.1.3': {}
'@react-pdf/font@4.0.8':
dependencies:
'@react-pdf/pdfkit': 5.1.1
'@react-pdf/types': 2.11.1
fontkit: 2.0.4
is-url: 1.2.4
'@react-pdf/image@3.1.0':
dependencies:
'@react-pdf/svg': 1.1.0
jay-peg: 1.1.1
png-js: 2.0.0
'@react-pdf/layout@4.6.1':
dependencies:
'@react-pdf/fns': 3.1.3
'@react-pdf/image': 3.1.0
'@react-pdf/primitives': 4.3.0
'@react-pdf/stylesheet': 6.2.1
'@react-pdf/textkit': 6.3.0
'@react-pdf/types': 2.11.1
emoji-regex-xs: 1.0.0
queue: 6.0.2
yoga-layout: 3.2.1
'@react-pdf/pdfkit@5.1.1':
dependencies:
'@babel/runtime': 7.29.2
'@noble/ciphers': 1.3.0
'@noble/hashes': 1.8.0
browserify-zlib: 0.2.0
fontkit: 2.0.4
jay-peg: 1.1.1
js-md5: 0.8.3
linebreak: 1.1.0
png-js: 2.0.0
vite-compatible-readable-stream: 3.6.1
'@react-pdf/primitives@4.3.0': {}
'@react-pdf/reconciler@2.0.0(react@19.2.5)':
dependencies:
object-assign: 4.1.1
react: 19.2.5
scheduler: 0.25.0-rc-603e6108-20241029
'@react-pdf/render@4.5.1':
dependencies:
'@babel/runtime': 7.29.2
'@react-pdf/fns': 3.1.3
'@react-pdf/primitives': 4.3.0
'@react-pdf/textkit': 6.3.0
'@react-pdf/types': 2.11.1
abs-svg-path: 0.1.1
color-string: 2.1.4
normalize-svg-path: 1.1.0
parse-svg-path: 0.1.2
svg-arc-to-cubic-bezier: 3.2.0
'@react-pdf/renderer@4.5.1(react@19.2.5)':
dependencies:
'@babel/runtime': 7.29.2
'@react-pdf/fns': 3.1.3
'@react-pdf/font': 4.0.8
'@react-pdf/layout': 4.6.1
'@react-pdf/pdfkit': 5.1.1
'@react-pdf/primitives': 4.3.0
'@react-pdf/reconciler': 2.0.0(react@19.2.5)
'@react-pdf/render': 4.5.1
'@react-pdf/types': 2.11.1
events: 3.3.0
object-assign: 4.1.1
prop-types: 15.8.1
queue: 6.0.2
react: 19.2.5
'@react-pdf/stylesheet@6.2.1':
dependencies:
'@react-pdf/fns': 3.1.3
'@react-pdf/types': 2.11.1
color-string: 2.1.4
hsl-to-hex: 1.0.0
media-engine: 1.0.3
postcss-value-parser: 4.2.0
'@react-pdf/svg@1.1.0':
dependencies:
'@react-pdf/primitives': 4.3.0
'@react-pdf/textkit@6.3.0':
dependencies:
'@react-pdf/fns': 3.1.3
bidi-js: 1.0.3
hyphen: 1.14.1
unicode-properties: 1.4.1
'@react-pdf/types@2.11.1':
dependencies:
'@react-pdf/font': 4.0.8
'@react-pdf/primitives': 4.3.0
'@react-pdf/stylesheet': 6.2.1
'@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1))(react@19.2.5)':
dependencies:
'@standard-schema/spec': 1.1.0
@ -8277,7 +8574,7 @@ snapshots:
'@swc/core-win32-x64-msvc@1.15.33':
optional: true
'@swc/core@1.15.33':
'@swc/core@1.15.33(@swc/helpers@0.5.21)':
dependencies:
'@swc/counter': 0.1.3
'@swc/types': 0.1.26
@ -8294,9 +8591,14 @@ snapshots:
'@swc/core-win32-arm64-msvc': 1.15.33
'@swc/core-win32-ia32-msvc': 1.15.33
'@swc/core-win32-x64-msvc': 1.15.33
'@swc/helpers': 0.5.21
'@swc/counter@0.1.3': {}
'@swc/helpers@0.5.21':
dependencies:
tslib: 2.8.1
'@swc/types@0.1.26':
dependencies:
'@swc/counter': 0.1.3
@ -8842,6 +9144,8 @@ snapshots:
loupe: 3.2.1
tinyrainbow: 2.0.0
abs-svg-path@0.1.1: {}
abstract-logging@2.0.1: {}
acorn-jsx@5.3.2(acorn@8.16.0):
@ -8921,6 +9225,8 @@ snapshots:
balanced-match@4.0.4: {}
base64-js@0.0.8: {}
base64-js@1.5.1: {}
baseline-browser-mapping@2.10.27: {}
@ -8934,6 +9240,10 @@ snapshots:
bindings: 1.5.0
prebuild-install: 7.1.3
bidi-js@1.0.3:
dependencies:
require-from-string: 2.0.2
binary-extensions@2.3.0: {}
bindings@1.5.0:
@ -8961,6 +9271,14 @@ snapshots:
dependencies:
fill-range: 7.1.1
brotli@1.3.3:
dependencies:
base64-js: 1.5.1
browserify-zlib@0.2.0:
dependencies:
pako: 1.0.11
browserslist@4.28.2:
dependencies:
baseline-browser-mapping: 2.10.27
@ -9103,6 +9421,8 @@ snapshots:
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
clone@2.1.2: {}
clsx@2.1.1: {}
cluster-key-slot@1.1.2: {}
@ -9115,6 +9435,12 @@ snapshots:
color-name@1.1.4: {}
color-name@2.1.0: {}
color-string@2.1.4:
dependencies:
color-name: 2.1.0
colorette@2.0.19: {}
colorette@2.0.20: {}
@ -9279,6 +9605,8 @@ snapshots:
asap: 2.0.6
wrappy: 1.0.2
dfa@1.2.0: {}
diff@8.0.4: {}
dlv@1.1.3: {}
@ -9303,6 +9631,8 @@ snapshots:
emittery@1.2.1: {}
emoji-regex-xs@1.0.0: {}
emoji-regex@10.6.0: {}
emoji-regex@8.0.0: {}
@ -9563,6 +9893,8 @@ snapshots:
eventemitter3@5.0.4: {}
events@3.3.0: {}
execa@8.0.1:
dependencies:
cross-spawn: 7.0.6
@ -9645,6 +9977,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.4
fflate@0.8.2: {}
figures@6.1.0:
dependencies:
is-unicode-supported: 2.1.0
@ -9699,6 +10033,18 @@ snapshots:
'@aws-sdk/client-s3': 3.1043.0
'@aws-sdk/s3-request-presigner': 3.1043.0
fontkit@2.0.4:
dependencies:
'@swc/helpers': 0.5.21
brotli: 1.3.3
clone: 2.1.2
dfa: 1.2.0
fast-deep-equal: 3.1.3
restructure: 3.0.2
tiny-inflate: 1.0.3
unicode-properties: 1.4.1
unicode-trie: 2.0.0
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
@ -9834,6 +10180,12 @@ snapshots:
picomatch: 4.0.4
read-package-up: 12.0.0
hsl-to-hex@1.0.0:
dependencies:
hsl-to-rgb-for-reals: 1.1.1
hsl-to-rgb-for-reals@1.1.1: {}
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
@ -9866,6 +10218,8 @@ snapshots:
husky@9.1.7: {}
hyphen@1.14.1: {}
ical-generator@10.2.0(@types/luxon@3.7.1)(@types/node@25.6.0)(dayjs@1.11.20)(luxon@3.7.2):
optionalDependencies:
'@types/luxon': 3.7.1
@ -9982,6 +10336,8 @@ snapshots:
is-unicode-supported@2.1.0: {}
is-url@1.2.4: {}
is-wsl@3.1.1:
dependencies:
is-inside-container: 1.0.0
@ -9990,6 +10346,10 @@ snapshots:
isexe@2.0.0: {}
jay-peg@1.1.1:
dependencies:
restructure: 3.0.2
jest-diff@30.3.0:
dependencies:
'@jest/diff-sequences': 30.3.0
@ -10001,6 +10361,8 @@ snapshots:
joycon@3.1.1: {}
js-md5@0.8.3: {}
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@ -10173,6 +10535,11 @@ snapshots:
lilconfig@3.1.3: {}
linebreak@1.1.0:
dependencies:
base64-js: 0.0.8
unicode-trie: 2.0.0
lint-staged@15.5.2:
dependencies:
chalk: 5.6.2
@ -10227,6 +10594,10 @@ snapshots:
strip-ansi: 7.2.0
wrap-ansi: 10.0.0
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
loupe@3.2.1: {}
lru-cache@10.4.3: {}
@ -10251,6 +10622,8 @@ snapshots:
math-intrinsics@1.1.0: {}
media-engine@1.0.3: {}
media-typer@1.1.0: {}
merge-stream@2.0.0: {}
@ -10374,6 +10747,10 @@ snapshots:
normalize-path@3.0.0: {}
normalize-svg-path@1.1.0:
dependencies:
svg-arc-to-cubic-bezier: 3.2.0
normalize-url@8.1.1: {}
npm-run-path@5.3.0:
@ -10387,6 +10764,8 @@ snapshots:
nwsapi@2.2.23: {}
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
object-to-formdata@4.5.1: {}
@ -10439,6 +10818,10 @@ snapshots:
package-manager-detector@1.6.0: {}
pako@0.2.9: {}
pako@1.0.11: {}
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@ -10456,6 +10839,8 @@ snapshots:
parse-ms@4.0.0: {}
parse-svg-path@0.1.2: {}
parse5@7.3.0:
dependencies:
entities: 6.0.1
@ -10567,6 +10952,12 @@ snapshots:
pluralize@8.0.0: {}
png-js@2.0.0:
dependencies:
fflate: 0.8.2
postcss-value-parser@4.2.0: {}
postcss@8.5.14:
dependencies:
nanoid: 3.3.12
@ -10635,6 +11026,12 @@ snapshots:
process-warning@5.0.0: {}
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
@ -10653,6 +11050,10 @@ snapshots:
queue-microtask@1.2.3: {}
queue@6.0.2:
dependencies:
inherits: 2.0.4
quick-format-unescaped@4.0.4: {}
random-bytes@1.0.0: {}
@ -10680,6 +11081,8 @@ snapshots:
react: 19.2.5
scheduler: 0.27.0
react-is@16.13.1: {}
react-is@17.0.2: {}
react-is@18.3.1: {}
@ -10801,6 +11204,8 @@ snapshots:
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
reselect@5.1.1: {}
resolve-from@4.0.0: {}
@ -10821,6 +11226,8 @@ snapshots:
onetime: 7.0.0
signal-exit: 4.1.0
restructure@3.0.2: {}
retry@0.13.1: {}
rettime@0.11.11: {}
@ -10903,6 +11310,8 @@ snapshots:
dependencies:
xmlchars: 2.2.0
scheduler@0.25.0-rc-603e6108-20241029: {}
scheduler@0.27.0: {}
secure-json-parse@4.1.0: {}
@ -11133,6 +11542,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
svg-arc-to-cubic-bezier@3.2.0: {}
symbol-tree@3.2.4: {}
synckit@0.11.12:
@ -11176,6 +11587,8 @@ snapshots:
timekeeper@2.3.1: {}
tiny-inflate@1.0.3: {}
tiny-invariant@1.3.3: {}
tinybench@2.9.0: {}
@ -11311,6 +11724,16 @@ snapshots:
undici-types@7.19.2: {}
unicode-properties@1.4.1:
dependencies:
base64-js: 1.5.1
unicode-trie: 2.0.0
unicode-trie@2.0.0:
dependencies:
pako: 0.2.9
tiny-inflate: 1.0.3
unicorn-magic@0.3.0: {}
unicorn-magic@0.4.0: {}
@ -11382,6 +11805,12 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
vite-compatible-readable-stream@3.6.1:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
vite-node@3.2.4(@types/node@24.12.2)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.4):
dependencies:
cac: 6.7.14
@ -11563,6 +11992,8 @@ snapshots:
yoctocolors@2.1.2: {}
yoga-layout@3.2.1: {}
youch-core@0.3.3:
dependencies:
'@poppinss/exception': 1.2.3