diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef17b272..a4d2035d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,87 @@ # Changelog +## [1.46.6] — 2026-11-02 + +### Added + +- **Lab values without a unit.** Ratios and indices such as INR, + cholesterol/HDL or albumin/globulin had nowhere to go: manual entry, the + CSV import and the document review all required a unit. Entry, the + scanned-report rows and the document review now offer an explicit "No + unit" choice, stored as the UCUM unity `"1"`, and the CSV import reads + `1` in the unit column the same way. An empty unit is still refused, so + a unit the reading lost is not mistaken for none, and a document read + that answers "no unit" by itself is held for review. Such a value shows + as the number alone, a marker kept in a real unit refuses it, and the + FHIR export codes it as UCUM `1`. (#1313) +- **MCP reads follow their links.** Lab readings in `get_labs` and + `fetch lab:` list the documents and visits they are linked to, with the + linked records once per answer instead of on every reading of the same + report. `fetch med:` and `get_medication_schedule` list theirs, and + `fetch document:` now also names the lab results and medications filed + against it. Rows of `get_visits`, `get_medication_schedule` and + `get_illness_recovery` carry an id `fetch` takes. An imported document + names its source system and id, never the address of the instance it + came from. (#1323) + +### Fixed + +- **A refused lab value can be corrected in the review.** A value that + Finish review refused, such as a ratio printed without a unit or a unit + that disagrees with the marker, showed the reason but could only be + discarded. The row now offers the same Check control as a low-confidence + value. (#1313, #1327) +- **The doctor report prints every language.** The PDF used a built-in + font that covers Western European letters only, so Polish letters such + as ą, ł or ś, the whole Korean report, and any medication name or note in + another script printed as empty boxes. The report now embeds an open + Unicode font family covering Latin, Greek, Cyrillic and, when the report + needs it, Korean, and arrows, ≤ and ² print as themselves instead of + ASCII stand-ins. The file is compressed, so a report stays around + 65 KB. Chinese, Japanese and Arabic text are not covered yet. +- **PDFs read on a Raspberry Pi 4.** The native canvas build for arm64 + Alpine needs CPU features an ARMv8.0 core lacks, and loading it ended + every PDF read with an illegal instruction. The CPU check now covers that + case, and PDF reading carries on without the canvas, so the text layer + and the index work; thumbnails keep their existing fallback. (#1311) +- **The display name greets you.** The dashboard and Insights greetings, + the top bar and the sidebar showed the username even when a display name + was set. They now use the display name and fall back to the username. + (#1309) +- **Summaries count every reading right after an import.** A type whose + history was not folded yet counted as covered as soon as one day was, so + a summary could show one day of weight readings out of three. A type now + counts as covered only when its folded days reach back to its oldest + reading. +- **The repeated hour of a clock change stays two hours.** On the night + the clocks go back, a dense pulse or glucose chart folded both runs of + the repeated hour into one point. Each hour is its own point now. +- **Google Health heals a connection that lost its account id.** The + 1.46.4 update cleared a placeholder id on existing connections. After a + clean sync such a connection now reads its real id back, so the + one-account-per-profile check covers it again. +- **WHOOP refuses a sign-in without a user id** instead of storing the + text "undefined" as the account. + +### Changed + +- Next.js 16.4.3 and the weekly dependency updates. node-forge, reached + through the APNs client, is raised to 1.4.2, which closes five high + advisories. + +### Thanks + +- @johnnyrepo026 for the precise report on unitless lab ratios (#1313), + with the cause already traced to the right two files, and for the pull + request that fixed the review half of it (#1327). +- @mbreitkreuz for the MCP linked-records request (#1323), a careful spec + with the real case that made date matching fail. +- @Oguz3003 for tracking the Raspberry Pi 4 crash down to the CPU and + confirming the workaround (#1311). +- @angusmaul for noticing the greeting ignored the display name (#1309). +- @mills1975 for the heart-rate sync report and the diagnostics that + pinned it to the iPhone app (#1326); the fix follows in an app update. + ## [1.46.5] — 2026-10-30 ### Fixed diff --git a/Dockerfile b/Dockerfile index 9290eedd1..37143e516 100644 --- a/Dockerfile +++ b/Dockerfile @@ -312,7 +312,7 @@ RUN mkdir -p /opt/prisma-cli && \ npm pkg set 'overrides.mysql2=^3.22.0' && \ npm pkg set 'overrides.@hono/node-server=^1.19.15' && \ npm pkg set 'overrides.valibot=^1.4.2' && \ - npm install --omit=dev prisma@7.10.1 @prisma/engines@7.10.1 tsx@4.23.1 dotenv@18.0.8 && \ + npm install --omit=dev prisma@7.10.1 @prisma/engines@7.10.1 tsx@4.23.1 dotenv@18.0.9 && \ ln -sfn /opt/prisma-cli/node_modules/.bin/tsx /usr/local/bin/healthlog-tsx && \ ln -sfn /opt/prisma-cli/node_modules/dotenv /app/node_modules/dotenv && \ ln -sfn /opt/prisma-cli/node_modules/prisma /app/node_modules/prisma && \ diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index fa60753c9..4effebec6 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: HealthLog API - version: 1.46.5 + version: 1.46.6 description: >- Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest. @@ -15883,10 +15883,11 @@ paths: checks an hour, the import itself the shared 5-an-hour `import:` bucket. Owner only; refused with `module.disabled` when the module is switched off. An unknown query parameter is refused with 422, so a misspelt `dryRun` never writes. Each row's name resolves to the account's marker the way a scanned report's rows do - (name, alias, catalog name); a new analyte mints one marker from its first row. A numeric result needs a unit; - one in another unit is converted when the conversion is known and keeps the printed value beside it, otherwise - the row is refused with `unit_mismatch`. Any other text in the value column is a qualitative result. A date - without a time is stored as that calendar date. At most 20 000 data rows." + (name, alias, catalog name); a new analyte mints one marker from its first row. A numeric result needs a unit: + an empty unit cell is refused with `missing_unit`, and `1` (the UCUM unity) states a value without a unit, such + as a ratio or INR. A result in another unit is converted when the conversion is known and keeps the printed + value beside it, otherwise the row is refused with `unit_mismatch`. Any other text in the value column is a + qualitative result. A date without a time is stored as that calendar date. At most 20 000 data rows." parameters: - in: query name: dryRun @@ -34160,6 +34161,11 @@ components: minLength: 1 maxLength: 120 unit: + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' type: string minLength: 1 maxLength: 40 @@ -34229,6 +34235,11 @@ components: minLength: 1 maxLength: 120 unit: + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' type: string minLength: 1 maxLength: 40 @@ -34323,6 +34334,11 @@ components: minLength: 1 maxLength: 120 unit: + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice + and a unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker + kept in a real unit and the other way round. Clients show nothing beside such a value. An empty unit + on a numeric value is never read as `"1"` and stays refused.' type: string minLength: 1 maxLength: 40 @@ -34377,6 +34393,11 @@ components: type: string minLength: 1 maxLength: 40 + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' lowerBound: type: number upperBound: @@ -34406,6 +34427,11 @@ components: minLength: 1 maxLength: 120 unit: + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' type: string minLength: 1 maxLength: 40 @@ -35774,6 +35800,11 @@ components: maxLength: 300 - type: "null" unit: + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and + a unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in + a real unit and the other way round. Clients show nothing beside such a value. An empty unit on a + numeric value is never read as `"1"` and stays refused.' anyOf: - type: string maxLength: 80 @@ -75294,6 +75325,11 @@ components: - "null" unit: type: string + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' converted: type: boolean sourceValue: @@ -75543,6 +75579,11 @@ components: - "null" unit: type: string + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' converted: type: boolean sourceValue: @@ -76522,6 +76563,11 @@ components: type: string unit: type: string + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' lowerBound: type: - number @@ -76621,6 +76667,11 @@ components: type: string unit: type: string + description: 'The unit the value is in, free-form as the report prints it (e.g. `mg/dL`). `"1"`, the UCUM unity, means + the value has no unit: a ratio or an index such as INR or cholesterol/HDL. It is an explicit choice and a + unit of its own: it matches only `"1"`, so a reading without a unit is refused under a marker kept in a real + unit and the other way round. Clients show nothing beside such a value. An empty unit on a numeric value is + never read as `"1"` and stays refused.' lowerBound: type: - number diff --git a/messages/de.json b/messages/de.json index 1614425f1..3c914dfc9 100644 --- a/messages/de.json +++ b/messages/de.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "PDF-Scannen benötigt einen Claude-Bildanbieter; lade stattdessen ein Foto hoch.", "refTextLabel": "Bereich wie gedruckt", "refTextPlaceholder": "z. B. 3,5 - 5,0", - "aiUnavailable": "Das Scannen eines Befunds mit KI ist hier gerade nicht verfügbar." + "aiUnavailable": "Das Scannen eines Befunds mit KI ist hier gerade nicht verfügbar.", + "errorUnitMismatchNoUnit": "Dieser Marker wird ohne Einheit geführt. Setz das Häkchen bei Keine Einheit, falls der Befund falsch gelesen wurde, oder wähle den Wert ab.", + "unitDiffersBadgeNoUnit": "Ohne Einheit geführt; dieser Befund nennt {unit}" }, "loadMoreReadings": "Weitere Werte laden", "documentsLink": "Befund-Dokumente", @@ -10474,6 +10476,10 @@ "stale": "Der neueste Wert ist vom {date}, also älter als ein Jahr. Die Gerade gilt für diesen Stand, ohne Projektion." }, "interval": "95-%-Intervall der jährlichen Veränderung: {lo} bis {hi} {unit}." + }, + "unit": { + "none": "Keine Einheit", + "noneHint": "Für einen Quotienten oder Index wie INR oder Cholesterin/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "Bei Bedarf", "startsOn": "Beginn", "endsOn": "Ende" - } + }, + "unitlessHint": "Ein Quotient oder Index ohne Einheit (INR, Cholesterin/HDL): Trag in der Spalte für die Einheit eine 1 ein. Eine leere Einheit bleibt ein Fehler." } } diff --git a/messages/en.json b/messages/en.json index 0b9a78b16..aea2d6a89 100644 --- a/messages/en.json +++ b/messages/en.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "PDF scanning needs a Claude vision provider; upload a photo instead.", "refTextLabel": "Range as printed", "refTextPlaceholder": "e.g. 3.5 - 5.0", - "aiUnavailable": "Scanning a report with AI is not available here right now." + "aiUnavailable": "Scanning a report with AI is not available here right now.", + "errorUnitMismatchNoUnit": "This marker is tracked without a unit. Tick No unit if the report was misread, or deselect this reading.", + "unitDiffersBadgeNoUnit": "Tracked without a unit; this report says {unit}" }, "loadMoreReadings": "Load more readings", "documentsLink": "Lab report documents", @@ -10474,6 +10476,10 @@ "stale": "The newest reading is from {date}, more than a year ago. The line is shown as of then, without a projection." }, "interval": "95 % interval of the yearly change: {lo} to {hi} {unit}." + }, + "unit": { + "none": "No unit", + "noneHint": "For a ratio or an index such as INR or cholesterol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "As needed", "startsOn": "Start", "endsOn": "End" - } + }, + "unitlessHint": "A ratio or an index without a unit (INR, cholesterol/HDL): write 1 in the unit column. An empty unit cell stays an error." } } diff --git a/messages/es.json b/messages/es.json index 494161998..a729ed506 100644 --- a/messages/es.json +++ b/messages/es.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "El escaneo de PDF necesita un proveedor de visión de Claude; sube una foto en su lugar.", "refTextLabel": "Rango tal como aparece", "refTextPlaceholder": "p. ej. 3,5 - 5,0", - "aiUnavailable": "Escanear un informe con IA no está disponible aquí ahora mismo." + "aiUnavailable": "Escanear un informe con IA no está disponible aquí ahora mismo.", + "errorUnitMismatchNoUnit": "Este marcador se registra sin unidad. Marca Sin unidad si el informe se leyó mal o deselecciona este valor.", + "unitDiffersBadgeNoUnit": "Registrado sin unidad; este informe indica {unit}" }, "loadMoreReadings": "Cargar más mediciones", "documentsLink": "Documentos de resultados", @@ -10474,6 +10476,10 @@ "stale": "El valor más reciente es del {date}, hace más de un año. La línea se muestra a esa fecha, sin proyección." }, "interval": "Intervalo del 95 % del cambio anual: de {lo} a {hi} {unit}." + }, + "unit": { + "none": "Sin unidad", + "noneHint": "Para un cociente o un índice como el INR o colesterol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "A demanda", "startsOn": "Inicio", "endsOn": "Fin" - } + }, + "unitlessHint": "Un cociente o un índice sin unidad (INR, colesterol/HDL): escribe 1 en la columna de la unidad. Una unidad vacía sigue siendo un error." } } diff --git a/messages/fr.json b/messages/fr.json index 3cf6c27ec..130a2dcec 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "Le scan PDF nécessite un fournisseur de vision Claude ; importez plutôt une photo.", "refTextLabel": "Plage telle qu'imprimée", "refTextPlaceholder": "p. ex. 3,5 - 5,0", - "aiUnavailable": "La numérisation d'un compte rendu par IA n'est pas disponible ici pour le moment." + "aiUnavailable": "La numérisation d'un compte rendu par IA n'est pas disponible ici pour le moment.", + "errorUnitMismatchNoUnit": "Ce marqueur est suivi sans unité. Cochez Sans unité si le compte rendu a été mal lu, ou désélectionnez cette valeur.", + "unitDiffersBadgeNoUnit": "Suivi sans unité ; ce compte rendu indique {unit}" }, "loadMoreReadings": "Charger plus de mesures", "documentsLink": "Documents de résultats", @@ -10474,6 +10476,10 @@ "stale": "La valeur la plus récente date du {date}, il y a plus d’un an. La droite est montrée à cette date, sans projection." }, "interval": "Intervalle à 95 % de la variation annuelle : de {lo} à {hi} {unit}." + }, + "unit": { + "none": "Sans unité", + "noneHint": "Pour un rapport ou un indice comme l'INR ou cholestérol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "Si besoin", "startsOn": "Début", "endsOn": "Fin" - } + }, + "unitlessHint": "Un rapport ou un indice sans unité (INR, cholestérol/HDL) : inscrivez 1 dans la colonne de l'unité. Une unité vide reste une erreur." } } diff --git a/messages/it.json b/messages/it.json index f72bbde59..7c417dc4c 100644 --- a/messages/it.json +++ b/messages/it.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "La scansione PDF richiede un provider di visione Claude; carica invece una foto.", "refTextLabel": "Intervallo come stampato", "refTextPlaceholder": "es. 3,5 - 5,0", - "aiUnavailable": "La scansione di un referto con IA non è disponibile qui al momento." + "aiUnavailable": "La scansione di un referto con IA non è disponibile qui al momento.", + "errorUnitMismatchNoUnit": "Questo marcatore è registrato senza unità. Spunta Nessuna unità se il referto è stato letto male, oppure deseleziona questo valore.", + "unitDiffersBadgeNoUnit": "Registrato senza unità; questo referto indica {unit}" }, "loadMoreReadings": "Carica altre misurazioni", "documentsLink": "Documenti dei referti", @@ -10474,6 +10476,10 @@ "stale": "Il valore più recente è del {date}, più di un anno fa. La retta è mostrata a quella data, senza proiezione." }, "interval": "Intervallo al 95 % della variazione annua: da {lo} a {hi} {unit}." + }, + "unit": { + "none": "Nessuna unità", + "noneHint": "Per un rapporto o un indice come l'INR o colesterolo/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "Al bisogno", "startsOn": "Inizio", "endsOn": "Fine" - } + }, + "unitlessHint": "Un rapporto o un indice senza unità (INR, colesterolo/HDL): scrivi 1 nella colonna dell'unità. Un'unità vuota resta un errore." } } diff --git a/messages/ko.json b/messages/ko.json index fa858cc6a..6687f8fd6 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "PDF 스캔에는 Claude 비전 제공자가 필요해요. 대신 사진을 올려 주세요.", "refTextLabel": "적힌 그대로의 범위", "refTextPlaceholder": "예: 3.5 - 5.0", - "aiUnavailable": "지금 여기에서는 AI로 결과지를 스캔할 수 없습니다." + "aiUnavailable": "지금 여기에서는 AI로 결과지를 스캔할 수 없습니다.", + "errorUnitMismatchNoUnit": "이 지표는 단위 없이 기록됩니다. 결과지를 잘못 읽었다면 단위 없음을 선택하거나 이 값의 선택을 해제하세요.", + "unitDiffersBadgeNoUnit": "단위 없이 기록 중; 이 결과지는 {unit}" }, "loadMoreReadings": "측정값 더 보기", "documentsLink": "검사 결과지 문서", @@ -10474,6 +10476,10 @@ "stale": "가장 최근 값은 {date}로 1년이 넘었습니다. 직선은 그 시점 기준으로 표시하며 예측은 하지 않습니다." }, "interval": "연간 변화의 95% 구간: {lo}~{hi} {unit}." + }, + "unit": { + "none": "단위 없음", + "noneHint": "INR이나 콜레스테롤/HDL 같은 비율 또는 지수에 사용해요." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "필요시", "startsOn": "시작", "endsOn": "종료" - } + }, + "unitlessHint": "단위가 없는 비율이나 지수(INR, 콜레스테롤/HDL)는 단위 열에 1을 입력하세요. 단위 칸이 비어 있으면 여전히 오류예요." } } diff --git a/messages/nl.json b/messages/nl.json index 0d7a0de24..17aefb7de 100644 --- a/messages/nl.json +++ b/messages/nl.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "Voor het scannen van PDF's is een Claude-provider met beeldherkenning nodig; upload in plaats daarvan een foto.", "refTextLabel": "Bereik zoals afgedrukt", "refTextPlaceholder": "bijv. 3,5 - 5,0", - "aiUnavailable": "Een rapport scannen met AI is hier op dit moment niet beschikbaar." + "aiUnavailable": "Een rapport scannen met AI is hier op dit moment niet beschikbaar.", + "errorUnitMismatchNoUnit": "Deze marker wordt zonder eenheid bijgehouden. Vink Geen eenheid aan als het rapport verkeerd is gelezen, of deselecteer deze meting.", + "unitDiffersBadgeNoUnit": "Zonder eenheid bijgehouden; dit rapport vermeldt {unit}" }, "loadMoreReadings": "Meer metingen laden", "documentsLink": "Documenten met labrapporten", @@ -10474,6 +10476,10 @@ "stale": "De nieuwste waarde is van {date}, meer dan een jaar geleden. De lijn staat op die datum, zonder projectie." }, "interval": "95%-interval van de jaarlijkse verandering: {lo} tot {hi} {unit}." + }, + "unit": { + "none": "Geen eenheid", + "noneHint": "Voor een verhouding of index zoals INR of cholesterol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "Zo nodig", "startsOn": "Begin", "endsOn": "Einde" - } + }, + "unitlessHint": "Een verhouding of index zonder eenheid (INR, cholesterol/HDL): vul 1 in de eenheidskolom in. Een lege eenheid blijft een fout." } } diff --git a/messages/pl.json b/messages/pl.json index 03b936c1b..5132eeb8a 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "Skanowanie PDF wymaga dostawcy wizji Claude; prześlij zamiast tego zdjęcie.", "refTextLabel": "Zakres tak jak wydrukowano", "refTextPlaceholder": "np. 3,5 - 5,0", - "aiUnavailable": "Skanowanie wyniku przez AI jest tu teraz niedostępne." + "aiUnavailable": "Skanowanie wyniku przez AI jest tu teraz niedostępne.", + "errorUnitMismatchNoUnit": "Ten wskaźnik jest prowadzony bez jednostki. Zaznacz Bez jednostki, jeśli wynik został źle odczytany, albo odznacz tę wartość.", + "unitDiffersBadgeNoUnit": "Prowadzony bez jednostki; ten wynik podaje {unit}" }, "loadMoreReadings": "Wczytaj więcej pomiarów", "documentsLink": "Dokumenty wyników badań", @@ -10474,6 +10476,10 @@ "stale": "Najnowszy wynik pochodzi z {date}, sprzed ponad roku. Prosta jest pokazana na ten dzień, bez projekcji." }, "interval": "95% przedział rocznej zmiany: od {lo} do {hi} {unit}." + }, + "unit": { + "none": "Bez jednostki", + "noneHint": "Dla ilorazu lub wskaźnika, np. INR albo cholesterol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "W razie potrzeby", "startsOn": "Początek", "endsOn": "Koniec" - } + }, + "unitlessHint": "Iloraz lub wskaźnik bez jednostki (INR, cholesterol/HDL): wpisz 1 w kolumnie jednostki. Pusta jednostka nadal jest błędem." } } diff --git a/messages/pt-BR.json b/messages/pt-BR.json index d3a4ecb84..d8d87e84b 100644 --- a/messages/pt-BR.json +++ b/messages/pt-BR.json @@ -10396,7 +10396,9 @@ "pdfNeedsAnthropic": "A digitalização de PDF precisa de um provedor de visão Claude; envie uma foto em vez disso.", "refTextLabel": "Faixa como impressa", "refTextPlaceholder": "ex.: 3,5 - 5,0", - "aiUnavailable": "Digitalizar um laudo com IA não está disponível aqui agora." + "aiUnavailable": "Digitalizar um laudo com IA não está disponível aqui agora.", + "errorUnitMismatchNoUnit": "Este marcador é acompanhado sem unidade. Marque Sem unidade se o laudo foi lido errado, ou desmarque esta leitura.", + "unitDiffersBadgeNoUnit": "Acompanhado sem unidade; este laudo diz {unit}" }, "loadMoreReadings": "Carregar mais leituras", "documentsLink": "Documentos de laudos laboratoriais", @@ -10474,6 +10476,10 @@ "stale": "O resultado mais recente é de {date}, há mais de um ano. A linha é mostrada até essa data, sem projeção." }, "interval": "Intervalo de 95 % da mudança anual: {lo} a {hi} {unit}." + }, + "unit": { + "none": "Sem unidade", + "noneHint": "Para uma razão ou um índice como INR ou colesterol/HDL." } }, "modules": { @@ -14093,6 +14099,7 @@ "asNeeded": "Conforme necessário", "startsOn": "Início", "endsOn": "Fim" - } + }, + "unitlessHint": "Uma razão ou um índice sem unidade (INR, colesterol/HDL): escreva 1 na coluna da unidade. Uma unidade vazia continua sendo um erro." } } diff --git a/messages/ru.json b/messages/ru.json index 0f2fcd695..eb72045fb 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -10381,7 +10381,9 @@ "errorResult": "Укажите результат.", "errorUnit": "Укажите единицу.", "errorUnitMismatch": "Этот показатель отслеживается в {markerUnit}. Измените единицу, если отчёт прочитан неверно, или снимите выбор с этого измерения.", + "errorUnitMismatchNoUnit": "Этот показатель отслеживается без единицы. Поставьте галочку «Без единицы», если отчёт прочитан неверно, или снимите выбор с этого измерения.", "unitDiffersBadge": "Отслеживается в {markerUnit}; в этом отчёте указано {unit}", + "unitDiffersBadgeNoUnit": "Отслеживается без единицы; в этом отчёте указано {unit}", "unitConvertedBadge": "Сохранено как {value} {markerUnit}, пересчитано из {statedValue} {unit}", "savedPartialUnitToast": "Сохранено результатов анализа: {count}. Не сохранено из-за несовпадения единицы с показателем: {analytes}", "savedNothingUnitToast": "Ничего не сохранено: единица не совпадает с показателем для {analytes}", @@ -10474,6 +10476,10 @@ "stale": "Самое новое измерение — от {date}, более года назад. Линия показана по состоянию на тот момент, без прогноза." }, "interval": "95 % интервал годового изменения: от {lo} до {hi} {unit}." + }, + "unit": { + "none": "Без единицы", + "noneHint": "Для коэффициента или индекса, например МНО или холестерин/ЛПВП." } }, "modules": { @@ -14028,6 +14034,7 @@ "dot": "Точка (5.4)", "comma": "Запятая (5,4)" }, + "unitlessHint": "Коэффициент или индекс без единицы (МНО, холестерин/ЛПВП): напишите 1 в столбце единицы. Пустая ячейка единицы остаётся ошибкой.", "dateOrder": "Формат даты", "dateOrderOption": { "iso": "2025-03-01", diff --git a/next.config.ts b/next.config.ts index 013e81c7a..a4813cdab 100644 --- a/next.config.ts +++ b/next.config.ts @@ -309,6 +309,9 @@ const nextConfig: NextConfig = { "./src/lib/documents/pdf-child.mjs", "./src/lib/documents/pdf-engine.mjs", "./src/lib/documents/image-engine.mjs", + // The doctor-report PDF embeds its fonts, read from disk by a path the + // tracer cannot follow (`src/lib/doctor-report-pdf/fonts.ts`). + "./src/lib/doctor-report-pdf/fonts/**", // Document AI local text extraction and rasterization both run the // app's one pdfjs-dist (`src/lib/documents/pdfjs.ts`) server-side; the // text read is the provider-free fallback that keeps content search diff --git a/package.json b/package.json index 6368ffab5..0da3bb19f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "healthlog", - "version": "1.46.5", + "version": "1.46.6", "description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.", "license": "PolyForm-Noncommercial-1.0.0", "homepage": "https://healthlog.dev", @@ -54,34 +54,34 @@ "mcp:stdio": "npx tsx src/cli/mcp-stdio.ts" }, "dependencies": { - "@aws-sdk/client-s3": "^3.1155.0", - "@aws-sdk/lib-storage": "3.1155.0", + "@aws-sdk/client-s3": "^3.1159.0", + "@aws-sdk/lib-storage": "3.1159.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@modelcontextprotocol/sdk": "^1.32.1", + "@modelcontextprotocol/sdk": "^1.32.2", "@napi-rs/canvas": "1.0.13", "@node-rs/argon2": "^2.2.2", - "@parse/node-apn": "^8.1.0", + "@parse/node-apn": "^8.1.1", "@prisma/adapter-pg": "^7.10.1", "@prisma/client": "^7.10.1", "@simplewebauthn/browser": "^14.0.0", "@simplewebauthn/server": "^14.0.3", - "@tanstack/react-query": "5.104.5", - "@tanstack/react-virtual": "^3.14.22", + "@tanstack/react-query": "5.105.0", + "@tanstack/react-virtual": "^3.14.25", "@types/sax": "^1.2.7", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.4.0", - "dotenv": "^18.0.8", + "dotenv": "^18.0.9", "fflate": "^0.8.3", - "jose": "^6.2.13", + "jose": "^6.2.14", "jspdf": "^4.2.1", "jspdf-autotable": "^5.0.9", - "lucide-react": "^1.61.0", + "lucide-react": "^1.66.0", "mmdb-lib": "^3.0.3", - "next": "16.4.2", - "nodemailer": "10.2.1", + "next": "16.4.3", + "nodemailer": "10.3.1", "otpauth": "^9.5.2", "p-limit": "^7.3.3", "pg": "^8.23.1", @@ -107,15 +107,15 @@ }, "devDependencies": { "@axe-core/playwright": "^4.14.0", - "@next/bundle-analyzer": "16.4.2", + "@next/bundle-analyzer": "16.4.3", "@playwright/test": "^1.64.1", - "@stryker-mutator/core": "10.0.0", + "@stryker-mutator/core": "10.1.1", "@stryker-mutator/vitest-runner": "10.0.0", "@tailwindcss/postcss": "^4", "@tesseract.js-data/deu": "1.0.0", "@tesseract.js-data/eng": "1.0.0", "@testcontainers/postgresql": "^12.2.1", - "@types/node": "26.6.5", + "@types/node": "26.6.6", "@types/pg": "^8.23.1", "@types/qrcode": "^1.5.6", "@types/react": "^19.3.0", @@ -125,14 +125,14 @@ "@vitest/coverage-v8": "^5.0.5", "ajv": "^8.20.0", "eslint": "^9", - "eslint-config-next": "16.4.2", + "eslint-config-next": "16.4.3", "fast-check": "4.10.2", - "knip": "^6.42.0", + "knip": "^6.44.1", "lefthook": "^2.2.2", "pdfjs-dist": "6.4.299", "prettier": "^3.9.10", "prettier-plugin-tailwindcss": "^0.8.1", - "shadcn": "^4.22.1", + "shadcn": "^4.23.0", "tailwindcss": "^4", "testcontainers": "^12.2.1", "tw-animate-css": "^1.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18b066b1a..1c07cb070 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,11 +46,11 @@ importers: .: dependencies: '@aws-sdk/client-s3': - specifier: ^3.1155.0 - version: 3.1155.0 + specifier: ^3.1159.0 + version: 3.1159.0 '@aws-sdk/lib-storage': - specifier: 3.1155.0 - version: 3.1155.0(@aws-sdk/client-s3@3.1155.0) + specifier: 3.1159.0 + version: 3.1159.0(@aws-sdk/client-s3@3.1159.0) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1) @@ -61,8 +61,8 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.3.1) '@modelcontextprotocol/sdk': - specifier: ^1.32.1 - version: 1.32.1(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.6.7) + specifier: ^1.32.2 + version: 1.32.2(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.6.7) '@napi-rs/canvas': specifier: 1.0.13 version: 1.0.13 @@ -70,14 +70,14 @@ importers: specifier: ^2.2.2 version: 2.2.2 '@parse/node-apn': - specifier: ^8.1.0 - version: 8.1.0(supports-color@7.2.0) + specifier: ^8.1.1 + version: 8.1.1(supports-color@7.2.0) '@prisma/adapter-pg': specifier: ^7.10.1 version: 7.10.1 '@prisma/client': specifier: ^7.10.1 - version: 7.10.1(prisma@7.10.1(@types/node@26.6.5)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3))(typescript@6.0.3) + version: 7.10.1(prisma@7.10.1(@types/node@26.6.6)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3))(typescript@6.0.3) '@simplewebauthn/browser': specifier: ^14.0.0 version: 14.0.0 @@ -85,11 +85,11 @@ importers: specifier: ^14.0.3 version: 14.0.3 '@tanstack/react-query': - specifier: 5.104.5 - version: 5.104.5(@types/react@19.3.0)(react@19.3.1) + specifier: 5.105.0 + version: 5.105.0(@types/react@19.3.0)(react@19.3.1) '@tanstack/react-virtual': - specifier: ^3.14.22 - version: 3.14.22(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + specifier: ^3.14.25 + version: 3.14.25(react-dom@19.3.1(react@19.3.1))(react@19.3.1) '@types/sax': specifier: ^1.2.7 version: 1.2.7 @@ -103,14 +103,14 @@ importers: specifier: ^4.4.0 version: 4.4.0 dotenv: - specifier: ^18.0.8 - version: 18.0.8 + specifier: ^18.0.9 + version: 18.0.9 fflate: specifier: ^0.8.3 version: 0.8.3 jose: - specifier: ^6.2.13 - version: 6.2.13 + specifier: ^6.2.14 + version: 6.2.14 jspdf: specifier: ^4.2.1 version: 4.2.1 @@ -118,17 +118,17 @@ importers: specifier: ^5.0.9 version: 5.0.9(jspdf@4.2.1) lucide-react: - specifier: ^1.61.0 - version: 1.61.0(@types/react@19.3.0)(react@19.3.1) + specifier: ^1.66.0 + version: 1.66.0(@types/react@19.3.0)(react@19.3.1) mmdb-lib: specifier: ^3.0.3 version: 3.0.3 next: - specifier: 16.4.2 - version: 16.4.2(@babel/core@7.29.7(supports-color@7.2.0))(@opentelemetry/api@1.9.1)(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + specifier: 16.4.3 + version: 16.4.3(@babel/core@8.0.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.64.1)(@types/node@26.6.6)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) nodemailer: - specifier: 10.2.1 - version: 10.2.1 + specifier: 10.3.1 + version: 10.3.1 otpauth: specifier: ^9.5.2 version: 9.5.2 @@ -143,7 +143,7 @@ importers: version: 12.38.0(@opentelemetry/api@1.9.1) prisma: specifier: ^7.10.1 - version: 7.10.1(@types/node@26.6.5)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3) + version: 7.10.1(@types/node@26.6.6)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3) qrcode: specifier: ^1.5.4 version: 1.5.4 @@ -200,17 +200,17 @@ importers: specifier: ^4.14.0 version: 4.14.0(playwright-core@1.64.1) '@next/bundle-analyzer': - specifier: 16.4.2 - version: 16.4.2 + specifier: 16.4.3 + version: 16.4.3 '@playwright/test': specifier: ^1.64.1 version: 1.64.1 '@stryker-mutator/core': - specifier: 10.0.0 - version: 10.0.0(@types/node@26.6.5) + specifier: 10.1.1 + version: 10.1.1(@types/node@26.6.6) '@stryker-mutator/vitest-runner': specifier: 10.0.0 - version: 10.0.0(patch_hash=9ad3e9855fd9781fd36e872ed42c5f934f91b962d6830e6cc56d56bf16e1dabd)(@stryker-mutator/core@10.0.0(@types/node@26.6.5))(vitest@5.0.5) + version: 10.0.0(patch_hash=9ad3e9855fd9781fd36e872ed42c5f934f91b962d6830e6cc56d56bf16e1dabd)(@stryker-mutator/core@10.1.1(@types/node@26.6.6))(vitest@5.0.5) '@tailwindcss/postcss': specifier: ^4 version: 4.3.3 @@ -224,8 +224,8 @@ importers: specifier: ^12.2.1 version: 12.2.1(supports-color@7.2.0) '@types/node': - specifier: 26.6.5 - version: 26.6.5 + specifier: 26.6.6 + version: 26.6.6 '@types/pg': specifier: ^8.23.1 version: 8.23.1 @@ -243,7 +243,7 @@ importers: version: 3.6.4 '@vitest/browser-playwright': specifier: ^5.0.5 - version: 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) + version: 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) '@vitest/coverage-v8': specifier: ^5.0.5 version: 5.0.5(@vitest/browser@5.0.5)(vitest@5.0.5) @@ -254,14 +254,14 @@ importers: specifier: ^9 version: 9.39.3(jiti@2.7.0)(supports-color@7.2.0) eslint-config-next: - specifier: 16.4.2 - version: 16.4.2(@typescript-eslint/parser@8.71.0(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: 16.4.3 + version: 16.4.3(@typescript-eslint/parser@8.71.0(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) fast-check: specifier: 4.10.2 version: 4.10.2 knip: - specifier: ^6.42.0 - version: 6.42.1 + specifier: ^6.44.1 + version: 6.44.1 lefthook: specifier: ^2.2.2 version: 2.2.2 @@ -275,8 +275,8 @@ importers: specifier: ^0.8.1 version: 0.8.1(prettier@3.9.10) shadcn: - specifier: ^4.22.1 - version: 4.22.1(@cfworker/json-schema@4.1.1)(supports-color@7.2.0) + specifier: ^4.23.0 + version: 4.23.0(supports-color@7.2.0) tailwindcss: specifier: ^4 version: 4.3.3 @@ -291,7 +291,7 @@ importers: version: 6.0.3 vitest: specifier: ^5.0.5 - version: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + version: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) vitest-browser-react: specifier: ^2.3.0 version: 2.3.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@5.0.5) @@ -302,78 +302,78 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@aws-sdk/checksums@3.1001.5': - resolution: {integrity: sha512-6erto9nK2OZO/woEgmFIaPh5gChgdNd7nL6jgAf8TAXz3/QHC8Pan2TFe9GYp3IxOIKCCGWPylSjtOHKfNzQlw==} + '@aws-sdk/checksums@3.1002.1': + resolution: {integrity: sha512-CXNESwkQC9jdrUG6cKXBfudVt1frGcYQykcCYbNclVrsewuGMbo3PlFjRteMe4OftNAqhyc3xC2jTz7SUqLasQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-s3@3.1155.0': - resolution: {integrity: sha512-l3uMeIlzWVgj/RTJTh5sKYKtQz1la3cvWLUPn1cwFH4UZpcqTH66SgJHCeB2FOE9bEAjOdbmCyPKt9aw867Fng==} + '@aws-sdk/client-s3@3.1159.0': + resolution: {integrity: sha512-el/Ihylk4PjJh/uJvYUeAzBiVLR6zt0xBOPIbciybePABWD/cOcxinHEPQslogm61LI2etnRrixSQltX94gzLA==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.978.5': - resolution: {integrity: sha512-ruI0AWqcrfL20XDS6SwZIJFPOBZ6N0ADa9nLzWlBhxk1aoUjbUX3JkTR9vEmk7o35XpAHi68ahZ4T6RE2U9XyA==} + '@aws-sdk/core@3.979.1': + resolution: {integrity: sha512-ayOlV1VhLNMiq8PW9ZkVobG4gkldnUoHjG69yy2b8j+VYFlhz/uAL7ZdYQAoQ+eShtGUdNDnnG5rxDg6yUJrOg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.76': - resolution: {integrity: sha512-YxmL1Ar7bV9ZkJvtv+lj+MF6le76NnZnbmgySyZuxpZaCv0/1lZ3KxKy6RIj1h9ui2hWnVjZxbmTMeO0y/NrQA==} + '@aws-sdk/credential-provider-env@3.972.80': + resolution: {integrity: sha512-uO5TiSvb6j1w9RTe5z28OaOmsrOxVQUPaC5+wZl50RfOXcrYD/KgnS8I9lfyGXc7sGbkCopK6VnhNIAoLqfewQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.78': - resolution: {integrity: sha512-3VHknDRngoebsaqyT1iR75b5cBT2zfEtODK6yYmYltljkK1HEAQLs2FEd1IpWqAeOYdMGaG9wikngWLTufY7RA==} + '@aws-sdk/credential-provider-http@3.972.82': + resolution: {integrity: sha512-vQzlDHlC24Yz42p+rT4NBoP/5VdetkBoujbOLq9h6QYWC8THuZSPYnXIR9OP3XcOrdMgPBBipOrdssfxnIiWUg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.973.21': - resolution: {integrity: sha512-aLx9hbCX6mGAyv4ZZd8UagJ4RASHVJw6BFDSIyuKmLkqNL6H47EjBPK6qaJ4B5TDV6mc+vMa0SJFYyo4mkvVQg==} + '@aws-sdk/credential-provider-ini@3.973.25': + resolution: {integrity: sha512-b5xl71uCRdWsu7P1VeGpiGuCf6zfYETsSNOv8AmYVTrsgbvTJRXdmmOPVfxkvGGVNsiKkGctClQW3jAn0SZLug==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.83': - resolution: {integrity: sha512-9bJU6FjRacF4FK/QHf8Dyxhur7B1grRj8C1Yh4IkpoFW2exQflPdCv0VrbemLW9ZctLNle+AE7TETs9KNvuLYg==} + '@aws-sdk/credential-provider-login@3.972.87': + resolution: {integrity: sha512-C4ZFmcwM+Zj14Z8huVUk54Gv4uzT1ZdzG9cY3Gdh8FePakq7Bss1OFsgZjAhWFOkFOGpBvFBeu0OWjWf8HNKRQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.88': - resolution: {integrity: sha512-AG0KID5qhQPzrFkh5b0Cws1Amytvzo0L0Xj6hMgJXEwD6ZXAqninDhSNAWJiN5zU4YVVZnuidnqwPwYJ04IamA==} + '@aws-sdk/credential-provider-node@3.972.92': + resolution: {integrity: sha512-jC3zmOo7Qxlk+oBivvSsS1Ph7sFGm0QfuhqDGbqgRXi4cxUYMG+dWtBwS2XYYXgc8TIVXJiwgQ65sbNpbYupTA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.76': - resolution: {integrity: sha512-pdhKFTXv1zPYhh92MTlp0jVbLWvUEV9v+rziuEkoskGGQ2iJskxHTO38nA8UAbT/N4IM3n8OZJ9rIY5IBO15/A==} + '@aws-sdk/credential-provider-process@3.972.80': + resolution: {integrity: sha512-xqfixO5aclje7tbQJDias+iNND5wp/3QZixCdZcVQpgWPTZ0V5DfTW9A804A5Z7ezu7sH3WRO+vzUjtiJBA8yg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.973.20': - resolution: {integrity: sha512-DlxrAB3MnjNLx/da7b89W+3DyJQYso/q7Ns15MsST2IV2nkAYQOYTUCaffNSjgrpMP99Dm2mV2jxzcbyF94ZfA==} + '@aws-sdk/credential-provider-sso@3.973.24': + resolution: {integrity: sha512-nlg3BKG03Cgzvv/dMnhxvDJPhAhQSpaN0RUdwgU7ziwkasoev7iI8el8Xy4Rd5sqzgaDUbV269fOXck5SargqA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.82': - resolution: {integrity: sha512-LUo46IqPTJ4xKBsrLuoaxiv/D2GTBCcFDMD1y3jKIqPR/p7Rw14RJFZ0iRWftqZtyLPQX9JMGnSi3mBu4y/pNA==} + '@aws-sdk/credential-provider-web-identity@3.972.86': + resolution: {integrity: sha512-zKTyLJBEyfQBVlYqT6Jt+mYV4r8kGbWM7dn6v4Y4MRARizhYafjDXP/iMu76UMRhToSPNmIKX1XAb24gtpBFIA==} engines: {node: '>=20.0.0'} - '@aws-sdk/lib-storage@3.1155.0': - resolution: {integrity: sha512-ThvepKZILBOGCO1rsRsuAWps6hwfMfFVVhRpNrxup+o0q/Hyi50IaDSGZYxrZMPbWH/8pG2LFld//OYDmyr48A==} + '@aws-sdk/lib-storage@3.1159.0': + resolution: {integrity: sha512-dJmPlATEBG4jKpdtDliywSb4JO2HZs5QtOwMkK1J/Jb3rw/WUU0z/JkWPqKgEs4GSHaH7Ep3uYY+1Tw64r0C8g==} engines: {node: '>=20.0.0'} peerDependencies: - '@aws-sdk/client-s3': ^3.1155.0 + '@aws-sdk/client-s3': ^3.1159.0 - '@aws-sdk/middleware-sdk-s3@3.972.81': - resolution: {integrity: sha512-jfanv1pV0sJFZw6/DPiNjvK7B478god0zOum5yIWo+/+1Gy+CSXWpGBWx+3nBJyDvjcu/2kUMr4ADUp9BHH34Q==} + '@aws-sdk/middleware-sdk-s3@3.972.85': + resolution: {integrity: sha512-Kyl2G6zhIS9qFoeLdlxvXFrWyc6g9D9ZCIRJnGkkfX6JZhxCZB5ebXBc7GKEeetrnhXcail6ALZT0lKbojcaNA==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.997.50': - resolution: {integrity: sha512-nKb8qu4QsnpZTq/6JIXc72mzuzfh7BK4sUQkpQznPec2z4W7Ob2xYkcM4i5e1yGTBnbJVeFv/0sf3jcz85hclA==} + '@aws-sdk/nested-clients@3.997.54': + resolution: {integrity: sha512-/OczlavsS7U5sOodRO10Ug4R/AKFVZiXTstKipWe68EfjPkmdDFNXNl9FCJyXWkg1DG6RBm3qAuVB8FNW9O8KQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.996.49': - resolution: {integrity: sha512-nvuAZNRrRRVCiARRKsYlQ0VnXiEQiq7vXPH+UA+LSo+kN3Djl9eo/V2r0udkw85PnsNshmv2Em1clld5M3j67w==} + '@aws-sdk/signature-v4-multi-region@3.996.51': + resolution: {integrity: sha512-+aHvUugVBuMPXxgkPfWnTMyGdE/yWS8GHi5+qQ37HowS0YqzrbuaDLznj+Dtmtu5jgCdqz36gXmujOToUhNNWw==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1155.0': - resolution: {integrity: sha512-iIcQnYLhWuq9qOLQbIWFrxF3PF0svVeZvHnUS4DUnO4zUFmFHIyGyjqrntXG+e/5PUgfavV0pYfDIKHxTzN2LA==} + '@aws-sdk/token-providers@3.1161.0': + resolution: {integrity: sha512-ypbXSofNcSHwf/KA40bFCXJb0MLaAKrfT7sot4dFaA+2lsuXNah4zLRJIAU7Qmvs9PFJ6rnY0bZFEC+mE7attA==} engines: {node: '>=20.0.0'} '@aws-sdk/types@3.975.0': resolution: {integrity: sha512-WQlhs6juByzWOzj5fwxOx0mPJaEqMcG/sDpl3Id61B3XhKE63xY+0QWcnG+sWR/sCfprmreyUo1lM7IKZmHMzw==} engines: {node: '>=20.0.0'} - '@aws-sdk/xml-builder@3.972.41': - resolution: {integrity: sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==} + '@aws-sdk/xml-builder@3.972.42': + resolution: {integrity: sha512-smX8/gNP8Kjq+CWTBMZQLQ912vOQjiWExzwzvMO+eujPB5RY8IbtF0AGdUUXHKN7KoDWK9dIcuW0WG269kiP6w==} engines: {node: '>=20.0.0'} '@aws/lambda-invoke-store@0.3.0': @@ -1224,8 +1224,12 @@ packages: '@levischuck/tiny-cbor@0.2.11': resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} - '@modelcontextprotocol/sdk@1.32.1': - resolution: {integrity: sha512-2DdE+SJDtzLEEWzY1ZjY7Q+VcPhcV1KisD3zI4u0XZyktsjHum1mwbMI+JaulUBi2OZk+KJAi2uPXzxichPkdw==} + '@modelcontextprotocol/core@2.4.0': + resolution: {integrity: sha512-z8QBKqdfXLPzkLQuG4xp8hrVEMm1PZ1IgxMN2sMbJiFiAKOWXnAzogXn2W4aqIBlP1ea6U5yiqVquvUNM1Cj6Q==} + engines: {node: '>=20'} + + '@modelcontextprotocol/sdk@1.32.2': + resolution: {integrity: sha512-SWsVtH/0vULSQStoZ6xxH2K09Li8fXYTMC64ZeogCdpZ3XSi1eCPOByV1OpuJxuI3OcmHhosDWYyii07tpPsLw==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -1234,6 +1238,10 @@ packages: '@cfworker/json-schema': optional: true + '@modelcontextprotocol/server@2.4.0': + resolution: {integrity: sha512-rgR9yxSaAJ+bcsi/XroT/S2AfPiIWloXAnrdfYSCms9ivVju0ishu/wW0J21Ho6+ZOR1r7RyeRbjiRuF87ix5Q==} + engines: {node: '>=20'} + '@mswjs/interceptors@0.41.9': resolution: {integrity: sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==} engines: {node: '>=18'} @@ -1320,63 +1328,63 @@ packages: '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - '@next/bundle-analyzer@16.4.2': - resolution: {integrity: sha512-tpNTC/WZYsmmixg3MZfx5JUuTh+Sgryu4eKhe7leQRcXHabztqtTkPCQM1Bk1VsE0trZ3w7NUCC3Zf7SeIBVzg==} + '@next/bundle-analyzer@16.4.3': + resolution: {integrity: sha512-FGcLziT2rqvGZTxZUjnCzwjCANnigN9vrbCm+1hQtzXbbtc1bXBTRmkXohVqyB/ReF5bOjpM2bNJQhz0PfLk9Q==} - '@next/env@16.4.2': - resolution: {integrity: sha512-nTUTFH7G5/J/fmpkjVLegOkqyKOP0CEsJcMsyO4UCYeN1su+YMW/MfaSErnJskL7XM+UDK6aTvslxsRCyya/sA==} + '@next/env@16.4.3': + resolution: {integrity: sha512-a7tz1QCcWWkwC/rPJcPMJk/UNRu9CFhDd3OHYE5hddbJrs8BqRTalxI6GlKCWEGzRLHN+S/B7a4PAHCtm25aBQ==} - '@next/eslint-plugin-next@16.4.2': - resolution: {integrity: sha512-gCTWlw0e+Y6kajpFyKKgA195jUJCRhlzJE0lV7ufe8a+ghIsANWZ0/FiJwg6DuOG1+OvRbcZDcFBoRh3mNJx0g==} + '@next/eslint-plugin-next@16.4.3': + resolution: {integrity: sha512-oxuC06wt/71h6ACYCV9GbKOfnf5a7VlRe/p80YHTut15TNgDEmynDnaq8t/xhy5rlvk7dhItIPs6H3rvIM4kyw==} - '@next/swc-darwin-arm64@16.4.2': - resolution: {integrity: sha512-ONkhFvZNFWlsEHOM/81AtxdyuJP2KRYKYR0JxPwvcu1AuPMMMgcL+wW2luldJvMtZwKtUxoSkCychW5wIeoYSw==} + '@next/swc-darwin-arm64@16.4.3': + resolution: {integrity: sha512-4yq5EXBt+VDtAZwTyfijaFp5D2C5oz3Ikw5a2kiX2K9nw72vrZX2q5UuAlkPtUMO1tQz6JTKpaKWjS7OOefTDQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.4.2': - resolution: {integrity: sha512-luPCMbOsCoaF+kXJEUjmjmOZg1lC3BflhmUu+ZmW4tBu2vW/4AXak8JBFvePizGkxVmNiAw/r9ra+6UviCWtWQ==} + '@next/swc-darwin-x64@16.4.3': + resolution: {integrity: sha512-1Rvkn/LUhnEF8WxnRkOrqGhbwXui1bkWFxONKIbN+r7C+9KHDSZ+iUoj4CzymVMWUyZIyx9szcb9+kbKhD500A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.4.2': - resolution: {integrity: sha512-xhwFTAncJyaCNy5KqKKuKaIIdCy1/1ZV1s5S1G0hhT7wGMkDTlfJ6aQbfRFnIG/s3/kDrxQ8aycVe+c5QnP8ow==} + '@next/swc-linux-arm64-gnu@16.4.3': + resolution: {integrity: sha512-dCKpXErGg3abUM6t5JTJV/ottVBTStJB5lRJTbgdUdQaQ+jNHiK56Hsc0YAEg/rinSh42hYG3HWiYmEMdilnxg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.4.2': - resolution: {integrity: sha512-T1PNmfbPcxr5ndtWUL/3wQtLXsz808lq6sc2GrNT5k2oquF7UyqZddHSuAewHVsWsGXe6nsl9HoN1YNriVjuSg==} + '@next/swc-linux-arm64-musl@16.4.3': + resolution: {integrity: sha512-WwYbhWkhYBvBtib1K4W0kL8MW2snBD2A5b3SN4vPpqalZbZs5+bQ1yzAdepVoOqrFfEW3dmREy4Zs1MrWcrFbw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.4.2': - resolution: {integrity: sha512-N9cDUOCGtkJG5PNKDFZUF3xXndrJJcpLp121uAGjIGvO/U2p9tfdNOM9htj7+5f72l0m8rMw/cvYacUJBQoudg==} + '@next/swc-linux-x64-gnu@16.4.3': + resolution: {integrity: sha512-QymWvfUwDEC5/lpJOsxX5VAbyoR2D13+2Jsjz4be7gT4LPqEgdpkeLIR/HFfCLgKzoMhpJbp6I/JnogyNZHcaA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.4.2': - resolution: {integrity: sha512-yY2uh1YhX6ufuYy2FCbw1dqblbhI57GLYAJfCkqD9auTv6pLrH67Uccjc3QMKBeCYAG6lkgu08ExmX1bbjejjQ==} + '@next/swc-linux-x64-musl@16.4.3': + resolution: {integrity: sha512-Vmjd9D7DpA4Vv3cUlr82QWgJD/BQZmns801vtC5VWHg6jCIA4a5vMKpQnfrM2pyCrp2eV0ENdUg4PlN3bAc2Yw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.4.2': - resolution: {integrity: sha512-j/ArWRIHpMMB6wYLMhr2puTguBt70lNU/Cmjl9p6dTDE8DGknYJMP9PdwPk2dqpCNL/KIX9yfngDvIesxJPmsg==} + '@next/swc-win32-arm64-msvc@16.4.3': + resolution: {integrity: sha512-lG1pPdPLk7gTyGb00n5JIMLdBJgjb+UEhSdZvFbhUMg0DyC6z4B7RnpSKF9VCd4imkLObVbXOFA0kFCpw7yFow==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.4.2': - resolution: {integrity: sha512-AA4edyWHDko3NCSo0x6GomsdgFb0oR1J3MXU1b5xt6FRFg4AucrMPW3S0hCe/9onU0O1BbpGQBsqo1r0Gneu1g==} + '@next/swc-win32-x64-msvc@16.4.3': + resolution: {integrity: sha512-NmQC9RkJdnPXRaMxtkCzobB3teVjqF33oSOnwDfi+XYGWWYpt+xlGK3mtktSKLbdjwaWbJu2OkkMiRFGUUncKg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1503,124 +1511,124 @@ packages: resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@oxc-parser/binding-android-arm-eabi@0.154.0': - resolution: {integrity: sha512-sDdEtDl7vKdCvf54j72RJbowE3jCmyRz/+oOB6IAwQxAHZ0eI+Dcj4hvVnm0b9Dy31plUkdmfds9C+/Zt895Tg==} + '@oxc-parser/binding-android-arm-eabi@0.155.0': + resolution: {integrity: sha512-A6xv7hDtnTm+xlZ7utn6rRQpRMJHRhVr3gjRGqlx0RUX84mNk0pAsy6YN/wWhuOTkaZhRrrzaLxf0NfbH77j2w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm64@0.154.0': - resolution: {integrity: sha512-UHrDPELzvWZoVkIDdSycj4bzcTMCJG3IbN++mSUgVBaUtNtWHjQ98U6Vz5bpF/1Ic3FYJyYhMr74huO5tVvpZw==} + '@oxc-parser/binding-android-arm64@0.155.0': + resolution: {integrity: sha512-T1wWwH9/JI5g7Z4kEQwDOwhToxdDhRyOTklH+uuNpJ16m3MZFmGl+l2rKc0NHQdbVRG2LTOBsNjpW3h1BWytPA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-darwin-arm64@0.154.0': - resolution: {integrity: sha512-mokYzajOSXxtSRDWCdHARGdntrKH+rZZ24Jzo8AtafyNzz0NARmpMm26Tc5B6qiGrr6UliWibHCOif1qRN2vaA==} + '@oxc-parser/binding-darwin-arm64@0.155.0': + resolution: {integrity: sha512-ZoRB3qJxJ8DWA41jHja+YeB0lLfjBy4T+Kr15vnN1k65X3zbJt3rPZftEwN4Ju4tmA4K/T9dWWD7Z8ewQLnrVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.154.0': - resolution: {integrity: sha512-WbtUBrclOVItWfLRSvs+Z/WLtXxJ2Ctv50PyuX894HzDN5/e0qzxVpTNPIVMzOerBhgKtFsSMcfxlYIAbvdVgg==} + '@oxc-parser/binding-darwin-x64@0.155.0': + resolution: {integrity: sha512-vxtL86BtM+IgrpejA86nbTk5j0HKTIMeuaJ1fQciw6p9RfavPtIPjI7gN34owap0yG9txXBaAWpGdxokNwdqIw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.154.0': - resolution: {integrity: sha512-YooHZSLawOe2fqm+lDdG8oAaQh2NYV/RMYTYzWRLy72stm2BgE9O/8Al6kFENjkmzyyBccDLLBirGxVtpzQfrw==} + '@oxc-parser/binding-freebsd-x64@0.155.0': + resolution: {integrity: sha512-tN6Ru5e0UVnWaIuiH8jEwnvxuxg7FvhWwSd3oe5oDhOD4ObsSr9/N6WfHLjilUWlPPj65ptwrSDH0Y7lzwTzmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': - resolution: {integrity: sha512-hKOwhZbrXdTwc4bGVfbLCXl9f2swl6zWdISocLQSNX9MgPmwHE3qGzOUkCrkuGpwdCVHPnkfOwsqTuYsrP5uNg==} + '@oxc-parser/binding-linux-arm-gnueabihf@0.155.0': + resolution: {integrity: sha512-h4ozA5n6L6lwolsz9iwunEhKWnIVbmFRots5QxEix0H6nJ5ICpuDa7PuShuhfpIDFe3+Qvyscioyiv+9g+4Syg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': - resolution: {integrity: sha512-tnjiooXEU013349O/yxKbF5Cusp1CfHWQ8kYR8tGeRzR/P4sOpQGQo21fsS71M0fMD6ESLq+lbvXFWi43PuKeQ==} + '@oxc-parser/binding-linux-arm-musleabihf@0.155.0': + resolution: {integrity: sha512-058/+LardpfuUlsKIvBGk/CYoakEVcMgqYx8GgyUZeOxFWTojYLlCc1Gb60/y21v3esDhHidgiY/Zbq9LpBhaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.154.0': - resolution: {integrity: sha512-Cao2kj+8d7BT6XJU1gV9eVQjV+Cr+e8vQm3tddDRZiM2hHrMDxwy3j6t+ofaSl0idyuPPCZ4AlpmQoj8yOT1QA==} + '@oxc-parser/binding-linux-arm64-gnu@0.155.0': + resolution: {integrity: sha512-nrOt2Y3xIAzu+lSPzH0864ieO+iCCXgoo9qFlGANE8Xh0cQ+RP8Wstfp+/wXN2YCyb98cAGzX0VruKYw7it/jw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-arm64-musl@0.154.0': - resolution: {integrity: sha512-uiwA0V3q8llWA7/8r+a9BBjk4j5YMDmi6wfOsyQfGOJMQSLHEiZ3HI8ulea766ykUa9wJFWk9XWEl4uJrZLQqw==} + '@oxc-parser/binding-linux-arm64-musl@0.155.0': + resolution: {integrity: sha512-KYAayyN5hQbJPtGKtRxlyc8XYmyntOplyXSQzTDrmbz7l/GCrzQbSswvyJFBTH1LGtsZrbXOAfN52i/Kz6kLKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': - resolution: {integrity: sha512-LICfN0Xs4Zdko+bJy6eOAEQojDuIR26suF2JtOsMaXjgbCrpRSH7/NCvJhY13YvYBx12V6hnwrL8n0lk0rbNJQ==} + '@oxc-parser/binding-linux-ppc64-gnu@0.155.0': + resolution: {integrity: sha512-CSuSY5hfjtsBnHXydOj8jiNfS1qHbdPZuPz1YL1cSgK7VmNYP+QlZIbG0BBYYBgX/vYEgZwbG9mBdW4YairZ5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': - resolution: {integrity: sha512-gbbSYxLF8ssRbQ2qQPy+2EhGNwNH1bAoRdkk6cnWaKHqmCikpSIPtpXjFbCCtjTi0uojqOM3ghFQwQPbDQsU0Q==} + '@oxc-parser/binding-linux-riscv64-gnu@0.155.0': + resolution: {integrity: sha512-7KCfOQm+Nz2N8trAXbQkal4TQ5756WVEmhm35y816YHvyFnEfVsICsiV5k0pEszNf/fRm4cm2i6i18SJ6/iCWg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-musl@0.154.0': - resolution: {integrity: sha512-nSnRYYDLCcRVjSQzF3g6rKqCNYwo5o+aQgnn8BBXfe+ofCgMGlGqkfRyvXm6ptZvoxNkkWtLlqM8W7Xc3j6ZnQ==} + '@oxc-parser/binding-linux-riscv64-musl@0.155.0': + resolution: {integrity: sha512-JSlhgoK+/g1TGJI5NuADx2+6syhxnQNLCWLXyO5QLFyetomcr/vIxSdiNlmyAv963YXUzCuwAwRG6npZ5xyJ1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-s390x-gnu@0.154.0': - resolution: {integrity: sha512-BxBQoJKtzRQgZEKQIt6CDUm8RGKC5T8Qo4576yDa5/xgc10X3fBDItMbRabzLtbUBfTqKLl+8AVr/H6CF7W22g==} + '@oxc-parser/binding-linux-s390x-gnu@0.155.0': + resolution: {integrity: sha512-WFIX+dPokWp64mi434Md3U3lJaTwNxAphvGjpltoyQjGUsdXavOIRrnp9dOS34Hd75HOAwDxAI+YwWOwqmJbtg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-gnu@0.154.0': - resolution: {integrity: sha512-/whkust2vYy+GjRUVL5cWaJmEu6jkdFfo5mkxgckyeOX61eMwo4iBoiwzeJZeMWAdzb/XOtQyLApHhFht3sOWA==} + '@oxc-parser/binding-linux-x64-gnu@0.155.0': + resolution: {integrity: sha512-g6xSDC/JpbnVOz5uafMGyK3txBVRFMQTx8opv/yHXGxqV3ZMVl3bf7W8XrSnF68dmy3gM4dgReNryuE53+WkeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-musl@0.154.0': - resolution: {integrity: sha512-EXURTyW9riw4B/kZnnE+58emAtw6+3VEszQfXUZkRqGaKIcmWDYkZtKB+xY/blHvuZ+Qy/fDclc31nmUCgtkSA==} + '@oxc-parser/binding-linux-x64-musl@0.155.0': + resolution: {integrity: sha512-6/4xlxKlZJWrQ0uwDFPc0H9+xLu7068CKhX3vIDW3SbvP/lVgnVuT5v6dyugeWskWpuxqF/WJ4WKwhxjU3pG2w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-parser/binding-openharmony-arm64@0.154.0': - resolution: {integrity: sha512-ZRFooyH3qsR6vuR4jFGlG3XM36490SvvXtNaUahBK4zHpooMdTHNaOMtGGJI0EW38m5hi4rOco9kw7ZwCIp28w==} + '@oxc-parser/binding-openharmony-arm64@0.155.0': + resolution: {integrity: sha512-tltklL0J0XjDxIRTBXWOBhvc2mitcmES45pIxhwDWfxRyqz7Vkeu0NekTZEIxGE4f/lXgq3vZcjjffteQOVorg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-win32-arm64-msvc@0.154.0': - resolution: {integrity: sha512-U0Vp+4lvwUa/PnOCJTZOjydj1rX2+VLHz4Y2vSFqlN8/7LTiURgD7z4uQ9yNv9O/NlU3mELBnPDlu7aaSYG1zQ==} + '@oxc-parser/binding-win32-arm64-msvc@0.155.0': + resolution: {integrity: sha512-alAb9TzjatUEsOeoncAziUnfdTDxfyswhalFZ9sC6plUgATIUx2NIZ0+bMn6aJ28AduS1OpG/OAisr/YISn4Ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.154.0': - resolution: {integrity: sha512-Hc8QgsFY5eUUP25we8TISUruibG2cDt0H4IcPG9RKdabb6odkCzIqjV6Gk9beGWGuOwMVCr81H/Su1q363LCCg==} + '@oxc-parser/binding-win32-ia32-msvc@0.155.0': + resolution: {integrity: sha512-yc5cbSfcGmRv/KpxDFuyk8adEBaWd/9HilWvBbQ4bFbus1V2PUh2mGB2Cfq9rqZTqLeiMT8x0skV+LKp9hOMgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.154.0': - resolution: {integrity: sha512-hD7judkUMA/hZPoamvKADs6+an1smp8UTK0aMYRijkvi00K/1vl7vEtmyn2JyQ9S+vibtnfcNzxqTLGyJUZCRQ==} + '@oxc-parser/binding-win32-x64-msvc@0.155.0': + resolution: {integrity: sha512-8heq6jGq+rfpTDRDjoQiBHw0maQZf3IXkS99pdHQZPoTL5kyF5qyPS0RidUlSdnWDIqxXb5nux7GBD9cT+imUw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1628,8 +1636,8 @@ packages: '@oxc-project/types@0.139.0': resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} - '@oxc-project/types@0.154.0': - resolution: {integrity: sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==} + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} '@oxc-resolver/binding-android-arm-eabi@11.24.2': resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==} @@ -1734,8 +1742,8 @@ packages: cpu: [x64] os: [win32] - '@parse/node-apn@8.1.0': - resolution: {integrity: sha512-LowcdkKPDikbbzIr3zwEdoFW5wfEbbTzpYQeen3S8kKLePG0AQK586Li+OLC7bonyLmlk//Yk3smHZOLSV6TZA==} + '@parse/node-apn@8.1.1': + resolution: {integrity: sha512-PXhWpSZiMSwxqJm9bR88bYcZGfe8JhauEEcUSbPlgwEEzGExK23Zxfj1a/9zy9/JWxP5VcULUVCvezJqV9mwUw==} engines: {node: 20 || 22 || 24} '@peculiar/asn1-android@2.9.4': @@ -2778,8 +2786,8 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@shadcn/registry@0.2.0': - resolution: {integrity: sha512-m3TeqU/+av2kgOLfESHkWzsmhuQuY4NXZd5Y1Rd4lzy4IX3JJ5+k2mYfkq6OT8oMuk2W4GQPAkO7+CC7KlpSbw==} + '@shadcn/registry@0.2.1': + resolution: {integrity: sha512-wMvZ3DGdnhCwtpeFbwKybSGfCcP52bZX77jMKgZvupmirgyA5KRLlkeQXkI2RGHIaD8TX2iWe2wcIEjjqzg2FQ==} engines: {node: '>=20.18.1'} '@simplewebauthn/browser@14.0.0': @@ -2793,8 +2801,8 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} - '@smithy/core@3.36.2': - resolution: {integrity: sha512-oRw0rB9QSUiCZfEs23G5F4Af+b2rQt1lItIICWu5IejFNd+uPM8SWqiKLMpQ6bX1Q7slsLbjuoE2niErFtkVPQ==} + '@smithy/core@3.38.1': + resolution: {integrity: sha512-U/mB2XiwTLaf+NSgLSWwJfptsMT/H8aBi0aTAA/E5e2/TagFeGCqAyhKGG0w0A9IWTkm4qYEmLoD/HB6aYfnRA==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.5.2': @@ -2805,12 +2813,12 @@ packages: resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.12.1': - resolution: {integrity: sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==} + '@smithy/node-http-handler@4.14.1': + resolution: {integrity: sha512-/T6E1jzCL0fErS9uq8JqES/5yYQQ4ppVmmYHwXw2nlov8KFzLb+3QqHR5iAun1BsuAB50IPxZliV8YMgghLwhA==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.7.4': - resolution: {integrity: sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==} + '@smithy/signature-v4@5.7.5': + resolution: {integrity: sha512-WPjdr5oWOk1LArpI4pavu+fSo+/evi0Re1olxGvqwuZopd4gYR1UGCi+Soyn/IjmafqbWs+ZC+3AKxJS3ZpwUg==} engines: {node: '>=18.0.0'} '@smithy/types@4.19.0': @@ -2827,18 +2835,25 @@ packages: resolution: {integrity: sha512-ZtAJ0ZT3MVRCWJTBE2h90XB/6E+4lifHYtcTyNG6nU2nLekPgTo4gD5esjX6Okxo1b/JB4jJzyxYB54fwKAoJw==} engines: {node: '>=22.0.0'} - '@stryker-mutator/core@10.0.0': - resolution: {integrity: sha512-ZvMsRyaXQQ5e6Thcid9pkuODv6Fn9E3nrBQJUap+hcJuGJ4unm26afo3m6YKSjn8kinyxJ/3TXf0cTWRDaTxVw==} + '@stryker-mutator/api@10.1.1': + resolution: {integrity: sha512-3s/ECsrD1Tf1WEB7amBk0HxjN7zgkabKvmqnI2C831rTNszJ6o2HoV9PVxtElDEWxb2+t4iavK5x25G+DTUOUA==} + engines: {node: '>=22.0.0'} + + '@stryker-mutator/core@10.1.1': + resolution: {integrity: sha512-4xJAOCw9utJMLyrTk9gINi434tBxnyuwt8lU/InyoKagKd2/zh/2ui7ncWoD0qZeJrxClYzblg8iUh5ewBAB3Q==} engines: {node: '>=22.0.0'} hasBin: true - '@stryker-mutator/instrumenter@10.0.0': - resolution: {integrity: sha512-B7Wmn1KlEWyFeOz6D6oGvQGRfi5Xw3VemG6dEKvFQp4qLvxD9Mf4kcZghfxffgnYwXd3bFgqXsJ+ZGlhdfIOrQ==} + '@stryker-mutator/instrumenter@10.1.1': + resolution: {integrity: sha512-Vyude2i8LhDciLV1q6J55KtdA7gZpRuMfZcBcmWV6hLHAvWocoPKnCKc5BlZt1mwGWkX3Olc0457I7Ue6F1WEg==} engines: {node: '>=22.0.0'} '@stryker-mutator/util@10.0.0': resolution: {integrity: sha512-LzOpHiJaCp2ABQgnPMlrQQcsK43bd5Vo/2FGL78aN62yDoeRQ+4j3tzeuXxK5OAHdC3fUz6TDoy4IsoAuLAd3w==} + '@stryker-mutator/util@10.1.1': + resolution: {integrity: sha512-Z0zDzsmhoSykE1gT3DvD1knFxySgNMfBlpSSs1j87kWvjEMfeMqfLOk0bqEPRg/rTFIUNSEXLZapxePUhZmfZA==} + '@stryker-mutator/vitest-runner@10.0.0': resolution: {integrity: sha512-SHK2/vfvRUpiz7jXPnQMBnr6zLdm69DK03Mo5mPhaZWcRSygrKUqYsPqWsXsK+5ySHzlMTfCyFK5NQ/X9sJFFw==} engines: {node: '>=22.0.0'} @@ -2941,11 +2956,11 @@ packages: '@tailwindcss/postcss@4.3.3': resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} - '@tanstack/query-core@5.104.5': - resolution: {integrity: sha512-Q94gI8Opd+CbdVNOdj8ZCyV8WqLYitrDq1t96Xc8WZT6lY0r5iRnJLXYDxMex7EEf2v+mXvn4FcjaBKSxXZQ9A==} + '@tanstack/query-core@5.105.0': + resolution: {integrity: sha512-7p56vRmT/z4UJ6sctGIdl5WRUQyUv53IUpUwEKi2g97zMbO7zh8ZsCLffGAvCPBR4xD72e3VXsDyLwXHhoNTMQ==} - '@tanstack/react-query@5.104.5': - resolution: {integrity: sha512-RORgFe052U+93weaNuqg7qHq7vNVNzXN/VrXqD4bbAuQCWUqOl2lV5Ui9flWk5CVvMyL/Bh27QWhzwH0aaOx9g==} + '@tanstack/react-query@5.105.0': + resolution: {integrity: sha512-y+hMuDERvgg6ay1da0V1a6ZC0ZONt7dELxSFkqRZuwm7p1TTZs0MoXrPlBRflIpRoYjvzQVYxycnLImpFLhWrw==} peerDependencies: '@types/react': ^18 || ^19 react: ^18 || ^19 @@ -2953,14 +2968,14 @@ packages: '@types/react': optional: true - '@tanstack/react-virtual@3.14.22': - resolution: {integrity: sha512-zNiB9IF3prySTfAUrj9tPHjD/lonBYkfxrPP4v4ITUx+qwHajJR5cY/xirjvwc+KWkur10GX3TpsbKh7JkD8Lw==} + '@tanstack/react-virtual@3.14.25': + resolution: {integrity: sha512-LYNLaogi8NZUqjPgJ0byKQrXprkDJsZLd94u0i1UpYtXz2fgvbP4KrHygM4MSgSAvEaqykQofYdJ1Vuf7XIz/Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/virtual-core@3.19.7': - resolution: {integrity: sha512-gxy5SvH0mFRJ0YujtrflB/1HAu9Wn1KGvL0bjZfQkYVVMsIpQiwcf1mR06/ViN4NjllUb4HNCjqE9FGwgTvMCQ==} + '@tanstack/virtual-core@3.19.10': + resolution: {integrity: sha512-/ltpH0qUCs5XQYE7fIhgA+aqgC5NzSfLTDQkC+N1wOOdvIYx1FH/kz2LGfSeanNbekqy3WBu6mNIbqXhxE/pew==} '@tesseract.js-data/deu@1.0.0': resolution: {integrity: sha512-3ter1p2gFAiCd5CMC+PodZ9YY2UDomkKj+ytlKeeZqOUmhLx1SDnYPf5zog0g5MBbxYveW+8omI3PUflqHfZ4Q==} @@ -3073,8 +3088,8 @@ packages: '@types/node@18.19.130': resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} - '@types/node@26.6.5': - resolution: {integrity: sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==} + '@types/node@26.6.6': + resolution: {integrity: sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==} '@types/pako@2.0.4': resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} @@ -4133,8 +4148,8 @@ packages: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - dotenv@18.0.8: - resolution: {integrity: sha512-2KDeoFoK/zRtcnbunCDlLG5VWVMcyqeQc6iK65o231nfNAcuGrKoqUQfJFUtBI+QlShk5HKIHxwebBtUl3rEfA==} + dotenv@18.0.9: + resolution: {integrity: sha512-3fVOW4cB02R066PUSwn8O4TJyz9NckQl7F81blIbaq9jKBm2tSmOKky7ZHIXzGvkVPXCSn6jkpziBPZdGFs8Tw==} engines: {node: '>=12'} hasBin: true @@ -4256,8 +4271,8 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-next@16.4.2: - resolution: {integrity: sha512-P33vjcETMXc+qBjpF77TeJHZLzk6cPcTy8KjpxLucYB3mCIFIORMcZ+cBXcAiIYjE5RM7jyknEEOwMNdnx/ADQ==} + eslint-config-next@16.4.3: + resolution: {integrity: sha512-j9IqBma6abp800frdUURaizYMgXOK+jNGyq6CsYcM9AxpSJs5D/TgMNGeAmRUilZvA7g9V1Tr71gNg9/SVTuMQ==} peerDependencies: eslint: '>=9.0.0' typescript: '>=3.3.1' @@ -5044,6 +5059,9 @@ packages: jose@6.2.13: resolution: {integrity: sha512-7TIg10ZE1x82YediN+lcrPNvGMKge9yFHQD+Qho/b8y2adfugU3AsvvHfxV0fzyFllT6l9xCjf4RWY9g/Z9PJQ==} + jose@6.2.14: + resolution: {integrity: sha512-3JasLuki1NRLQvY4wCoC37KZk4qxoBx2k2aFqLxT84IezqW0bkJKnNtxnZj/Fu1xsQivoc/lytxaRHJoGLjJ1A==} + js-md4@0.3.2: resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} @@ -5128,8 +5146,8 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - knip@6.42.1: - resolution: {integrity: sha512-gKJVsiT4LJQ0lfc8uSHOCzkOY8adAXNFGarIeODZbJOkBnQRVsG3e0UZFnO4LMwjA82A5tBWX/VgoeTYcjdKiQ==} + knip@6.44.1: + resolution: {integrity: sha512-Hbd8nvkIsNgFfXgC7Jsb5LHv7jj6VwA3tmfHd53XPX2z9Vc9RnAZqV0BIiP4OrtYqKwCoLseFHQZerb1bNlbSw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -5421,8 +5439,8 @@ packages: resolution: {integrity: sha512-5J9ysMYUpYIg9RF2vJpy9SinEmSviFSe0GyPpCQ4L5QSkLAgeLXlTAOu2ZwWUU5m+0SBl6gUU1R1ZQB3aKypfA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - lucide-react@1.61.0: - resolution: {integrity: sha512-v2SQPPPNjnr+BlhL9Spuzmo5yR+hLkftfuE4E3jaxdNPgSH0hJKPcLJBP7yAta87jQNPsSERS59PJjCJ/CorBA==} + lucide-react@1.66.0: + resolution: {integrity: sha512-8zjbi/Us+ETXqfBwmXF/FHrWGIqOdE6zT1yUdRJLQVoptomSkB0zdFWVIM667t9K8djWDaXdkBkqi2qVTuDNiw==} peerDependencies: '@types/react': '*' react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -5592,8 +5610,8 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - next@16.4.2: - resolution: {integrity: sha512-r+oBJojfefUjOiWkBhXgLS+igxX/7BWyK59uHnyOyplMSLtBZ+QLP3okrdYTbrfrbrmNTVWLBPaHDX9KRaIt3w==} + next@16.4.3: + resolution: {integrity: sha512-OqxKTGi9u80FydydsMNYNjnuje9Au+kvHlt2GZ//ftdpDHm1dxKqAaENoOOTX5wKzn+9vaKUNIfZeyZUuLhCnA==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -5634,8 +5652,8 @@ packages: resolution: {integrity: sha512-BdiKAgbfRlvfMq/XzO/AF9NPmaA8a+YpLAyAFTVFBj3gARrAIfWvNq7Q7NE4se3KgFu0KkrvQMxTS0XVnsGzHg==} engines: {node: '>=18'} - nodemailer@10.2.1: - resolution: {integrity: sha512-ZrDNsPFoDMwefNs7sJwrYiEJ/CG4ClJWDZv05iNJsEBWa8GRDry1QJHTJxsuTAY9eDDKjX4k+q3SxslXJOao7w==} + nodemailer@10.3.1: + resolution: {integrity: sha512-uF0AFsJC07Y1vdW7p580DKAnh7rAO+4UPSSB3mDCPNDufoiaOebV6JmrzpxB14OjEEEiBsNdYoM2Y+fN8M7BBA==} engines: {node: '>=20.0.0'} non-error@0.1.0: @@ -5746,8 +5764,8 @@ packages: resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} - oxc-parser@0.154.0: - resolution: {integrity: sha512-Gr/6fkjZwi937c4Tsz8y0iO4U0FLPkZI6JSVucLAIvQyqh379px7RS8ORIc0HOORbFjXZ6zyqWLl53qxhSeofw==} + oxc-parser@0.155.0: + resolution: {integrity: sha512-C/ReSf1JUFukK/zvk6jhcNibSssvas5+ktIzK7fbKVd3CedWe59C3QwHEOrEZj/4Rt9+xg0Jeis/Jv1F/KM1mw==} engines: {node: ^20.19.0 || >=22.12.0} oxc-resolver@11.24.2: @@ -6114,10 +6132,6 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - qs@6.16.0: - resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} - engines: {node: '>=0.6'} - qs@6.16.1: resolution: {integrity: sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg==} engines: {node: '>=0.6'} @@ -6387,11 +6401,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} - engines: {node: '>=10'} - hasBin: true - semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -6430,8 +6439,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@4.22.1: - resolution: {integrity: sha512-LbB4Lro+b0qSVki/tgL5edtKylEnXe1ppxMJC12d7NHPgaT+eSgJGMQULwP72V7X9tbiUq7xfx3VDAfB7jdGoA==} + shadcn@4.23.0: + resolution: {integrity: sha512-lKgq7QPFgkV/6EOrMCwvEn7ZAw/YnM/grhxzJmK4cZdw3E4F3Ut2EmWvrn2E+vzJp1y/76mxU185OSkXo9Ff+Q==} engines: {node: '>=20.18.1'} hasBin: true @@ -7269,166 +7278,166 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@aws-sdk/checksums@3.1001.5': + '@aws-sdk/checksums@3.1002.1': dependencies: - '@aws-sdk/core': 3.978.5 + '@aws-sdk/core': 3.979.1 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1155.0': + '@aws-sdk/client-s3@3.1159.0': dependencies: - '@aws-sdk/checksums': 3.1001.5 - '@aws-sdk/core': 3.978.5 - '@aws-sdk/credential-provider-node': 3.972.88 - '@aws-sdk/middleware-sdk-s3': 3.972.81 - '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/checksums': 3.1002.1 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/credential-provider-node': 3.972.92 + '@aws-sdk/middleware-sdk-s3': 3.972.85 + '@aws-sdk/signature-v4-multi-region': 3.996.51 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/fetch-http-handler': 5.8.0 - '@smithy/node-http-handler': 4.12.1 + '@smithy/node-http-handler': 4.14.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/core@3.978.5': + '@aws-sdk/core@3.979.1': dependencies: '@aws-sdk/types': 3.975.0 - '@aws-sdk/xml-builder': 3.972.41 + '@aws-sdk/xml-builder': 3.972.42 '@aws/lambda-invoke-store': 0.3.0 - '@smithy/core': 3.36.2 - '@smithy/signature-v4': 5.7.4 + '@smithy/core': 3.38.1 + '@smithy/signature-v4': 5.7.5 '@smithy/types': 4.19.0 bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.76': + '@aws-sdk/credential-provider-env@3.972.80': dependencies: - '@aws-sdk/core': 3.978.5 + '@aws-sdk/core': 3.979.1 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.78': + '@aws-sdk/credential-provider-http@3.972.82': dependencies: - '@aws-sdk/core': 3.978.5 + '@aws-sdk/core': 3.979.1 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/fetch-http-handler': 5.8.0 - '@smithy/node-http-handler': 4.12.1 + '@smithy/node-http-handler': 4.14.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.973.21': + '@aws-sdk/credential-provider-ini@3.973.25': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/credential-provider-env': 3.972.76 - '@aws-sdk/credential-provider-http': 3.972.78 - '@aws-sdk/credential-provider-login': 3.972.83 - '@aws-sdk/credential-provider-process': 3.972.76 - '@aws-sdk/credential-provider-sso': 3.973.20 - '@aws-sdk/credential-provider-web-identity': 3.972.82 - '@aws-sdk/nested-clients': 3.997.50 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/credential-provider-env': 3.972.80 + '@aws-sdk/credential-provider-http': 3.972.82 + '@aws-sdk/credential-provider-login': 3.972.87 + '@aws-sdk/credential-provider-process': 3.972.80 + '@aws-sdk/credential-provider-sso': 3.973.24 + '@aws-sdk/credential-provider-web-identity': 3.972.86 + '@aws-sdk/nested-clients': 3.997.54 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/credential-provider-imds': 4.5.2 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-login@3.972.83': + '@aws-sdk/credential-provider-login@3.972.87': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/nested-clients': 3.997.50 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/nested-clients': 3.997.54 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-node@3.972.88': + '@aws-sdk/credential-provider-node@3.972.92': dependencies: - '@aws-sdk/credential-provider-env': 3.972.76 - '@aws-sdk/credential-provider-http': 3.972.78 - '@aws-sdk/credential-provider-ini': 3.973.21 - '@aws-sdk/credential-provider-process': 3.972.76 - '@aws-sdk/credential-provider-sso': 3.973.20 - '@aws-sdk/credential-provider-web-identity': 3.972.82 + '@aws-sdk/credential-provider-env': 3.972.80 + '@aws-sdk/credential-provider-http': 3.972.82 + '@aws-sdk/credential-provider-ini': 3.973.25 + '@aws-sdk/credential-provider-process': 3.972.80 + '@aws-sdk/credential-provider-sso': 3.973.24 + '@aws-sdk/credential-provider-web-identity': 3.972.86 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/credential-provider-imds': 4.5.2 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.972.76': + '@aws-sdk/credential-provider-process@3.972.80': dependencies: - '@aws-sdk/core': 3.978.5 + '@aws-sdk/core': 3.979.1 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.973.20': + '@aws-sdk/credential-provider-sso@3.973.24': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/nested-clients': 3.997.50 - '@aws-sdk/token-providers': 3.1155.0 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/nested-clients': 3.997.54 + '@aws-sdk/token-providers': 3.1161.0 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-web-identity@3.972.82': + '@aws-sdk/credential-provider-web-identity@3.972.86': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/nested-clients': 3.997.50 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/nested-clients': 3.997.54 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/lib-storage@3.1155.0(@aws-sdk/client-s3@3.1155.0)': + '@aws-sdk/lib-storage@3.1159.0(@aws-sdk/client-s3@3.1159.0)': dependencies: - '@aws-sdk/client-s3': 3.1155.0 - '@smithy/core': 3.36.2 + '@aws-sdk/client-s3': 3.1159.0 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.81': + '@aws-sdk/middleware-sdk-s3@3.972.85': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/signature-v4-multi-region': 3.996.51 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.997.50': + '@aws-sdk/nested-clients@3.997.54': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/signature-v4-multi-region': 3.996.51 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/fetch-http-handler': 5.8.0 - '@smithy/node-http-handler': 4.12.1 + '@smithy/node-http-handler': 4.14.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.996.49': + '@aws-sdk/signature-v4-multi-region@3.996.51': dependencies: '@aws-sdk/types': 3.975.0 - '@smithy/signature-v4': 5.7.4 + '@smithy/signature-v4': 5.7.5 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1155.0': + '@aws-sdk/token-providers@3.1161.0': dependencies: - '@aws-sdk/core': 3.978.5 - '@aws-sdk/nested-clients': 3.997.50 + '@aws-sdk/core': 3.979.1 + '@aws-sdk/nested-clients': 3.997.54 '@aws-sdk/types': 3.975.0 - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 @@ -7437,7 +7446,7 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.41': + '@aws-sdk/xml-builder@3.972.42': dependencies: '@smithy/types': 4.19.0 tslib: 2.8.1 @@ -8196,122 +8205,122 @@ snapshots: '@inquirer/ansi@2.0.9': {} - '@inquirer/checkbox@5.2.7(@types/node@26.6.5)': + '@inquirer/checkbox@5.2.7(@types/node@26.6.6)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.5(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/confirm@6.3.4(@types/node@26.6.5)': + '@inquirer/confirm@6.3.4(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/core@12.0.5(@types/node@26.6.5)': + '@inquirer/core@12.0.5(@types/node@26.6.6)': dependencies: '@inquirer/ansi': 2.0.9 '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/type': 4.2.0(@types/node@26.6.6) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/editor@5.3.5(@types/node@26.6.5)': + '@inquirer/editor@5.3.5(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/external-editor': 3.0.6(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/external-editor': 3.0.6(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/expand@5.1.7(@types/node@26.6.5)': + '@inquirer/expand@5.1.7(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/external-editor@3.0.6(@types/node@26.6.5)': + '@inquirer/external-editor@3.0.6(@types/node@26.6.6)': dependencies: chardet: 2.2.0 iconv-lite: 0.7.3 optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@inquirer/figures@2.0.9': {} - '@inquirer/input@5.1.8(@types/node@26.6.5)': + '@inquirer/input@5.1.8(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/number@4.2.5(@types/node@26.6.5)': + '@inquirer/number@4.2.5(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/password@5.2.4(@types/node@26.6.5)': + '@inquirer/password@5.2.4(@types/node@26.6.6)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/prompts@8.7.4(@types/node@26.6.5)': + '@inquirer/prompts@8.7.4(@types/node@26.6.6)': dependencies: - '@inquirer/checkbox': 5.2.7(@types/node@26.6.5) - '@inquirer/confirm': 6.3.4(@types/node@26.6.5) - '@inquirer/editor': 5.3.5(@types/node@26.6.5) - '@inquirer/expand': 5.1.7(@types/node@26.6.5) - '@inquirer/input': 5.1.8(@types/node@26.6.5) - '@inquirer/number': 4.2.5(@types/node@26.6.5) - '@inquirer/password': 5.2.4(@types/node@26.6.5) - '@inquirer/rawlist': 5.3.7(@types/node@26.6.5) - '@inquirer/search': 4.3.5(@types/node@26.6.5) - '@inquirer/select': 5.2.7(@types/node@26.6.5) + '@inquirer/checkbox': 5.2.7(@types/node@26.6.6) + '@inquirer/confirm': 6.3.4(@types/node@26.6.6) + '@inquirer/editor': 5.3.5(@types/node@26.6.6) + '@inquirer/expand': 5.1.7(@types/node@26.6.6) + '@inquirer/input': 5.1.8(@types/node@26.6.6) + '@inquirer/number': 4.2.5(@types/node@26.6.6) + '@inquirer/password': 5.2.4(@types/node@26.6.6) + '@inquirer/rawlist': 5.3.7(@types/node@26.6.6) + '@inquirer/search': 4.3.5(@types/node@26.6.6) + '@inquirer/select': 5.2.7(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/rawlist@5.3.7(@types/node@26.6.5)': + '@inquirer/rawlist@5.3.7(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/search@4.3.5(@types/node@26.6.5)': + '@inquirer/search@4.3.5(@types/node@26.6.6)': dependencies: - '@inquirer/core': 12.0.5(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/select@5.2.7(@types/node@26.6.5)': + '@inquirer/select@5.2.7(@types/node@26.6.6)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.5(@types/node@26.6.5) + '@inquirer/core': 12.0.5(@types/node@26.6.6) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@26.6.5) + '@inquirer/type': 4.2.0(@types/node@26.6.6) optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 - '@inquirer/type@4.2.0(@types/node@26.6.5)': + '@inquirer/type@4.2.0(@types/node@26.6.6)': optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@isaacs/cliui@8.0.2': dependencies: @@ -8356,7 +8365,11 @@ snapshots: '@levischuck/tiny-cbor@0.2.11': {} - '@modelcontextprotocol/sdk@1.32.1(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.6.7)': + '@modelcontextprotocol/core@2.4.0': + dependencies: + zod: 4.6.7 + + '@modelcontextprotocol/sdk@1.32.2(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.6.7)': dependencies: '@hono/node-server': 1.19.17(hono@4.13.13) ajv: 8.20.0 @@ -8380,6 +8393,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/server@2.4.0': + dependencies: + '@modelcontextprotocol/core': 2.4.0 + zod: 4.6.7 + '@mswjs/interceptors@0.41.9': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -8458,44 +8476,44 @@ snapshots: '@tybys/wasm-util': 0.10.4 optional: true - '@next/bundle-analyzer@16.4.2': + '@next/bundle-analyzer@16.4.3': dependencies: webpack-bundle-analyzer: 4.10.1 transitivePeerDependencies: - bufferutil - utf-8-validate - '@next/env@16.4.2': {} + '@next/env@16.4.3': {} - '@next/eslint-plugin-next@16.4.2(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))': + '@next/eslint-plugin-next@16.4.3(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0)) fast-glob: 3.3.1 transitivePeerDependencies: - eslint - '@next/swc-darwin-arm64@16.4.2': + '@next/swc-darwin-arm64@16.4.3': optional: true - '@next/swc-darwin-x64@16.4.2': + '@next/swc-darwin-x64@16.4.3': optional: true - '@next/swc-linux-arm64-gnu@16.4.2': + '@next/swc-linux-arm64-gnu@16.4.3': optional: true - '@next/swc-linux-arm64-musl@16.4.2': + '@next/swc-linux-arm64-musl@16.4.3': optional: true - '@next/swc-linux-x64-gnu@16.4.2': + '@next/swc-linux-x64-gnu@16.4.3': optional: true - '@next/swc-linux-x64-musl@16.4.2': + '@next/swc-linux-x64-musl@16.4.3': optional: true - '@next/swc-win32-arm64-msvc@16.4.2': + '@next/swc-win32-arm64-msvc@16.4.3': optional: true - '@next/swc-win32-x64-msvc@16.4.2': + '@next/swc-win32-x64-msvc@16.4.3': optional: true '@noble/hashes@2.4.0': {} @@ -8586,66 +8604,66 @@ snapshots: '@opentelemetry/api@1.9.1': {} - '@oxc-parser/binding-android-arm-eabi@0.154.0': + '@oxc-parser/binding-android-arm-eabi@0.155.0': optional: true - '@oxc-parser/binding-android-arm64@0.154.0': + '@oxc-parser/binding-android-arm64@0.155.0': optional: true - '@oxc-parser/binding-darwin-arm64@0.154.0': + '@oxc-parser/binding-darwin-arm64@0.155.0': optional: true - '@oxc-parser/binding-darwin-x64@0.154.0': + '@oxc-parser/binding-darwin-x64@0.155.0': optional: true - '@oxc-parser/binding-freebsd-x64@0.154.0': + '@oxc-parser/binding-freebsd-x64@0.155.0': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': + '@oxc-parser/binding-linux-arm-gnueabihf@0.155.0': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': + '@oxc-parser/binding-linux-arm-musleabihf@0.155.0': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.154.0': + '@oxc-parser/binding-linux-arm64-gnu@0.155.0': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.154.0': + '@oxc-parser/binding-linux-arm64-musl@0.155.0': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': + '@oxc-parser/binding-linux-ppc64-gnu@0.155.0': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': + '@oxc-parser/binding-linux-riscv64-gnu@0.155.0': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.154.0': + '@oxc-parser/binding-linux-riscv64-musl@0.155.0': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.154.0': + '@oxc-parser/binding-linux-s390x-gnu@0.155.0': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.154.0': + '@oxc-parser/binding-linux-x64-gnu@0.155.0': optional: true - '@oxc-parser/binding-linux-x64-musl@0.154.0': + '@oxc-parser/binding-linux-x64-musl@0.155.0': optional: true - '@oxc-parser/binding-openharmony-arm64@0.154.0': + '@oxc-parser/binding-openharmony-arm64@0.155.0': optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.154.0': + '@oxc-parser/binding-win32-arm64-msvc@0.155.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.154.0': + '@oxc-parser/binding-win32-ia32-msvc@0.155.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.154.0': + '@oxc-parser/binding-win32-x64-msvc@0.155.0': optional: true '@oxc-project/types@0.139.0': {} - '@oxc-project/types@0.154.0': {} + '@oxc-project/types@0.155.0': {} '@oxc-resolver/binding-android-arm-eabi@11.24.2': optional: true @@ -8708,7 +8726,7 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.24.2': optional: true - '@parse/node-apn@8.1.0(supports-color@7.2.0)': + '@parse/node-apn@8.1.1(supports-color@7.2.0)': dependencies: debug: 4.4.3(supports-color@7.2.0) jsonwebtoken: 9.0.3 @@ -8853,11 +8871,11 @@ snapshots: '@prisma/client-runtime-utils@7.10.1': {} - '@prisma/client@7.10.1(prisma@7.10.1(@types/node@26.6.5)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3))(typescript@6.0.3)': + '@prisma/client@7.10.1(prisma@7.10.1(@types/node@26.6.6)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3))(typescript@6.0.3)': dependencies: '@prisma/client-runtime-utils': 7.10.1 optionalDependencies: - prisma: 7.10.1(@types/node@26.6.5)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3) + prisma: 7.10.1(@types/node@26.6.6)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3) typescript: 6.0.3 '@prisma/config@7.10.1(magicast@0.5.5)': @@ -9843,7 +9861,7 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@shadcn/registry@0.2.0(supports-color@7.2.0)': + '@shadcn/registry@0.2.1(supports-color@7.2.0)': dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.9 @@ -9888,32 +9906,32 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@smithy/core@3.36.2': + '@smithy/core@3.38.1': dependencies: '@smithy/types': 4.19.0 tslib: 2.8.1 '@smithy/credential-provider-imds@4.5.2': dependencies: - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 '@smithy/fetch-http-handler@5.8.0': dependencies: - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.12.1': + '@smithy/node-http-handler@4.14.1': dependencies: - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 - '@smithy/signature-v4@5.7.4': + '@smithy/signature-v4@5.7.5': dependencies: - '@smithy/core': 3.36.2 + '@smithy/core': 3.38.1 '@smithy/types': 4.19.0 tslib: 2.8.1 @@ -9932,12 +9950,19 @@ snapshots: tslib: 2.8.1 typed-inject: 5.0.0 - '@stryker-mutator/core@10.0.0(@types/node@26.6.5)': + '@stryker-mutator/api@10.1.1': dependencies: - '@inquirer/prompts': 8.7.4(@types/node@26.6.5) - '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/instrumenter': 10.0.0 - '@stryker-mutator/util': 10.0.0 + mutation-testing-metrics: 3.8.4 + mutation-testing-report-schema: 3.8.4 + tslib: 2.8.1 + typed-inject: 5.0.0 + + '@stryker-mutator/core@10.1.1(@types/node@26.6.6)': + dependencies: + '@inquirer/prompts': 8.7.4(@types/node@26.6.6) + '@stryker-mutator/api': 10.1.1 + '@stryker-mutator/instrumenter': 10.1.1 + '@stryker-mutator/util': 10.1.1 ajv: 8.20.0 chalk: 5.6.2 commander: 14.0.3 @@ -9963,7 +9988,7 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@stryker-mutator/instrumenter@10.0.0': + '@stryker-mutator/instrumenter@10.1.1': dependencies: '@babel/core': 8.0.7 '@babel/generator': 8.0.6 @@ -9973,8 +9998,8 @@ snapshots: '@babel/preset-react': 8.0.1(@babel/core@8.0.7) '@babel/preset-typescript': 8.0.7(@babel/core@8.0.7) '@babel/traverse': 8.0.7 - '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/util': 10.0.0 + '@stryker-mutator/api': 10.1.1 + '@stryker-mutator/util': 10.1.1 angular-html-parser: 10.11.0 semver: 7.8.5 tslib: 2.8.1 @@ -9982,14 +10007,16 @@ snapshots: '@stryker-mutator/util@10.0.0': {} - '@stryker-mutator/vitest-runner@10.0.0(patch_hash=9ad3e9855fd9781fd36e872ed42c5f934f91b962d6830e6cc56d56bf16e1dabd)(@stryker-mutator/core@10.0.0(@types/node@26.6.5))(vitest@5.0.5)': + '@stryker-mutator/util@10.1.1': {} + + '@stryker-mutator/vitest-runner@10.0.0(patch_hash=9ad3e9855fd9781fd36e872ed42c5f934f91b962d6830e6cc56d56bf16e1dabd)(@stryker-mutator/core@10.1.1(@types/node@26.6.6))(vitest@5.0.5)': dependencies: '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/core': 10.0.0(@types/node@26.6.5) + '@stryker-mutator/core': 10.1.1(@types/node@26.6.6) '@stryker-mutator/util': 10.0.0 semver: 7.8.5 tslib: 2.8.1 - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) '@swc/helpers@0.5.23': dependencies: @@ -10064,22 +10091,22 @@ snapshots: postcss: 8.5.26 tailwindcss: 4.3.3 - '@tanstack/query-core@5.104.5': {} + '@tanstack/query-core@5.105.0': {} - '@tanstack/react-query@5.104.5(@types/react@19.3.0)(react@19.3.1)': + '@tanstack/react-query@5.105.0(@types/react@19.3.0)(react@19.3.1)': dependencies: - '@tanstack/query-core': 5.104.5 + '@tanstack/query-core': 5.105.0 react: 19.3.1 optionalDependencies: '@types/react': 19.3.0 - '@tanstack/react-virtual@3.14.22(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + '@tanstack/react-virtual@3.14.25(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': dependencies: - '@tanstack/virtual-core': 3.19.7 + '@tanstack/virtual-core': 3.19.10 react: 19.3.1 react-dom: 19.3.1(react@19.3.1) - '@tanstack/virtual-core@3.19.7': {} + '@tanstack/virtual-core@3.19.10': {} '@tesseract.js-data/deu@1.0.0': {} @@ -10166,13 +10193,13 @@ snapshots: '@types/docker-modem@3.0.6': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/ssh2': 1.15.6 '@types/dockerode@4.0.2': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/ssh2': 1.15.6 '@types/estree@1.0.8': {} @@ -10195,7 +10222,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@26.6.5': + '@types/node@26.6.6': dependencies: undici-types: 8.9.0 @@ -10203,13 +10230,13 @@ snapshots: '@types/pg@8.23.1': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 pg-protocol: 1.16.0 pg-types: 2.2.0 '@types/qrcode@1.5.6': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/raf@3.4.3': optional: true @@ -10224,20 +10251,20 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/set-cookie-parser@2.4.10': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 optional: true '@types/ssh2-streams@0.1.13': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/ssh2@0.5.52': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@types/ssh2-streams': 0.1.13 '@types/ssh2@1.15.6': @@ -10256,7 +10283,7 @@ snapshots: '@types/web-push@3.6.4': dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 '@typescript-eslint/eslint-plugin@8.71.0(@typescript-eslint/parser@8.71.0(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: @@ -10496,30 +10523,30 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 - '@vitest/browser-playwright@5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5)': + '@vitest/browser-playwright@5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5)': dependencies: - '@vitest/browser': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) - '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + '@vitest/browser': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) + '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) playwright: 1.64.1 tinyrainbow: 3.2.0 - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5)': + '@vitest/browser@5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5)': dependencies: '@blazediff/core': 1.10.0 - '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) '@vitest/ui': 5.0.5(vitest@5.0.5) '@vitest/utils': 5.0.5 magic-string: 1.4.3 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.2.0 - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) ws: 8.22.0 transitivePeerDependencies: - bufferutil @@ -10537,9 +10564,9 @@ snapshots: obug: 3.0.0 std-env: 4.3.0 tinyrainbow: 3.2.0 - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) optionalDependencies: - '@vitest/browser': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) + '@vitest/browser': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) '@vitest/istanbul-lib-coverage@1.0.2': {} @@ -10547,15 +10574,15 @@ snapshots: dependencies: '@vitest/istanbul-lib-coverage': 1.0.2 - '@vitest/mocker@5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))': + '@vitest/mocker@5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.5 estree-walker: 3.0.3 magic-string: 1.4.3 optionalDependencies: - msw: 2.14.6(@types/node@26.6.5)(typescript@6.0.3) - vite: 8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1) + msw: 2.14.6(@types/node@26.6.6)(typescript@6.0.3) + vite: 8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1) '@vitest/pretty-format@5.0.5': dependencies: @@ -10571,7 +10598,7 @@ snapshots: pathe: 2.0.3 sirv: 3.0.2 tinyrainbow: 3.2.0 - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) '@vitest/utils@5.0.5': dependencies: @@ -11309,7 +11336,7 @@ snapshots: dotenv@17.4.2: {} - dotenv@18.0.8: {} + dotenv@18.0.9: {} dunder-proto@1.0.1: dependencies: @@ -11487,9 +11514,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@16.4.2(@typescript-eslint/parser@8.71.0(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): + eslint-config-next@16.4.3(@typescript-eslint/parser@8.71.0(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@next/eslint-plugin-next': 16.4.2(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0)) + '@next/eslint-plugin-next': 16.4.3(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0)) eslint: 9.39.3(jiti@2.7.0)(supports-color@7.2.0) eslint-import-resolver-node: 0.3.10(supports-color@7.2.0) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.3(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) @@ -11777,7 +11804,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.8 - qs: 6.16.0 + qs: 6.16.1 range-parser: 1.3.0 router: 2.2.0(supports-color@7.2.0) send: 1.2.1(supports-color@7.2.0) @@ -12357,6 +12384,8 @@ snapshots: jose@6.2.13: {} + jose@6.2.14: {} + js-md4@0.3.2: {} js-tokens@10.0.0: {} @@ -12406,7 +12435,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.0 + semver: 7.8.5 jspdf-autotable@5.0.9(jspdf@4.2.1): dependencies: @@ -12449,12 +12478,12 @@ snapshots: kleur@4.1.5: {} - knip@6.42.1: + knip@6.44.1: dependencies: formatly: 0.11.4 get-tsconfig: 4.14.3 jiti: 2.7.0 - oxc-parser: 0.154.0 + oxc-parser: 0.155.0 oxc-resolver: 11.24.2 picomatch: 4.0.7 smol-toml: 1.9.1 @@ -12678,7 +12707,7 @@ snapshots: lru.min@1.1.5: {} - lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1): + lucide-react@1.66.0(@types/react@19.3.0)(react@19.3.1): dependencies: react: 19.3.1 optionalDependencies: @@ -12759,9 +12788,9 @@ snapshots: ms@2.1.3: {} - msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3): + msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3): dependencies: - '@inquirer/confirm': 6.3.4(@types/node@26.6.5) + '@inquirer/confirm': 6.3.4(@types/node@26.6.6) '@mswjs/interceptors': 0.41.9 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 @@ -12799,9 +12828,9 @@ snapshots: mute-stream@3.0.0: {} - mysql2@3.24.4(@types/node@26.6.5): + mysql2@3.24.4(@types/node@26.6.6): dependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 aws-ssl-profiles: 1.1.2 generate-function: 2.3.1 iconv-lite: 0.7.3 @@ -12827,28 +12856,28 @@ snapshots: negotiator@1.0.0: {} - next@16.4.2(@babel/core@7.29.7(supports-color@7.2.0))(@opentelemetry/api@1.9.1)(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): + next@16.4.3(@babel/core@8.0.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.64.1)(@types/node@26.6.6)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - '@next/env': 16.4.2 + '@next/env': 16.4.3 '@swc/helpers': 0.5.23 baseline-browser-mapping: 2.11.27 caniuse-lite: 1.0.30001815 postcss: 8.5.23 react: 19.3.1 react-dom: 19.3.1(react@19.3.1) - styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@7.2.0))(react@19.3.1) + styled-jsx: 5.1.6(@babel/core@8.0.7)(react@19.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 16.4.2 - '@next/swc-darwin-x64': 16.4.2 - '@next/swc-linux-arm64-gnu': 16.4.2 - '@next/swc-linux-arm64-musl': 16.4.2 - '@next/swc-linux-x64-gnu': 16.4.2 - '@next/swc-linux-x64-musl': 16.4.2 - '@next/swc-win32-arm64-msvc': 16.4.2 - '@next/swc-win32-x64-msvc': 16.4.2 + '@next/swc-darwin-arm64': 16.4.3 + '@next/swc-darwin-x64': 16.4.3 + '@next/swc-linux-arm64-gnu': 16.4.3 + '@next/swc-linux-arm64-musl': 16.4.3 + '@next/swc-linux-x64-gnu': 16.4.3 + '@next/swc-linux-x64-musl': 16.4.3 + '@next/swc-win32-arm64-msvc': 16.4.3 + '@next/swc-win32-x64-msvc': 16.4.3 '@opentelemetry/api': 1.9.1 '@playwright/test': 1.64.1 - sharp: 0.35.5(@types/node@26.6.5) + sharp: 0.35.5(@types/node@26.6.6) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -12869,7 +12898,7 @@ snapshots: node-releases@2.0.58: {} - nodemailer@10.2.1: {} + nodemailer@10.3.1: {} non-error@0.1.0: {} @@ -13002,29 +13031,29 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxc-parser@0.154.0: + oxc-parser@0.155.0: dependencies: - '@oxc-project/types': 0.154.0 + '@oxc-project/types': 0.155.0 optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.154.0 - '@oxc-parser/binding-android-arm64': 0.154.0 - '@oxc-parser/binding-darwin-arm64': 0.154.0 - '@oxc-parser/binding-darwin-x64': 0.154.0 - '@oxc-parser/binding-freebsd-x64': 0.154.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.154.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.154.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.154.0 - '@oxc-parser/binding-linux-arm64-musl': 0.154.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.154.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.154.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.154.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.154.0 - '@oxc-parser/binding-linux-x64-gnu': 0.154.0 - '@oxc-parser/binding-linux-x64-musl': 0.154.0 - '@oxc-parser/binding-openharmony-arm64': 0.154.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.154.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.154.0 - '@oxc-parser/binding-win32-x64-msvc': 0.154.0 + '@oxc-parser/binding-android-arm-eabi': 0.155.0 + '@oxc-parser/binding-android-arm64': 0.155.0 + '@oxc-parser/binding-darwin-arm64': 0.155.0 + '@oxc-parser/binding-darwin-x64': 0.155.0 + '@oxc-parser/binding-freebsd-x64': 0.155.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.155.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.155.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.155.0 + '@oxc-parser/binding-linux-arm64-musl': 0.155.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.155.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.155.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.155.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.155.0 + '@oxc-parser/binding-linux-x64-gnu': 0.155.0 + '@oxc-parser/binding-linux-x64-musl': 0.155.0 + '@oxc-parser/binding-openharmony-arm64': 0.155.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.155.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.155.0 + '@oxc-parser/binding-win32-x64-msvc': 0.155.0 oxc-resolver@11.24.2: optionalDependencies: @@ -13247,13 +13276,13 @@ snapshots: dependencies: parse-ms: 4.0.0 - prisma@7.10.1(@types/node@26.6.5)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3): + prisma@7.10.1(@types/node@26.6.6)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(magicast@0.5.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3): dependencies: '@prisma/config': 7.10.1(magicast@0.5.5) '@prisma/dev': 0.24.17(typescript@6.0.3) '@prisma/engines': 7.10.1 '@prisma/studio-core': 0.33.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) - mysql2: 3.24.4(@types/node@26.6.5) + mysql2: 3.24.4(@types/node@26.6.6) postgres: 3.4.7 optionalDependencies: typescript: 6.0.3 @@ -13306,7 +13335,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.2 - '@types/node': 26.6.5 + '@types/node': 26.6.6 long: 5.3.2 proxy-addr@2.0.8: @@ -13337,11 +13366,6 @@ snapshots: pngjs: 5.0.0 yargs: 15.4.1 - qs@6.16.0: - dependencies: - es-define-property: 1.0.1 - side-channel: 1.1.1 - qs@6.16.1: dependencies: es-define-property: 1.0.1 @@ -13700,8 +13724,6 @@ snapshots: semver@6.3.1: {} - semver@7.8.0: {} - semver@7.8.5: {} send@1.2.1(supports-color@7.2.0): @@ -13763,15 +13785,15 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.22.1(@cfworker/json-schema@4.1.1)(supports-color@7.2.0): + shadcn@4.23.0(supports-color@7.2.0): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.9 '@babel/plugin-transform-typescript': 7.29.9(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.32.1(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.6.7) - '@shadcn/registry': 0.2.0(supports-color@7.2.0) + '@modelcontextprotocol/server': 2.4.0 + '@shadcn/registry': 0.2.1(supports-color@7.2.0) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.29.3 cn: 0.2.6 @@ -13798,11 +13820,10 @@ snapshots: validate-npm-package-name: 7.0.2 zod: 4.6.7 transitivePeerDependencies: - - '@cfworker/json-schema' - babel-plugin-macros - supports-color - sharp@0.35.5(@types/node@26.6.5): + sharp@0.35.5(@types/node@26.6.6): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 @@ -13833,7 +13854,7 @@ snapshots: '@img/sharp-win32-arm64': 0.35.5 '@img/sharp-win32-ia32': 0.35.5 '@img/sharp-win32-x64': 0.35.5 - '@types/node': 26.6.5 + '@types/node': 26.6.6 optional: true shebang-command@2.0.0: @@ -14065,12 +14086,12 @@ snapshots: strip-json-comments@5.0.3: {} - styled-jsx@5.1.6(@babel/core@7.29.7(supports-color@7.2.0))(react@19.3.1): + styled-jsx@5.1.6(@babel/core@8.0.7)(react@19.3.1): dependencies: client-only: 0.0.1 react: 19.3.1 optionalDependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 8.0.7 supports-color@7.2.0: dependencies: @@ -14318,7 +14339,7 @@ snapshots: dependencies: des.js: 1.1.0 js-md4: 0.3.2 - qs: 6.16.0 + qs: 6.16.1 tunnel: 0.0.6 underscore: 1.13.8 @@ -14459,7 +14480,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1): + vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -14467,7 +14488,7 @@ snapshots: rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.6.5 + '@types/node': 26.6.6 fsevents: 2.3.3 jiti: 2.7.0 yaml: 2.9.1 @@ -14476,15 +14497,15 @@ snapshots: dependencies: react: 19.3.1 react-dom: 19.3.1(react@19.3.1) - vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) optionalDependencies: '@types/react': 19.3.0 '@types/react-dom': 19.3.0(@types/react@19.3.0) - vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)): + vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@26.6.6)(@vitest/browser-playwright@5.0.5)(@vitest/coverage-v8@5.0.5)(@vitest/ui@5.0.5)(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1)) + '@vitest/mocker': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1)) chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -14495,12 +14516,12 @@ snapshots: tinybench: 6.2.2 tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1) + vite: 8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1) why-is-node-running: 3.2.1 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 26.6.5 - '@vitest/browser-playwright': 5.0.5(msw@2.14.6(@types/node@26.6.5)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) + '@types/node': 26.6.6 + '@vitest/browser-playwright': 5.0.5(msw@2.14.6(@types/node@26.6.6)(typescript@6.0.3))(playwright@1.64.1)(vite@8.1.6(@types/node@26.6.6)(jiti@2.7.0)(yaml@2.9.1))(vitest@5.0.5) '@vitest/coverage-v8': 5.0.5(@vitest/browser@5.0.5)(vitest@5.0.5) '@vitest/ui': 5.0.5(vitest@5.0.5) transitivePeerDependencies: diff --git a/public/sw.js b/public/sw.js index 9b9502e0f..d6e87d86a 100644 --- a/public/sw.js +++ b/public/sw.js @@ -36,7 +36,7 @@ try { // v1.4.38.4 → v1.4.42. Do not hand-edit; bump `package.json` and rebuild. const CACHE_VERSION = (typeof self !== "undefined" && self.__APP_VERSION__) || - /* @sw-version-fallback */ "v1.46.5"; + /* @sw-version-fallback */ "v1.46.6"; const STATIC_CACHE = `healthlog-static-${CACHE_VERSION}`; const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`; // v1.18.6 — read-only data cache for a curated allowlist of safe GET `/api/*` diff --git a/scripts/README.md b/scripts/README.md index 5692b78e4..18da03099 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -31,6 +31,7 @@ typecheck. - **`bench/`** — `seed-large-account.ts` (a synthetic ten-year account of about 1.26 million measurement rows) and `run.ts` (latency and SQL statements per request against it); see `docs/contributing/benchmarks.md`. Results land in `bench/results/`. - **`test-notifications.ts`** — exercise the notification dispatcher + reminder check. - **`fetch-geolite2.sh`** — download the MaxMind GeoLite2 MMDBs (needs a licence key) before `docker build`. +- **`build-pdf-fonts.py`** — rebuild the fonts the doctor-report PDF embeds (`src/lib/doctor-report-pdf/fonts/`) from the upstream Noto sources; needs `fonttools`. The source URLs are in its header. - **`install-hooks.sh`** — install the local git hooks. - **`generate-sw-version.mjs`**, **`print-bundle-report.mjs`** — service-worker version stamp and bundle-size report. - **`i18n/`** — locale tooling; **`__tests__/`** — tests for the scripts above. diff --git a/scripts/build-pdf-fonts.py b/scripts/build-pdf-fonts.py new file mode 100644 index 000000000..e6d2d5b2f --- /dev/null +++ b/scripts/build-pdf-fonts.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +"""Build the fonts the doctor-report PDF embeds. + +jsPDF draws one font per text run and has no glyph fallback, so every script +the report can carry has to live in one font file. No single upstream Noto +font covers what the report needs: Noto Sans has Latin, Greek and Cyrillic but +no arrows or comparison signs, Noto Sans KR has Hangul but no Latin +Extended-A (Polish). This script merges them: + + ReportSans-{Regular,Bold,Italic}.ttf + Noto Sans (Latin, Latin Extended-A/B, Greek, Cyrillic, punctuation, + super-/subscripts, currency) plus the arrows and mathematical operators + of Noto Sans Math. + ReportSansKR-{Regular,Bold}.ttf + The matching ReportSans weight plus Hangul (syllables, jamo, + compatibility jamo) and CJK punctuation from Noto Sans KR, instanced + at weight 400 / 700. Loaded only for a report that contains Hangul. + +All sources are SIL Open Font License 1.1; the licence texts sit beside the +output. The merged fonts carry their own family name, as the OFL asks of a +modified version. Layout tables (GSUB/GPOS/GDEF/MATH) are dropped: jsPDF +does no shaping, and precomposed Hangul syllables need none. + +Requires fonttools (`pip install fonttools`). Usage: + + python3 scripts/build-pdf-fonts.py + +where holds the unhinted upstream TTFs: + NotoSans-Regular.ttf, NotoSans-Bold.ttf, NotoSans-Italic.ttf + https://github.com/notofonts/notofonts.github.io/tree/main/fonts/NotoSans/unhinted/ttf + NotoSansMath-Regular.ttf + https://github.com/notofonts/notofonts.github.io/tree/main/fonts/NotoSansMath/unhinted/ttf + NotoSansKR[wght].ttf + https://github.com/google/fonts/tree/main/ofl/notosanskr +""" + +import copy +import sys +from pathlib import Path + +from fontTools import subset +from fontTools.ttLib import TTFont +from fontTools.varLib import instancer + + +def ranges(*spans): + out = set() + for lo, hi in spans: + out.update(range(lo, hi + 1)) + return out + + +BASE_CODEPOINTS = ranges( + (0x0020, 0x007E), # Basic Latin + (0x00A0, 0x024F), # Latin-1, Latin Extended-A/B + (0x0250, 0x02FF), # IPA, spacing modifiers + (0x0300, 0x036F), # combining diacritics + (0x0370, 0x03FF), # Greek + (0x0400, 0x052F), # Cyrillic + supplement + (0x1E00, 0x1EFF), # Latin Extended Additional + (0x2000, 0x206F), # general punctuation + (0x2070, 0x209F), # super-/subscripts + (0x20A0, 0x20CF), # currency + (0x2100, 0x214F), # letterlike (°C, №, ™) + (0x2150, 0x218F), # number forms +) +SYMBOL_CODEPOINTS = ranges( + (0x2190, 0x21FF), # arrows + (0x2200, 0x22FF), # mathematical operators (≈ ≤ ≥ ±) +) +HANGUL_CODEPOINTS = ranges( + (0x1100, 0x11FF), # Hangul jamo + (0x3000, 0x303F), # CJK symbols and punctuation + (0x3130, 0x318F), # compatibility jamo + (0xA960, 0xA97F), # jamo extended-A + (0xAC00, 0xD7A3), # syllables + (0xD7B0, 0xD7FF), # jamo extended-B +) +DROP_TABLES = ["GSUB", "GPOS", "GDEF", "MATH", "BASE", "JSTF", "DSIG", "STAT"] + + +def subset_font(font: TTFont, codepoints: set[int]) -> TTFont: + options = subset.Options() + options.layout_features = [] + options.drop_tables += DROP_TABLES + options.hinting = False + options.notdef_outline = True + options.name_IDs = ["*"] + options.glyph_names = True + subsetter = subset.Subsetter(options) + subsetter.populate(unicodes=codepoints & set(font.getBestCmap())) + subsetter.subset(font) + return font + + +def copy_glyph(base: TTFont, donor: TTFont, name: str, prefix: str) -> str: + """Copy one donor glyph (and its components) into base; return its name.""" + new_name = f"{prefix}{name}" + glyf = base["glyf"] + if new_name in glyf.glyphs: + return new_name + glyph = copy.deepcopy(donor["glyf"][name]) + if glyph.isComposite(): + for component in glyph.components: + component.glyphName = copy_glyph( + base, donor, component.glyphName, prefix + ) + glyf.glyphs[new_name] = glyph + glyf.glyphOrder.append(new_name) + base["hmtx"].metrics[new_name] = donor["hmtx"].metrics[name] + order = base.getGlyphOrder() + if new_name not in order: + order.append(new_name) + base.setGlyphOrder(order) + return new_name + + +def merge(base: TTFont, donor: TTFont, prefix: str) -> None: + if base["head"].unitsPerEm != donor["head"].unitsPerEm: + raise SystemExit("unitsPerEm differs between base and donor") + base_cmap = base.getBestCmap() + additions = {} + for cp, name in donor.getBestCmap().items(): + if cp in base_cmap: + continue + additions[cp] = copy_glyph(base, donor, name, prefix) + for table in base["cmap"].tables: + if table.isUnicode(): + if table.format == 4 and any(cp > 0xFFFF for cp in additions): + continue + table.cmap.update(additions) + base["maxp"].numGlyphs = len(base.getGlyphOrder()) + base["hhea"].numberOfHMetrics = len(base.getGlyphOrder()) + base["hhea"].advanceWidthMax = max( + base["hhea"].advanceWidthMax, + max(width for width, _ in donor["hmtx"].metrics.values()), + ) + + +def finish(font: TTFont, family: str, style: str, path: Path) -> None: + """Rename, drop glyph names, save. + + jsPDF copies the whole `post` table into every PDF it writes, subset or + not, so glyph names would cost each report tens of kilobytes (hundreds + with Hangul). Format 3 carries none. + """ + font["post"].formatType = 3.0 + rename(font, family, style) + font.save(path) + + +def rename(font: TTFont, family: str, style: str) -> None: + name = font["name"] + postscript = f"{family}-{style}" + for record in list(name.names): + if record.nameID in (1, 16): + record.string = family + elif record.nameID in (2, 17): + record.string = style + elif record.nameID == 3: + record.string = f"{postscript};HealthLog" + elif record.nameID == 4: + record.string = f"{family} {style}" + elif record.nameID == 6: + record.string = postscript + + +def build(src: Path, out: Path) -> None: + out.mkdir(parents=True, exist_ok=True) + math = subset_font(TTFont(src / "NotoSansMath-Regular.ttf"), SYMBOL_CODEPOINTS) + kr_source = src / "NotoSansKR[wght].ttf" + + for style in ("Regular", "Bold", "Italic"): + base = subset_font(TTFont(src / f"NotoSans-{style}.ttf"), BASE_CODEPOINTS) + merge(base, math, "math.") + finish(base, "ReportSans", style, out / f"ReportSans-{style}.ttf") + + if style == "Italic": + continue + weight = 400 if style == "Regular" else 700 + kr = subset_font(TTFont(kr_source), HANGUL_CODEPOINTS) + kr = instancer.instantiateVariableFont(kr, {"wght": weight}) + with_hangul = TTFont(out / f"ReportSans-{style}.ttf") + merge(with_hangul, kr, "kr.") + finish(with_hangul, "ReportSansKR", style, out / f"ReportSansKR-{style}.ttf") + + +if __name__ == "__main__": + if len(sys.argv) != 3: + raise SystemExit(__doc__) + build(Path(sys.argv[1]), Path(sys.argv[2])) diff --git a/src/__tests__/aging-fixture-dates-guard.test.ts b/src/__tests__/aging-fixture-dates-guard.test.ts index ba785e961..84a21a76c 100644 --- a/src/__tests__/aging-fixture-dates-guard.test.ts +++ b/src/__tests__/aging-fixture-dates-guard.test.ts @@ -83,6 +83,11 @@ const ALLOWLIST: Record = { reason: "the discovery matrix reads from a fixed since forward; the fixture days stay inside it as now moves on", }, + "tests/integration/dense-series-dst-hour.test.ts": { + max: 1, + reason: + "the read starts at a fixed fall-back night and runs forward to now; the readings are pinned to that night, so the case cannot age", + }, }; export interface AgingFinding { diff --git a/src/__tests__/baselines/source-file-lines.json b/src/__tests__/baselines/source-file-lines.json index 9c5349e11..7e93fa292 100644 --- a/src/__tests__/baselines/source-file-lines.json +++ b/src/__tests__/baselines/source-file-lines.json @@ -1,7 +1,7 @@ { "$comment": "Production files over 800 lines and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.", "count": 84, - "total": 94379, + "total": 94309, "entries": { "app/medications/page-client.tsx": 839, "components/charts/mood-chart.tsx": 1166, @@ -69,7 +69,7 @@ "lib/jobs/offhost-backup.ts": 1094, "lib/jobs/reaction-line.ts": 803, "lib/managed-profiles/handover.ts": 986, - "lib/mcp/record-search.ts": 1467, + "lib/mcp/record-search.ts": 1397, "lib/mcp/rich-reads.ts": 1467, "lib/measurements/dense-intraday-retention.ts": 1016, "lib/measurements/import-apple-health-export.ts": 1722, diff --git a/src/__tests__/baselines/source-function-lines.json b/src/__tests__/baselines/source-function-lines.json index 39d620275..e4bb6649d 100644 --- a/src/__tests__/baselines/source-function-lines.json +++ b/src/__tests__/baselines/source-function-lines.json @@ -1,7 +1,7 @@ { "$comment": "Production functions over 200 lines, keyed \"file :: name\", and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.", "count": 345, - "total": 111928, + "total": 111918, "entries": { "app/achievements/page.tsx :: AchievementsPage": 206, "app/api/admin/backups/upload/route.ts :: apiHandler(arg)": 275, @@ -93,7 +93,7 @@ "components/documents/document-card.tsx :: DocumentCard": 354, "components/documents/document-detail-sheet.tsx :: DocumentDetailSheet": 325, "components/documents/document-facts-review.tsx :: DocumentFactsSection": 242, - "components/documents/document-facts-review.tsx :: FactRow": 262, + "components/documents/document-facts-review.tsx :: FactRow": 261, "components/documents/document-filter-bar.tsx :: DocumentFilterBar": 348, "components/documents/document-record-links.tsx :: DocumentRecordLinks": 202, "components/documents/document-timeline.tsx :: DocumentTimeline": 314, @@ -139,7 +139,7 @@ "components/labs/lab-history-list.tsx :: LabHistoryList": 534, "components/labs/lab-list.tsx :: LabList": 308, "components/labs/ocr-review-dialog.tsx :: OcrReviewDialog": 359, - "components/labs/ocr-row-editor.tsx :: OcrRowEditor": 393, + "components/labs/ocr-row-editor.tsx :: OcrRowEditor": 386, "components/layout/auth-shell.tsx :: AuthShell": 518, "components/layout/bottom-nav.tsx :: BottomNav": 262, "components/layout/capture-picker.tsx :: CapturePicker": 235, @@ -205,7 +205,7 @@ "components/settings/import-panel/csv-import-card.tsx :: CsvImportCard": 212, "components/settings/import-panel/dose-history-import-card.tsx :: DoseHistoryImportCard": 225, "components/settings/import-panel/health-connect-import-card.tsx :: HealthConnectImportCard": 293, - "components/settings/import-panel/record-csv-import-card.tsx :: RecordCsvImportSheet": 460, + "components/settings/import-panel/record-csv-import-card.tsx :: RecordCsvImportSheet": 458, "components/settings/insights-pill-order-section.tsx :: InsightsPillOrderSection": 255, "components/settings/integrations/connections-panel.tsx :: ConnectionsPanel": 230, "components/settings/integrations/document-sources-card.tsx :: SourceForm": 306, diff --git a/src/__tests__/baselines/version-stamp-comments.json b/src/__tests__/baselines/version-stamp-comments.json index 8ad581d44..69c0ee030 100644 --- a/src/__tests__/baselines/version-stamp-comments.json +++ b/src/__tests__/baselines/version-stamp-comments.json @@ -1,7 +1,7 @@ { "$comment": "Comment lines that open with a release version, per file under src/. Maintained by src/__tests__/version-stamp-ratchet.test.ts.", - "count": 2895, - "total": 9226, + "count": 2894, + "total": 9223, "entries": { "__tests__/account-payload-consumer-guard.test.ts": 2, "__tests__/acting-account-boundary-guard.test.ts": 7, @@ -824,7 +824,7 @@ "components/documents/document-ai-transport.ts": 2, "components/documents/document-bulk-bar.tsx": 1, "components/documents/document-card.tsx": 2, - "components/documents/document-facts-review.tsx": 2, + "components/documents/document-facts-review.tsx": 1, "components/documents/document-summary-block.tsx": 2, "components/documents/use-content-index.ts": 1, "components/documents/use-document-assist.ts": 1, @@ -917,7 +917,7 @@ "components/insights/coach-panel/chat-bubble.tsx": 25, "components/insights/coach-panel/coach-conversation.tsx": 40, "components/insights/coach-panel/coach-drawer-body.tsx": 6, - "components/insights/coach-panel/coach-drawer.tsx": 14, + "components/insights/coach-panel/coach-drawer.tsx": 13, "components/insights/coach-panel/coach-hero.tsx": 2, "components/insights/coach-panel/coach-input.tsx": 12, "components/insights/coach-panel/coach-model-picker.tsx": 1, @@ -958,7 +958,6 @@ "components/insights/derived/coach-read-strip.tsx": 2, "components/insights/derived/composite-score-anatomy.tsx": 6, "components/insights/derived/coverage-meter.tsx": 1, - "components/insights/derived/index.ts": 1, "components/insights/derived/provenance-explainer.tsx": 2, "components/insights/derived/ring-hues.ts": 2, "components/insights/derived/score-anatomy-view.tsx": 3, diff --git a/src/app/api/labs/route.ts b/src/app/api/labs/route.ts index 65373f80c..32fb3924e 100644 --- a/src/app/api/labs/route.ts +++ b/src/app/api/labs/route.ts @@ -17,6 +17,7 @@ import { withIdempotency } from "@/lib/idempotency"; import { enqueueReminderSatisfy } from "@/lib/jobs/reminder-satisfy"; import { emitDataArrival } from "@/lib/arrivals/emit-shared"; import { resolveOrMintBiomarker } from "@/lib/labs/biomarker-store"; +import { isDimensionlessUnit } from "@/lib/labs/dimensionless"; import { readingInMarkerUnit } from "@/lib/labs/reading-conversion"; import { type ResolvedBiomarker, @@ -270,7 +271,7 @@ async function postLabResult(request: NextRequest) { meta: { biomarkerId: biomarker.id, reason: reading.reason }, }); return apiError( - `The reading is in ${unit}, but ${biomarker.name} is tracked in ${biomarker.unit}.`, + unitMismatchMessage(unit, biomarker.name, biomarker.unit), 422, { errorCode: "labs.unit.mismatch", @@ -392,3 +393,19 @@ async function postLabResult(request: NextRequest) { return apiSuccess(dto, 201); } + +/** The refusal for a reading whose unit differs from its marker's. */ +function unitMismatchMessage( + readingUnit: string | undefined, + markerName: string, + markerUnit: string, +): string { + const readingSide = + !readingUnit || isDimensionlessUnit(readingUnit) + ? "The reading has no unit" + : `The reading is in ${readingUnit}`; + const markerSide = isDimensionlessUnit(markerUnit) + ? "tracked without a unit" + : `tracked in ${markerUnit}`; + return `${readingSide}, but ${markerName} is ${markerSide}.`; +} diff --git a/src/app/api/measurements/series/__tests__/route.test.ts b/src/app/api/measurements/series/__tests__/route.test.ts index 0742d921b..ea63202db 100644 --- a/src/app/api/measurements/series/__tests__/route.test.ts +++ b/src/app/api/measurements/series/__tests__/route.test.ts @@ -131,7 +131,7 @@ function req(query: string): NextRequest { * `tests/integration/series-source-ladder.test.ts`. */ function adaptSeriesSql(sql: string): Promise { - if (/GROUP BY local_day|STDDEV_POP/.test(sql)) { + if (/GROUP BY (?:local_day|bucket_start)|STDDEV_POP/.test(sql)) { return (prisma.$queryRaw as unknown as () => Promise)(); } const type = /'([A-Z0-9_]+)'::"measurement_type"/.exec(sql)?.[1]; @@ -914,7 +914,7 @@ describe("GET /api/measurements/series — dense-kind day-bucketing (v1.28.25)", const bucketCall = vi .mocked(prisma.$queryRawUnsafe) .mock.calls.find(([sql]) => - /GROUP BY local_day/.test(sql as string), + /GROUP BY (?:local_day|bucket_start)/.test(sql as string), ) as unknown[]; expect(bucketCall.slice(1)).toContain("hour"); }); @@ -981,7 +981,7 @@ describe("GET /api/measurements/series — dense-kind day-bucketing (v1.28.25)", const bucketCall = vi .mocked(prisma.$queryRawUnsafe) .mock.calls.find(([sql]) => - /GROUP BY local_day/.test(sql as string), + /GROUP BY (?:local_day|bucket_start)/.test(sql as string), ) as unknown[]; expect(bucketCall.slice(1)).toContain("hour"); }); diff --git a/src/app/mcp/__tests__/route.test.ts b/src/app/mcp/__tests__/route.test.ts index 9a5589b20..d5c956613 100644 --- a/src/app/mcp/__tests__/route.test.ts +++ b/src/app/mcp/__tests__/route.test.ts @@ -52,6 +52,12 @@ vi.mock("@/lib/ai/coach/tools/executor", () => ({ executeCoachTool })); vi.mock("@/lib/ai/coach/tools/inventory", () => ({ buildCoachDataInventory: vi.fn(), })); +// `get_labs` builds its labs block first and asks the Coach only on a miss; +// a miss keeps the health-reader case on the executor it asserts. +vi.mock("@/lib/ai/coach/labs-snapshot", async (importOriginal) => ({ + ...(await importOriginal()), + buildLabsSnapshotBlock: vi.fn(async () => null), +})); vi.mock("@/lib/mcp/server", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/components/clinician/history-sections.tsx b/src/components/clinician/history-sections.tsx index 308f74ea4..dd6a25138 100644 --- a/src/components/clinician/history-sections.tsx +++ b/src/components/clinician/history-sections.tsx @@ -26,6 +26,7 @@ import { type LeafScope, type Translate, } from "./report-sections"; +import { withLabUnit } from "@/lib/labs/dimensionless"; /** Join the parts of a composed value, dropping the ones with nothing in. */ function compose(parts: Array): string { @@ -73,7 +74,7 @@ export function LabResultsSection({ const qualitative = lab.value === null; const reading = qualitative ? lab.valueText - : `${fmtLab(lab.value as number, lab.sourceValue)} ${lab.unit}`.trim(); + : withLabUnit(fmtLab(lab.value as number, lab.sourceValue), lab.unit); const range = ( low: number | null, high: number | null, diff --git a/src/components/documents/__tests__/document-facts-review.test.tsx b/src/components/documents/__tests__/document-facts-review.test.tsx index fbb28cccb..23cc24dd8 100644 --- a/src/components/documents/__tests__/document-facts-review.test.tsx +++ b/src/components/documents/__tests__/document-facts-review.test.tsx @@ -8,7 +8,7 @@ import type { InboundDocumentDetailDto, } from "@/lib/validations/inbound-documents"; -import { DocumentFactsSection } from "../document-facts-review"; +import { DocumentFactsSection, FactRow } from "../document-facts-review"; /** * The staged-facts block's honest states, pinned by static render: @@ -173,3 +173,56 @@ describe("", () => { expect(html).toBe(""); }); }); + +describe("", () => { + // A confident lab value the last save refused (here a ratio printed without + // a unit) gets the same edit control as a low-confidence one: it is the only + // way to add the unit and finish the review. + const unitless = fact({ + data: { + label: "Ratio", + code: null, + codeSystem: null, + value: 4.2, + valueText: null, + unit: null, + referenceLow: null, + referenceHigh: 5, + referenceText: "<5.0", + effectiveDate: "2026-08-01", + }, + provenance: { + sourceText: "Ratio 4.2 <5.0", + anchored: true, + sourceOffset: 10, + page: 0, + confidence: 0.95, + }, + }); + + const rowProps = { + documentId: "doc-1", + checked: true, + onCheckedChange: () => {}, + chosenBiomarkerId: null, + onChooseBiomarker: () => {}, + markerName: () => null, + }; + + it("offers the edit control on a confident row whose save was refused", () => { + const html = render( + , + ); + expect(html).toContain('data-slot="document-fact-verify-open"'); + expect(html).toContain("A numeric value needs a unit"); + }); + + it("leaves a confident row without a refusal free of the edit control", () => { + const html = render(); + expect(html).not.toContain('data-slot="document-fact-verify-open"'); + }); +}); diff --git a/src/components/documents/document-facts-review.tsx b/src/components/documents/document-facts-review.tsx index ded9d2d6a..00745a89c 100644 --- a/src/components/documents/document-facts-review.tsx +++ b/src/components/documents/document-facts-review.tsx @@ -37,10 +37,12 @@ import { Checkbox } from "@/components/ui/checkbox"; import { DateField } from "@/components/ui/date-field"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { LabUnitInput } from "@/components/labs/lab-unit-input"; import { MarkerMatchField } from "@/components/labs/marker-match-field"; import type { BiomarkerListResponse } from "@/components/labs/types"; import { apiGet } from "@/lib/api/api-fetch"; import type { DocumentExtractRunResult } from "@/lib/documents/ai-runs/types"; +import { withLabUnit } from "@/lib/labs/dimensionless"; import { useTranslations } from "@/lib/i18n/context"; import { queryKeys } from "@/lib/query-keys"; import { cn } from "@/lib/utils"; @@ -81,7 +83,7 @@ function factHeadline(fact: ExtractedFactDto): string { const data = fact.data as ObservationFactData; const value = typeof data.value === "number" - ? `${data.value}${data.unit ? ` ${data.unit}` : ""}` + ? withLabUnit(String(data.value), data.unit) : (data.valueText ?? ""); return value ? `${data.label}: ${value}` : data.label; } @@ -204,8 +206,8 @@ function draftFor(fact: ExtractedFactDto): VerifyDraft { }; } -/** One pending fact: include-toggle, stated values, verify-first when low-confidence. */ -function FactRow({ +/** One pending fact: include-toggle, stated values, and the edit control when it is low-confidence or its last save was refused. */ +export function FactRow({ documentId, fact, checked, @@ -221,7 +223,7 @@ function FactRow({ onCheckedChange: (checked: boolean) => void; /** A per-fact commit refusal from the last confirm attempt, or null. */ failure: string | null; - /** v1.43 — the suggestion the person picked for a lab value, or null. */ + /** The suggestion the person picked for a lab value, or null. */ chosenBiomarkerId: string | null; onChooseBiomarker: (biomarkerId: string | null) => void; /** The account's marker name by id, for the matched marker. */ @@ -250,8 +252,7 @@ function FactRow({ { onSuccess: () => { setVerifying(false); - // The refetched fact arrives with needsReview cleared; include it — - // the person just asserted these values. + // Include it: the refetched fact clears needsReview, as asserted. onCheckedChange(true); }, }, @@ -319,9 +320,10 @@ function FactRow({

) : null} - {fact.needsReview && !verifying ? ( + {(fact.needsReview || failure !== null) && !verifying ? (